/* 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;
}