Pith - fireworks_wine_drag_fix
/* fireworks cs6 wine drag fix */
/* vgmlr and opus 5.5 */

#include <windows.h>

typedef HWND (WINAPI *SetCapture_t)(HWND);
typedef BOOL (WINAPI *ReleaseCapture_t)(void);

static SetCapture_t real_SetCapture;
static ReleaseCapture_t real_ReleaseCapture;

static BOOL debug;
static volatile DWORD att_from, att_to;
static volatile LONG attaches;

static void dbg(const char *fmt, ...)
{
    char buf[512];
    va_list ap;

    if (!debug) return;
    va_start(ap, fmt);
    wvsprintfA(buf, fmt, ap);
    va_end(ap);
    OutputDebugStringA(buf);
}

static DWORD own_thread(HWND h)
{
    DWORD pid = 0, tid;

    if (!h) return 0;
    tid = GetWindowThreadProcessId(h, &pid);
    return pid == GetCurrentProcessId() ? tid : 0;
}

static DWORD input_thread(void)
{
    POINT pt;
    DWORD tid = own_thread(GetForegroundWindow());

    if (!tid && GetCursorPos(&pt))
        tid = own_thread(WindowFromPoint(pt));
    return tid;
}

static HWND WINAPI hook_SetCapture(HWND hwnd)
{
    DWORD me = GetCurrentThreadId();
    DWORD it = hwnd ? input_thread() : 0;

    if (it && it != me && !att_from && AttachThreadInput(me, it, TRUE)) {
        att_from = me;
        att_to = it;
        if (InterlockedIncrement(&attaches) <= 5)
            dbg("fwshim: attach %lx -> %lx for %08lx", me, it, (ULONG_PTR)hwnd);
    }
    return real_SetCapture(hwnd);
}

static BOOL WINAPI hook_ReleaseCapture(void)
{
    BOOL r = real_ReleaseCapture();

    if (att_from == GetCurrentThreadId()) {
        AttachThreadInput(att_from, att_to, FALSE);
        att_from = att_to = 0;
    }
    return r;
}

/* IAT patch */
static int patch_module(HMODULE mod)
{
    BYTE *base = (BYTE *)mod;
    IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)base;
    IMAGE_NT_HEADERS *nt;
    IMAGE_DATA_DIRECTORY *dir;
    IMAGE_IMPORT_DESCRIPTOR *imp;
    int n = 0;

    if (dos->e_magic != IMAGE_DOS_SIGNATURE) return 0;
    nt = (IMAGE_NT_HEADERS *)(base + dos->e_lfanew);
    if (nt->Signature != IMAGE_NT_SIGNATURE) return 0;
    dir = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    if (!dir->VirtualAddress) return 0;

    for (imp = (IMAGE_IMPORT_DESCRIPTOR *)(base + dir->VirtualAddress); imp->Name; imp++) {
        IMAGE_THUNK_DATA *t = (IMAGE_THUNK_DATA *)(base + imp->FirstThunk);
        for (; t->u1.Function; t++) {
            void *hook;
            DWORD old;

            if ((void *)t->u1.Function == (void *)real_SetCapture)
                hook = (void *)hook_SetCapture;
            else if ((void *)t->u1.Function == (void *)real_ReleaseCapture)
                hook = (void *)hook_ReleaseCapture;
            else
                continue;
            if (!VirtualProtect(&t->u1.Function, sizeof(void *), PAGE_READWRITE, &old)) continue;
            t->u1.Function = (ULONG_PTR)hook;
            VirtualProtect(&t->u1.Function, sizeof(void *), old, &old);
            n++;
        }
    }
    return n;
}

BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved)
{
    HMODULE u32;
    int n;

    if (reason != DLL_PROCESS_ATTACH) return TRUE;

    DisableThreadLibraryCalls(inst);
    debug = GetEnvironmentVariableA("FWSHIM_DEBUG", NULL, 0) > 0;

    u32 = GetModuleHandleW(L"user32.dll");
    real_SetCapture = (SetCapture_t)GetProcAddress(u32, "SetCapture");
    real_ReleaseCapture = (ReleaseCapture_t)GetProcAddress(u32, "ReleaseCapture");
    if (!real_SetCapture || !real_ReleaseCapture) {
        dbg("fwshim: user32 exports missing");
        return TRUE;
    }

    n = patch_module(GetModuleHandleW(NULL));
    dbg("fwshim: loaded, patched %d imports in Fireworks.exe", n);
    return TRUE;
}