From fbbf52af0469e270714fdb0c83cb6af7b2c036ba Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 22 Jul 2026 13:31:19 -0700 Subject: [PATCH] better handling of already-initialized COM --- src/backend/gdi.c | 180 +++++++++++++++++++++++++++------------------- 1 file changed, 105 insertions(+), 75 deletions(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index a005a74..4ab2d9e 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -12,27 +12,26 @@ typedef struct userdata { static struct symtbl { void* lib_dwmapi; - void *shell32lib; - void *ole32lib; - void *urlmonlib; + void* shell32lib; + void* ole32lib; + void* urlmonlib; MwBool has_drag_and_drop; HRESULT(WINAPI* DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); - UINT (WINAPI *DragQueryFileW)(HDROP hDrop,UINT iFile,LPWSTR lpszFile,UINT cch); - UINT (WINAPI *DragQueryFileA)(HDROP hDrop,UINT iFile,LPSTR lpszFile,UINT cch); - void (WINAPI *ReleaseStgMedium)(LPSTGMEDIUM unnamedParam1); - HRESULT (WINAPI *OleInitialize)(LPVOID pvReserved); - HRESULT (WINAPI *RegisterDragDrop)(HWND hwnd, LPDROPTARGET pDropTarget); - HRESULT (WINAPI *FindMimeFromData)( - LPBC pBC, - LPCWSTR pwzUrl, - LPVOID pBuffer, - DWORD cbSize, - LPCWSTR pwzMimeProposed, - DWORD dwMimeFlags, - LPWSTR *ppwzMimeOut, - _Reserved_ DWORD dwReserved - ); + UINT(WINAPI* DragQueryFileW)(HDROP hDrop, UINT iFile, LPWSTR lpszFile, UINT cch); + UINT(WINAPI* DragQueryFileA)(HDROP hDrop, UINT iFile, LPSTR lpszFile, UINT cch); + void(WINAPI* ReleaseStgMedium)(LPSTGMEDIUM unnamedParam1); + HRESULT(WINAPI* OleInitialize)(LPVOID pvReserved); + HRESULT(WINAPI* RegisterDragDrop)(HWND hwnd, LPDROPTARGET pDropTarget); + HRESULT(WINAPI* FindMimeFromData)( + LPBC pBC, + LPCWSTR pwzUrl, + LPVOID pBuffer, + DWORD cbSize, + LPCWSTR pwzMimeProposed, + DWORD dwMimeFlags, + LPWSTR* ppwzMimeOut, + _Reserved_ DWORD dwReserved); } wsymtbl; static int is_plgblt_reliable = 0; @@ -441,7 +440,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { SetWindowPos(r->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - r->gdi.dropTarget = NULL; + r->gdi.dropTarget = NULL; r->gdi.drag_update = MwFALSE; return r; @@ -1049,15 +1048,15 @@ static HRESULT STDMETHODCALLTYPE GDIDT_DragEnter(IDropTarget* this_, IDataObject static HRESULT STDMETHODCALLTYPE GDIDT_DragOver(IDropTarget* this_, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { - MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; + MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; self->handle->gdi.drag_update = MwTRUE; return S_OK; } static HRESULT STDMETHODCALLTYPE GDIDT_DragLeave(IDropTarget* this_) { - MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; - self->handle->gdi.drag_update = MwFALSE; + MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; + self->handle->gdi.drag_update = MwFALSE; return S_OK; } @@ -1070,42 +1069,42 @@ static HRESULT STDMETHODCALLTYPE GDIDT_Drop(IDropTarget* this_, IDataObject* pDa self->handle->gdi.drag_update = MwTRUE; if(pDataObj->lpVtbl->GetData(pDataObj, &fmt, &stg) == S_OK) { - HDROP hDrop = (HDROP)stg.hGlobal; - UINT count = wsymtbl.DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); - UINT i, n; + HDROP hDrop = (HDROP)stg.hGlobal; + UINT count = wsymtbl.DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); + UINT i, n; HRESULT hr; for(i = 0; i < count; i++) { - wchar_t path[MAX_PATH]; - char path_normal[MAX_PATH]; - char *mime_type_normal; - wchar_t *mime_type = NULL; - int mime_type_size; - HRESULT hr; - int i; + wchar_t path[MAX_PATH]; + char path_normal[MAX_PATH]; + char* mime_type_normal; + wchar_t* mime_type = NULL; + int mime_type_size; + HRESULT hr; + int i; wsymtbl.DragQueryFileW(hDrop, i, path, MAX_PATH); wsymtbl.DragQueryFileA(hDrop, i, path_normal, MAX_PATH); - hr = wsymtbl.FindMimeFromData( NULL, path, NULL, 0, - NULL, FMFD_DEFAULT , &mime_type, 0x0 ); + hr = wsymtbl.FindMimeFromData(NULL, path, NULL, 0, + NULL, FMFD_DEFAULT, &mime_type, 0x0); - mime_type_size = WideCharToMultiByte(CP_ACP, 0, mime_type, -1, NULL, 0, NULL, FALSE); + mime_type_size = WideCharToMultiByte(CP_ACP, 0, mime_type, -1, NULL, 0, NULL, FALSE); mime_type_normal = malloc(sizeof(mime_type_size)); WideCharToMultiByte(CP_ACP, 0, mime_type, -1, mime_type_normal, mime_type_size, NULL, FALSE); if(mime_type_size == 0) { - printf("Error converting mime type to multi-byte: %ld\n",GetLastError()); + printf("Error converting mime type to multi-byte: %ld\n", GetLastError()); } else { - if(self->handle->common.known_mime_types) { - for(n = 0; n < arrlen(self->handle->common.known_mime_types); n++) { - if(strcmp(mime_type_normal, self->handle->common.known_mime_types[n]) == 0) { - MwDispatchUserHandler(self->handle->common.user, MwNdragAndDropHandler, path_normal); - break; - } - } - } else { - MwDispatchUserHandler(self->handle->common.user, MwNdragAndDropHandler, path_normal); - } + if(self->handle->common.known_mime_types) { + for(n = 0; n < arrlen(self->handle->common.known_mime_types); n++) { + if(strcmp(mime_type_normal, self->handle->common.known_mime_types[n]) == 0) { + MwDispatchUserHandler(self->handle->common.user, MwNdragAndDropHandler, path_normal); + break; + } + } + } else { + MwDispatchUserHandler(self->handle->common.user, MwNdragAndDropHandler, path_normal); + } } free(mime_type); } @@ -1118,7 +1117,6 @@ static HRESULT STDMETHODCALLTYPE GDIDT_Drop(IDropTarget* this_, IDataObject* pDa return S_OK; } - static IDropTargetVtbl DropTarget_Vtbl = { GDIDT_QueryInterface, GDIDT_AddRef, @@ -1129,7 +1127,7 @@ static IDropTargetVtbl DropTarget_Vtbl = { GDIDT_Drop}; static void MwLLSetupDragAndDropImpl(MwLL handle) { - HRESULT hr = 0; + HRESULT hr = 0; handle->gdi.dropTarget = (MwLLGDIDropTarget*)malloc(sizeof(MwLLGDIDropTarget)); handle->gdi.dropTarget->lpVtbl = &DropTarget_Vtbl; @@ -1146,22 +1144,9 @@ static void MwLLSetupDragAndDropImpl(MwLL handle) { } static int MwLLGDICallInitImpl(void) { - void* ntdll; + void* ntdll; HRESULT hr; - CoInitialize(NULL); - hr = OleInitialize(NULL); - if(!SUCCEEDED(hr)) { - if(hr == RPC_E_CHANGED_MODE) { - CoUninitialize(); - hr = OleInitialize(NULL); - CoInitialize(NULL); - } else { - printf("OleInitialize failed; %08lx\n", hr); - return 1; - } - } - memset(&wsymtbl, 0, sizeof(wsymtbl)); wsymtbl.lib_dwmapi = MwDynamicOpen("dwmapi.dll"); @@ -1174,24 +1159,69 @@ static int MwLLGDICallInitImpl(void) { is_plgblt_reliable = 1; } - wsymtbl.has_drag_and_drop = MwTRUE; + wsymtbl.has_drag_and_drop = MwFALSE; - if(!(wsymtbl.shell32lib = LoadLibrary("shell32.dll"))) {goto dnd_error;}; - if(!(wsymtbl.ole32lib = LoadLibrary("ole32.dll"))) {goto dnd_error;}; - if(!(wsymtbl.urlmonlib = LoadLibrary("Urlmon.dll"))) {goto dnd_error;}; + /* Drag and Drop initialization */ + { + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + /* The only other error - COM already being initialized - can be ignored */ + if(hr == RPC_E_CHANGED_MODE) { + goto no_dnd; + } + if(!SUCCEEDED(hr) && hr != S_FALSE) { + printf("CoInitialize error: %08lx\n", hr); + goto dnd_error; + } + hr = OleInitialize(NULL); + if(!SUCCEEDED(hr)) { + if(hr == RPC_E_CHANGED_MODE) { + no_dnd: + printf("Cannot do drag and drop; Microsoft hates you and if you use COM anywhere else it has to be apartment threaded.\n"); + goto dnd_error; + } else { + printf("OleInitialize failed; %08lx. Drag and Drop won't be supported.\n", hr); + goto dnd_error; + } + } -#define SHELL32_FUNC(x) if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.shell32lib, #x))) {printf(#x "not found, drag and drop will not be supported"); goto dnd_error;} -#define OLE32_FUNC(x) if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.ole32lib, #x))) {printf(#x "not found, drag and drop will not be supported"); goto dnd_error;} -#define URLMON_FUNC(x) if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.urlmonlib, #x))) {printf(#x "not found, drag and drop will not be supported"); goto dnd_error;} + wsymtbl.has_drag_and_drop = MwTRUE; - SHELL32_FUNC(DragQueryFileW); - SHELL32_FUNC(DragQueryFileA); - OLE32_FUNC(ReleaseStgMedium); - OLE32_FUNC(RegisterDragDrop); - URLMON_FUNC(FindMimeFromData); + if(!(wsymtbl.shell32lib = LoadLibrary("shell32.dll"))) { + goto dnd_error; + }; + if(!(wsymtbl.ole32lib = LoadLibrary("ole32.dll"))) { + goto dnd_error; + }; + if(!(wsymtbl.urlmonlib = LoadLibrary("Urlmon.dll"))) { + goto dnd_error; + }; - wsymtbl.has_drag_and_drop = MwTRUE; +#define SHELL32_FUNC(x) \ + if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.shell32lib, #x))) { \ + printf(#x "not found, drag and drop will not be supported"); \ + goto dnd_error; \ + } +#define OLE32_FUNC(x) \ + if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.ole32lib, #x))) { \ + printf(#x "not found, drag and drop will not be supported"); \ + goto dnd_error; \ + } +#define URLMON_FUNC(x) \ + if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.urlmonlib, #x))) { \ + printf(#x "not found, drag and drop will not be supported"); \ + goto dnd_error; \ + } + + SHELL32_FUNC(DragQueryFileW); + SHELL32_FUNC(DragQueryFileA); + OLE32_FUNC(ReleaseStgMedium); + OLE32_FUNC(RegisterDragDrop); + URLMON_FUNC(FindMimeFromData); + + wsymtbl.has_drag_and_drop = MwTRUE; + } dnd_error: + /* TODO: check properly */ return 0; }