diff --git a/src/win32_init.c b/src/win32_init.c index 8704150c..c2806166 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -167,6 +167,19 @@ static GLFWbool loadLibraries(void) _glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); } + _glfw.win32.ole32.instance = _glfwPlatformLoadModule("ole32.dll"); + if (_glfw.win32.ole32.instance) + { + _glfw.win32.ole32.OleInitialize_ = (PFN_OleInitialize) + _glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "OleInitialize"); + _glfw.win32.ole32.OleUninitialize_ = (PFN_OleUninitialize) + _glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "OleUninitialize"); + _glfw.win32.ole32.RegisterDragDrop_ = (PFN_RegisterDragDrop) + _glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "RegisterDragDrop"); + _glfw.win32.ole32.RevokeDragDrop_ = (PFN_RevokeDragDrop) + _glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "RevokeDragDrop"); + } + return GLFW_TRUE; } @@ -191,6 +204,9 @@ static void freeLibraries(void) if (_glfw.win32.ntdll.instance) _glfwPlatformFreeModule(_glfw.win32.ntdll.instance); + + if (_glfw.win32.ole32.instance) + _glfwPlatformFreeModule(_glfw.win32.ole32.instance); } // Create key code translation tables @@ -430,6 +446,27 @@ static GLFWbool createHelperWindow(void) return GLFW_TRUE; } +// Initialize OLE as well as the IDropTarget vtable +// +static GLFWbool initDragDrop() +{ + if (FAILED(OleInitialize(NULL))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to initialize OLE"); + return GLFW_FALSE; + } + + //_glfw.win32.dropTargetVtbl.QueryInterface = _glfwDropTarget_QueryInterface; + _glfw.win32.dropTargetVtbl.AddRef = (PFN_IDropTarget_AddRef)_glfwDropTarget_AddRef; + _glfw.win32.dropTargetVtbl.Release = (PFN_IDropTarget_Release)_glfwDropTarget_Release; + _glfw.win32.dropTargetVtbl.DragEnter = (PFN_IDropTarget_DragEnter)_glfwDropTarget_DragEnter; + _glfw.win32.dropTargetVtbl.DragOver = (PFN_IDropTarget_DragOver)_glfwDropTarget_DragOver; + _glfw.win32.dropTargetVtbl.DragLeave = (PFN_IDropTarget_DragLeave)_glfwDropTarget_DragLeave; + _glfw.win32.dropTargetVtbl.Drop = (PFN_IDropTarget_Drop)_glfwDropTarget_Drop; + + return GLFW_TRUE; +} ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -699,6 +736,9 @@ int _glfwInitWin32(void) if (!createHelperWindow()) return GLFW_FALSE; + if (!initDragDrop()) + return GLFW_FALSE; + _glfwPollMonitorsWin32(); return GLFW_TRUE; } @@ -708,6 +748,8 @@ void _glfwTerminateWin32(void) if (_glfw.win32.deviceNotificationHandle) UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle); + OleUninitialize(); + if (_glfw.win32.helperWindowHandle) DestroyWindow(_glfw.win32.helperWindowHandle); if (_glfw.win32.helperWindowClass) diff --git a/src/win32_platform.h b/src/win32_platform.h index c2158943..f91b0424 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -64,11 +64,15 @@ // GLFW uses OEM cursor resources #define OEMRESOURCE +// define COM C object macros +#define COBJMACROS + #include #include #include #include #include +#include // HACK: Define macros that some windows.h variants don't #ifndef WM_MOUSEHWHEEL @@ -316,6 +320,22 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*, typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG); #define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_ +// ole32.dll function pointer typedefs +typedef HRESULT (WINAPI * PFN_OleInitialize)(LPVOID); +typedef VOID (WINAPI * PFN_OleUninitialize)(VOID); +typedef HRESULT (WINAPI * PFN_RegisterDragDrop)(HWND,LPDROPTARGET); +typedef HRESULT (WINAPI * PFN_RevokeDragDrop)(HWND); +typedef ULONG (STDMETHODCALLTYPE * PFN_IDropTarget_AddRef)(LPDROPTARGET); +typedef ULONG (STDMETHODCALLTYPE * PFN_IDropTarget_Release)(LPDROPTARGET); +typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_DragEnter)(LPDROPTARGET,IDataObject*,DWORD,POINTL,DWORD*); +typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_DragOver)(LPDROPTARGET,DWORD,POINTL,DWORD*); +typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_DragLeave)(LPDROPTARGET); +typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_Drop)(LPDROPTARGET,IDataObject*,DWORD,POINTL,DWORD*); +#define OleInitialize _glfw.win32.ole32.OleInitialize_ +#define OleUninitialize _glfw.win32.ole32.OleUninitialize_ +#define RegisterDragDrop _glfw.win32.ole32.RegisterDragDrop_ +#define RevokeDragDrop _glfw.win32.ole32.RevokeDragDrop_ + // WGL extension pointer typedefs typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); @@ -408,6 +428,13 @@ typedef struct _GLFWlibraryWGL GLFWbool ARB_context_flush_control; } _GLFWlibraryWGL; +typedef struct _GLFWdropTarget +{ + IDropTargetVtbl* lpVtbl; + ULONG cRefCount; + _GLFWwindow* window; +} _GLFWdropTarget; + // Win32-specific per-window data // typedef struct _GLFWwindowWin32 @@ -432,6 +459,8 @@ typedef struct _GLFWwindowWin32 int lastCursorPosX, lastCursorPosY; // The last received high surrogate when decoding pairs of UTF-16 messages WCHAR highSurrogate; + + _GLFWdropTarget dropTarget; } _GLFWwindowWin32; // Win32-specific global data @@ -455,6 +484,7 @@ typedef struct _GLFWlibraryWin32 RAWINPUT* rawInput; int rawInputSize; UINT mouseTrailSize; + IDropTargetVtbl dropTargetVtbl; struct { HINSTANCE instance; @@ -497,6 +527,15 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; } ntdll; + + struct { + HINSTANCE instance; + + PFN_OleInitialize OleInitialize_; + PFN_OleUninitialize OleUninitialize_; + PFN_RegisterDragDrop RegisterDragDrop_; + PFN_RevokeDragDrop RevokeDragDrop_; + } ole32; } _GLFWlibraryWin32; // Win32-specific per-monitor data @@ -620,3 +659,11 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); +// IDropTarget vtable functions +//HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(_GLFWdropTarget *This, REFIID riid, void **ppvObject); +ULONG STDMETHODCALLTYPE _glfwDropTarget_AddRef(_GLFWdropTarget *This); +ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(_GLFWdropTarget *This); +HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragEnter(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); +HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragOver(_GLFWdropTarget *This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); +HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(_GLFWdropTarget *This); +HRESULT STDMETHODCALLTYPE _glfwDropTarget_Drop(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); diff --git a/src/win32_window.c b/src/win32_window.c index 8d9c95e7..22df2b38 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -30,6 +30,7 @@ #include "internal.h" #include +#include // TODO remove #include #include #include @@ -1407,7 +1408,15 @@ static int createNativeWindow(_GLFWwindow* window, } } - DragAcceptFiles(window->win32.handle, TRUE); + //DragAcceptFiles(window->win32.handle, TRUE); + window->win32.dropTarget.lpVtbl = &_glfw.win32.dropTargetVtbl; + window->win32.dropTarget.window = window; + if (FAILED(RegisterDragDrop(window->win32.handle, (LPDROPTARGET)&window->win32.dropTarget))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register window for drag & drop"); + return GLFW_FALSE; + } if (fbconfig->transparent) { @@ -1493,6 +1502,8 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window) if (_glfw.win32.disabledCursorWindow == window) _glfw.win32.disabledCursorWindow = NULL; + RevokeDragDrop(window->win32.handle); + if (window->win32.handle) { RemovePropW(window->win32.handle, L"GLFW"); @@ -2452,3 +2463,119 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) return window->win32.handle; } +/*static GLFWbool _glfwIsEqualIID(REFIID riid1, REFIID riid2) +{ + return riid1->Data1 == riid2->Data1 + && riid1->Data2 == riid2->Data2 + && riid1->Data3 == riid2->Data3 + && (memcmp(riid1->Data4, riid2->Data4, sizeof(riid1->Data4)) == 0); +} + +// IDropTarget vtable functions +HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(_GLFWdropTarget *This, REFIID riid, void **ppvObject) +{ + printf("DropTarget_QueryInterface\n"); + if(!ppvObject) + return E_POINTER; + + if (_glfwIsEqualIID(riid, &IID_IUnknown) || _glfwIsEqualIID(riid, &IID_IDropTarget)) + { + *ppvObject = This; + This->lpVtbl->AddRef(This); + return S_OK; + } + + *ppvObject = 0; + return E_NOINTERFACE; +}*/ + +// IDropTarget vtable functions +ULONG STDMETHODCALLTYPE _glfwDropTarget_AddRef(_GLFWdropTarget *This) +{ + printf("DropTarget_AddRef\n"); + return ++This->cRefCount; +} + +ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(_GLFWdropTarget *This) +{ + printf("DropTarget_Release\n"); + return --This->cRefCount; +} + +HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragEnter(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) +{ + FORMATETC fmt = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + + printf("DropTarget_DragEnter\n"); + if(SUCCEEDED(IDataObject_QueryGetData(pDataObj, &fmt))) + { + printf("QueryGetData OK\n"); + *pdwEffect = DROPEFFECT_COPY; + } + else + *pdwEffect = DROPEFFECT_NONE; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragOver(_GLFWdropTarget *This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) +{ + printf("DropTarget_DragOver\n"); + *pdwEffect = DROPEFFECT_COPY; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(_GLFWdropTarget *This) +{ + printf("DropTarget_DragLeave\n"); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE _glfwDropTarget_Drop(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) +{ + FORMATETC fmt = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stgmed; + + printf("DropTarget_Drop\n"); + *pdwEffect = DROPEFFECT_NONE; + + if(SUCCEEDED(IDataObject_QueryGetData(pDataObj, &fmt))) + { + printf("QueryGetData OK\n"); + if(SUCCEEDED(IDataObject_GetData(pDataObj, &fmt, &stgmed))) + { + HDROP drop = (HDROP) GlobalLock(stgmed.hGlobal); + const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); + char** paths = _glfw_calloc(count, sizeof(char*)); + int i; + + printf("GetData OK\n"); + _glfwInputCursorPos(This->window, pt.x, pt.y); + + for (i = 0; i < count; ++i) + { + const UINT length = DragQueryFileW(drop, i, NULL, 0); + WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR)); + + DragQueryFileW(drop, i, buffer, length + 1); + paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); + + _glfw_free(buffer); + } + + _glfwInputDrop(This->window, count, (const char**) paths); + + for (i = 0; i < count; ++i) + _glfw_free(paths[i]); + _glfw_free(paths); + + GlobalUnlock(stgmed.hGlobal); + ReleaseStgMedium(&stgmed); + + *pdwEffect = DROPEFFECT_COPY; + } + } + + return S_OK; +}