Win32: Implement drag & drop via IDropTarget

This commit is contained in:
Florian Albrechtskirchinger 2022-06-10 13:24:45 +02:00
parent 735f31454e
commit d2763ec2a1
No known key found for this signature in database
GPG Key ID: 19618CE9B2D4BE6D
3 changed files with 217 additions and 1 deletions

View File

@ -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)

View File

@ -64,11 +64,15 @@
// GLFW uses OEM cursor resources
#define OEMRESOURCE
// define COM C object macros
#define COBJMACROS
#include <wctype.h>
#include <windows.h>
#include <dinput.h>
#include <xinput.h>
#include <dbt.h>
#include <ole2.h>
// 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);

View File

@ -30,6 +30,7 @@
#include "internal.h"
#include <limits.h>
#include <stdio.h> // TODO remove
#include <stdlib.h>
#include <string.h>
#include <windowsx.h>
@ -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;
}