[Bug 59652] New: ole32: DoDragDrop does not fall back to WM_DROPFILES for legacy applications
http://bugs.winehq.org/show_bug.cgi?id=59652 Bug ID: 59652 Summary: ole32: DoDragDrop does not fall back to WM_DROPFILES for legacy applications Product: Wine Version: 11.6 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: ole32 Assignee: wine-bugs@list.winehq.org Reporter: lldmakhbfcrmqyluns@nesopf.com Distribution: --- In Microsoft Windows, when an OLE Drag & Drop source application (using DoDragDrop) drops data onto a target application that does not implement IDropTarget but has the WS_EX_ACCEPTFILES style, the ole32.dll library automatically acts as a bridge. It extracts CF_HDROP data, allocates memory in the target process, and posts a WM_DROPFILES message. Currently, Wine's ole32.dll does not implement this fallback mechanism. If IDropTarget is not found on the target window, Wine simply returns DROPEFFECT_NONE and aborts the operation, even if a drop was requested (DRAGDROP_S_DROP). This breaks drag-and-drop functionality for many legacy applications that rely on WM_DROPFILES. Steps to Reproduce: Run an OLE-aware application that can act as a drag source (e.g., Total Commander, modern file explorers). Run a legacy application that accepts files via WM_DROPFILES but does not implement OLE IDropTarget (e.g., Notepad++, etc.). Drag a file from the source application to the target application. Actual Results: The drop fails. DoDragDrop returns DROPEFFECT_NONE. Expected Results: The file should be successfully dropped and opened by the target application, as it happens on Windows. Patch: The following patch implements the WM_DROPFILES fallback bridge in dlls/ole32/ole2.c. It correctly identifies legacy targets, marshals the CF_HDROP data into the target process, and posts the WM_DROPFILES message. This fixes the issue in both XWayland and native Wayland backend. diff --- a/dlls/ole32/ole2.c +++ b/dlls/ole32/ole2.c @@ -2246,6 +2246,90 @@ return target; } +/* WM_DROPFILES bridge for legacy apps without IDropTarget */ +typedef struct { + DWORD pFiles; + POINT pt; + BOOL fNC; + BOOL fWide; +} WINE_DROPFILES; + +static HWND find_drop_target(POINT pt) +{ + HWND walk = GetTopWindow(GetDesktopWindow()); + DWORD our_pid = GetCurrentProcessId(); + + while (walk) { + if (IsWindowVisible(walk)) { + RECT rc; + DWORD wpid = 0; + GetWindowThreadProcessId(walk, &wpid); + if (wpid && wpid != our_pid) { + GetWindowRect(walk, &rc); + if (PtInRect(&rc, pt)) { + HWND target = walk; + while (target) { + if (GetWindowLongW(target, GWL_EXSTYLE) & WS_EX_ACCEPTFILES) + return target; + target = GetParent(target); + } + return walk; + } + } + } + walk = GetWindow(walk, GW_HWNDNEXT); + } + return NULL; +} + +static BOOL bridge_wm_dropfiles(IDataObject *dataObject, HWND target, POINT pt) +{ + FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stg; + WINE_DROPFILES *df; + DWORD target_pid; + HANDLE hProc; + SIZE_T size; + void *remote; + + if (FAILED(IDataObject_GetData(dataObject, &fmt, &stg))) + return FALSE; + if (stg.tymed != TYMED_HGLOBAL || !stg.hGlobal) { + ReleaseStgMedium(&stg); + return FALSE; + } + + df = GlobalLock(stg.hGlobal); + if (!df) { + ReleaseStgMedium(&stg); + return FALSE; + } + size = GlobalSize(stg.hGlobal); + df->pt = pt; + df->fNC = FALSE; + + GetWindowThreadProcessId(target, &target_pid); + hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, target_pid); + if (!hProc) { + GlobalUnlock(stg.hGlobal); + ReleaseStgMedium(&stg); + return FALSE; + } + + remote = VirtualAllocEx(hProc, NULL, size, MEM_COMMIT, PAGE_READWRITE); + if (remote) { + WriteProcessMemory(hProc, remote, df, size, NULL); + PostMessageW(target, WM_DROPFILES, (WPARAM)remote, 0); + } + + CloseHandle(hProc); + GlobalUnlock(stg.hGlobal); + ReleaseStgMedium(&stg); + return remote != NULL; +} + static void drag_end( TrackerWindowInfo *info ) { HRESULT hr; @@ -2279,6 +2363,17 @@ else *info->pdwEffect = DROPEFFECT_NONE; + /* Bridge OLE drop to WM_DROPFILES for legacy apps */ + if (*info->pdwEffect == DROPEFFECT_NONE && info->returnValue == DRAGDROP_S_DROP) + { + POINT pt; + HWND target; + pt.x = info->curMousePos.x; + pt.y = info->curMousePos.y; + target = find_drop_target(pt); + if (target && bridge_wm_dropfiles(info->dataObject, target, pt)) + *info->pdwEffect = DROPEFFECT_COPY; + } } static HRESULT give_feedback( TrackerWindowInfo *info ) -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59652 --- Comment #1 from T_Im <lldmakhbfcrmqyluns@nesopf.com> --- FYI: I'm not a C dev and don't plan to submit a formal patch. I'm just sharing analysis to help fix the bug for everyone. Feel free to use or rewrite the code. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59652 T_Im <lldmakhbfcrmqyluns@nesopf.com> changed: What |Removed |Added ---------------------------------------------------------------------------- Blocks| |59653 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59652 T_Im <lldmakhbfcrmqyluns@nesopf.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |huw@codeweavers.com -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
participants (1)
-
WineHQ Bugzilla