From 720e0c05747b80f416e358cf0de073c8dc665bc1 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Wed, 29 Nov 2017 00:24:28 +0100 Subject: [PATCH] + workaround: drag n' drop from 32-bit process on Notepad3 x64 window --- src/Helpers.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Helpers.h | 19 +++ src/Notepad3.c | 76 +++++++++-- src/Notepad3.rc | Bin 183202 -> 183504 bytes src/resource.h | 1 + 5 files changed, 428 insertions(+), 10 deletions(-) diff --git a/src/Helpers.c b/src/Helpers.c index 925a3fc74..82145b624 100644 --- a/src/Helpers.c +++ b/src/Helpers.c @@ -3580,5 +3580,347 @@ INT UTF8_mbslen(LPCSTR source,INT byte_length) return wchar_length; } +/////////////////////////////////////////////////////////////////////////////// +// +// Drag N Drop helpers +// +/////////////////////////////////////////////////////////////////////////////// + +static HANDLE g_hHeap = NULL; + +#define NP3DD_HEAP (g_hHeap == NULL ? (g_hHeap = GetProcessHeap()) : g_hHeap) + +typedef struct tIDROPTARGET { + IDropTarget idt; + LONG lRefCount; + ULONG lNumFormats; + CLIPFORMAT *pFormat; + HWND hWnd; + BOOL bAllowDrop; + DWORD dwKeyState; + IDataObject *pDataObject; + UINT nMsg; + void *pUserData; + NP3DDCALLBACK pDropProc; +} +NP3IDROPTARGET, *PNP3IDROPTARGET; + + +typedef struct IDRPTRG_VTBL +{ + BEGIN_INTERFACE + HRESULT(STDMETHODCALLTYPE *QueryInterface)(PNP3IDROPTARGET pThis, REFIID riid, void **ppvObject); + ULONG(STDMETHODCALLTYPE *AddRef)(PNP3IDROPTARGET pThis); + ULONG(STDMETHODCALLTYPE *Release)(PNP3IDROPTARGET pThis); + HRESULT(STDMETHODCALLTYPE *DragEnter)(PNP3IDROPTARGET pThis, IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); + HRESULT(STDMETHODCALLTYPE *DragOver)(PNP3IDROPTARGET pThis, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); + HRESULT(STDMETHODCALLTYPE *DragLeave)(PNP3IDROPTARGET pThis); + HRESULT(STDMETHODCALLTYPE *Drop)(PNP3IDROPTARGET pThis, IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); + END_INTERFACE +} +IDRPTRG_VTBL, *PIDRPTRG_VTBL; + + +//============================================================================= +// +// NP3DragnDropInit() +// +void Np3DragnDropInit(HANDLE hHeap) +{ + if (g_hHeap == NULL && hHeap == NULL) + g_hHeap = GetProcessHeap(); + else if (g_hHeap == NULL) + g_hHeap = hHeap; + + OleInitialize(NULL); // just in case + return; +} + + +//============================================================================= +// +// IDRPTRG_AddRef() +// +static ULONG STDMETHODCALLTYPE IDRPTRG_AddRef(PNP3IDROPTARGET pThis) +{ + return InterlockedIncrement(&pThis->lRefCount); +} + + +//============================================================================= +// +// IDRPTRG_QueryDataObject() +// +static BOOL IDRPTRG_QueryDataObject(PNP3IDROPTARGET pDropTarget, IDataObject *pDataObject) +{ + ULONG lFmt; + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + + for (lFmt = 0; lFmt < pDropTarget->lNumFormats; lFmt++) + { + fmtetc.cfFormat = pDropTarget->pFormat[lFmt]; + if (pDataObject->lpVtbl->QueryGetData(pDataObject, &fmtetc) == S_OK) + return TRUE; + } + + return FALSE; +} + + +//============================================================================= +// +// IDRPTRG_QueryInterface() +// +static HRESULT STDMETHODCALLTYPE IDRPTRG_QueryInterface(PNP3IDROPTARGET pThis, REFIID riid, + LPVOID *ppvObject) +{ + *ppvObject = NULL; + + if (IsEqualGUID(riid, &IID_IUnknown)) + { + IDRPTRG_AddRef(pThis); + *ppvObject = pThis; + return S_OK; + } + else if (IsEqualGUID(riid, &IID_IDropTarget)) + { + IDRPTRG_AddRef(pThis); + *ppvObject = pThis; + return S_OK; + } + + return E_NOINTERFACE; +} + + +//============================================================================= +// +// IDRPTRG_Release() +// +static ULONG STDMETHODCALLTYPE IDRPTRG_Release(PNP3IDROPTARGET pThis) +{ + ULONG nCount; + + if ((nCount = InterlockedDecrement(&pThis->lRefCount)) == 0) + { + HeapFree(NP3DD_HEAP, 0, pThis); + return 0; + } + + return nCount; +} + + + +//============================================================================= +// +// IDRPTRG_DropEffect() +// +static DWORD IDRPTRG_DropEffect(DWORD dwKeyState, POINTL pt, DWORD dwAllowed) +{ + DWORD dwEffect = 0; + + if (dwKeyState & MK_CONTROL) + dwEffect = dwAllowed & DROPEFFECT_COPY; + else if (dwKeyState & MK_SHIFT) + dwEffect = dwAllowed & DROPEFFECT_MOVE; + + if (dwEffect == 0) + { + if (dwAllowed & DROPEFFECT_COPY) + dwEffect = DROPEFFECT_COPY; + if (dwAllowed & DROPEFFECT_MOVE) + dwEffect = DROPEFFECT_MOVE; + } + + UNUSED(pt); + return dwEffect; +} + + +//============================================================================= +// +// IDRPTRG_DragEnter() +// +static HRESULT STDMETHODCALLTYPE IDRPTRG_DragEnter(PNP3IDROPTARGET pThis, IDataObject *pDataObject, + DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) +{ + pThis->bAllowDrop = IDRPTRG_QueryDataObject(pThis, pDataObject); + if (pThis->bAllowDrop) + { + *pdwEffect = IDRPTRG_DropEffect(dwKeyState, pt, *pdwEffect); + SetFocus(pThis->hWnd); + } + else + *pdwEffect = DROPEFFECT_NONE; + + return S_OK; +} + + +//============================================================================= +// +// IDRPTRG_DragOver() +// +static HRESULT STDMETHODCALLTYPE IDRPTRG_DragOver(PNP3IDROPTARGET pThis, DWORD dwKeyState, POINTL pt, + DWORD *pdwEffect) +{ + if (pThis->bAllowDrop) + { + pThis->dwKeyState = dwKeyState; + + *pdwEffect = IDRPTRG_DropEffect(dwKeyState, pt, *pdwEffect); + } + else + *pdwEffect = DROPEFFECT_NONE; + + return S_OK; +} + + +//============================================================================= +// +// IDRPTRG_DragLeave() +// +static HRESULT STDMETHODCALLTYPE IDRPTRG_DragLeave(PNP3IDROPTARGET pThis) +{ + UNUSED(pThis); + return S_OK; +} + + +//============================================================================= +// +// IDRPTRG_Drop() +// +static HRESULT STDMETHODCALLTYPE IDRPTRG_Drop(PNP3IDROPTARGET pThis, IDataObject *pDataObject, + DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) +{ + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM medium; + ULONG lFmt; + NP3DROPDATA DropData; + + UNUSED(dwKeyState); + UNUSED(pt); + + if (pThis->bAllowDrop) + { + for (lFmt = 0; lFmt < pThis->lNumFormats; lFmt++) + { + fmtetc.cfFormat = pThis->pFormat[lFmt]; + if (pDataObject->lpVtbl->QueryGetData(pDataObject, &fmtetc) == S_OK) + break; + } + if (lFmt < pThis->lNumFormats) + { + pDataObject->lpVtbl->GetData(pDataObject, &fmtetc, &medium); + *pdwEffect = DROPEFFECT_NONE; + if (pThis->pDropProc != NULL) + *pdwEffect = (*pThis->pDropProc)(pThis->pFormat[lFmt], medium.hGlobal, pThis->hWnd, pThis->dwKeyState, + pt, pThis->pUserData); + else if (pThis->nMsg != WM_NULL) + { + DropData.cf = pThis->pFormat[lFmt]; + DropData.dwKeyState = pThis->dwKeyState; + DropData.hData = medium.hGlobal; + DropData.pt = pt; + + *pdwEffect = (DWORD)SendMessage(pThis->hWnd, pThis->nMsg, (WPARAM)&DropData, + (LPARAM)pThis->pUserData); + } + if (*pdwEffect != DROPEFFECT_NONE) + ReleaseStgMedium(&medium); + } + } + else + *pdwEffect = DROPEFFECT_NONE; + + return S_OK; +} + + +//============================================================================= +// +// Np3CreateDropTarget() +// +IDropTarget* Np3CreateDropTarget(CLIPFORMAT *pFormat, ULONG lFmt, HWND hWnd, UINT nMsg, + DWORD(*pDropProc)(CLIPFORMAT cf, HGLOBAL hData, HWND hWnd, DWORD dwKeyState, POINTL pt, void *pUserData), + void *pUserData) +{ + PNP3IDROPTARGET pRet; + static IDRPTRG_VTBL idt_vtbl = { + IDRPTRG_QueryInterface, + IDRPTRG_AddRef, + IDRPTRG_Release, + IDRPTRG_DragEnter, + IDRPTRG_DragOver, + IDRPTRG_DragLeave, + IDRPTRG_Drop }; + + if ((pRet = HeapAlloc(NP3DD_HEAP, 0, sizeof(NP3IDROPTARGET) + lFmt * sizeof(CLIPFORMAT))) == NULL) + return NULL; + pRet->pFormat = (CLIPFORMAT *)(((char *)pRet) + sizeof(NP3IDROPTARGET)); + + pRet->idt.lpVtbl = (IDropTargetVtbl*)&idt_vtbl; + pRet->lRefCount = 1; + pRet->hWnd = hWnd; + pRet->nMsg = nMsg; + pRet->bAllowDrop = FALSE; + pRet->dwKeyState = 0; + pRet->lNumFormats = lFmt; + pRet->pDropProc = pDropProc; + pRet->pUserData = pUserData; + + for (lFmt = 0; lFmt < pRet->lNumFormats; lFmt++) + pRet->pFormat[lFmt] = pFormat[lFmt]; + + return (IDropTarget *)pRet; +} + + + +//============================================================================= +// +// Np3RegisterDragnDrop() +// +PNP3DROPTARGET Np3RegisterDragnDrop(HWND hWnd, CLIPFORMAT *pFormat, ULONG lFmt, UINT nMsg, NP3DDCALLBACK pDropProc, void *pUserData) +{ + IDropTarget *pTarget; + + if ((pTarget = Np3CreateDropTarget(pFormat, lFmt, hWnd, nMsg, pDropProc, pUserData)) == NULL) + return NULL; + + if (RegisterDragDrop(hWnd, pTarget) != S_OK) + { + HeapFree(NP3DD_HEAP, 0, pTarget); + return NULL; + } + + return (PNP3DROPTARGET)pTarget; +} + + +//============================================================================= +// +// Np3RevokeDragnDrop() +// +PNP3DROPTARGET Np3RevokeDragnDrop(PNP3DROPTARGET pTarget) +{ + if (pTarget == NULL) + return NULL; + + if (((PNP3IDROPTARGET)pTarget)->hWnd != NULL) + { + if (GetWindowLongPtr(((PNP3IDROPTARGET)pTarget)->hWnd, GWLP_WNDPROC) != 0) + RevokeDragDrop(((PNP3IDROPTARGET)pTarget)->hWnd); + } + + ((IDropTarget *)pTarget)->lpVtbl->Release((IDropTarget *)pTarget); + + return NULL; +} + + /// End of Helpers.c \\\ diff --git a/src/Helpers.h b/src/Helpers.h index 1488867f0..fb1e857b2 100644 --- a/src/Helpers.h +++ b/src/Helpers.h @@ -436,6 +436,25 @@ inline HRESULT PathCchRenameExtension(PWSTR p,size_t l,PCWSTR a) { UNUSED(l); re inline HRESULT PathCchRemoveFileSpec(PWSTR p,size_t l) { UNUSED(l); return (PathRemoveFileSpec(p) ? S_OK : E_FAIL); } +// special Drag and Drop Handling + +typedef struct tNP3DROPDATA +{ + CLIPFORMAT cf; + POINTL pt; + DWORD dwKeyState; + HGLOBAL hData; +} +NP3DROPDATA, *PNP3DROPDATA; + +typedef struct tNP3DROPTARGET *PNP3DROPTARGET; +typedef DWORD(*NP3DDCALLBACK)(CLIPFORMAT cf, HGLOBAL hData, HWND hWnd, DWORD dwKeyState, POINTL pt, void *pUserData); + +void Np3DragnDropInit(HANDLE hHeap); +PNP3DROPTARGET Np3RegisterDragnDrop(HWND hWnd, CLIPFORMAT *pFormat, ULONG lFmt, UINT nMsg, NP3DDCALLBACK, void *pUserData); +PNP3DROPTARGET Np3RevokeDragnDrop(PNP3DROPTARGET pTarget); + + #endif //_NP3_HELPERS_H_ /// End of Helpers.h \\\ diff --git a/src/Notepad3.c b/src/Notepad3.c index f903125f6..1f848fb63 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -310,6 +310,13 @@ WCHAR g_wchWorkingDirectory[MAX_PATH+2] = { L'\0' }; static UT_icd UndoRedoSelection_icd = { sizeof(UndoRedoSelection_t), NULL, NULL, NULL }; static UT_array* UndoRedoSelectionUTArray = NULL; + +static CLIPFORMAT cfDrpF = CF_HDROP; +static POINTL ptDummy = { 0, 0 }; +static PNP3DROPTARGET pDropTarget = NULL; +static DWORD DropFilesProc(CLIPFORMAT cf, HGLOBAL hData, HWND hWnd, DWORD dwKeyState, POINTL pt, void *pUserData); + + //============================================================================= // // Flags @@ -644,6 +651,9 @@ int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPSTR lpCmdLine,int n if (!hwnd) return FALSE; + // init DragnDrop handler + Np3DragnDropInit(NULL); + if (IsVista()) { if (iSciDirectWriteTech >= 0) SciCall_SetTechnology(DirectWriteTechnology[iSciDirectWriteTech]); @@ -1168,7 +1178,6 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam) MsgDropFiles(hwnd, wParam, lParam); break; - case WM_COPYDATA: return MsgCopyData(hwnd, wParam, lParam); @@ -1225,13 +1234,6 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam) case WM_TRAYMESSAGE: return MsgTrayMessage(hwnd, wParam, lParam); - case WM_MOUSEWHEEL: - case WM_MBUTTONDOWN: - if (wParam & MK_MBUTTON) { - PostMessage(hwnd, WM_COMMAND, MAKELONG(BME_EDIT_BOOKMARKTOGGLE, 1), 0); - } - return DefWindowProc(hwnd, umsg, wParam, lParam); - default: if (umsg == msgTaskbarCreated) { if (!IsWindowVisible(hwnd)) @@ -1412,6 +1414,7 @@ LRESULT MsgCreate(HWND hwnd,WPARAM wParam,LPARAM lParam) // Drag & Drop DragAcceptFiles(hwnd,TRUE); + pDropTarget = Np3RegisterDragnDrop(hwnd, &cfDrpF, 1, WM_NULL, DropFilesProc, (void*)hwndEdit); // File MRU pFileMRU = MRU_Create(L"Recent Files",MRU_NOCASE,32); @@ -1634,6 +1637,7 @@ void MsgEndSession(HWND hwnd, UINT umsg) wininfo = GetMyWindowPlacement(hwnd, NULL); DragAcceptFiles(hwnd, FALSE); + Np3RevokeDragnDrop(pDropTarget); // Terminate clipboard watching if (flagPasteBoard) { @@ -1855,9 +1859,10 @@ void MsgDropFiles(HWND hwnd, WPARAM wParam, LPARAM lParam) if (OpenFileDlg(hwndMain, tchFile, COUNTOF(tchFile), szBuf)) FileLoad(FALSE, FALSE, FALSE, FALSE, tchFile); } - - else + else if (PathFileExists(szBuf)) FileLoad(FALSE, FALSE, FALSE, FALSE, szBuf); + else + MsgBox(MBWARN, IDS_DROP_NO_FILE); if (DragQueryFile(hDrop, (UINT)(-1), NULL, 0) > 1) MsgBox(MBWARN, IDS_ERR_DROP); @@ -1868,6 +1873,57 @@ void MsgDropFiles(HWND hwnd, WPARAM wParam, LPARAM lParam) } + +//============================================================================= +// +// DropFilesProc() - Handles DROPFILES +// +// +static DWORD DropFilesProc(CLIPFORMAT cf, HGLOBAL hData, HWND hWnd, DWORD dwKeyState, POINTL pt, void *pUserData) +{ + UNUSED(dwKeyState); + UNUSED(pt); + + DWORD dwEffect = DROPEFFECT_NONE; + + //HWND hEditWnd = (HWND)pUserData; + UNUSED(pUserData); + + if (cf == CF_HDROP) + { + WCHAR szBuf[MAX_PATH + 40]; + HDROP hDrop = (HDROP)hData; + + // Reset Change Notify + //bPendingChangeNotify = FALSE; + + if (IsIconic(hWnd)) + ShowWindow(hWnd, SW_RESTORE); + + //SetForegroundWindow(hwnd); + + DragQueryFile(hDrop, 0, szBuf, COUNTOF(szBuf)); + + if (PathIsDirectory(szBuf)) { + WCHAR tchFile[MAX_PATH] = { L'\0' }; + if (OpenFileDlg(hWnd, tchFile, COUNTOF(tchFile), szBuf)) + FileLoad(FALSE, FALSE, FALSE, FALSE, tchFile); + } + + else + FileLoad(FALSE, FALSE, FALSE, FALSE, szBuf); + + if (DragQueryFile(hDrop, (UINT)(-1), NULL, 0) > 1) + MsgBox(MBWARN, IDS_ERR_DROP); + + dwEffect = DROPEFFECT_COPY; + } + + return dwEffect; +} /* End of MyDropProc(). */ + + + //============================================================================= // // MsgCopyData() - Handles WM_COPYDATA diff --git a/src/Notepad3.rc b/src/Notepad3.rc index eaede8a2dde1233c31939ebad716afd2a8639795..62f3b3a86bf291de25363fe98329bc0f803a44ca 100644 GIT binary patch delta 232 zcmZ29o%_N}?uHh|ElgIP{4NYZ4E_uO4Dk$pKstVUy(*LR^a&hHEa3_aDGWsn`3wa> zm>&jrdDGZ-=GG9&@@mrNHFWRm39 z0SXp?4NGJwW=Ngxn8_$BsKAiOkPgI|Kob=hN*MB|Gnz69tE&T5fVn`!a)7LSptC@H dpkYwwBmp%QO>Z=1lALbf&BU?Y$&)Fe2>|WpF8u%i delta 24 gcmcaGlY7y0?uHh|ElgIP)8l-YIJOsfF(ots0Cf=vmjD0& diff --git a/src/resource.h b/src/resource.h index 0dabab805..dc6ed473d 100644 --- a/src/resource.h +++ b/src/resource.h @@ -460,6 +460,7 @@ #define IDS_ERR_ACCESSDENIED 50041 #define IDS_WARN_UNKNOWN_EXT 50042 #define IDS_REGEX_INVALID 50043 +#define IDS_DROP_NO_FILE 50044 #define IDS_CMDLINEHELP 60000 #define IDM_EDIT_INSERT_GUID 60001 #define IDC_STATIC -1