177 lines
4.8 KiB
C
177 lines
4.8 KiB
C
|
#include <Windows.h>
|
||
|
#include <oleidl.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include "vector.h"
|
||
|
#include "_cgo_export.h"
|
||
|
|
||
|
#define STDULONGMETHODIMP STDMETHODIMP_(ULONG)
|
||
|
#define DRAGDROP_MAXFILEPATHSIZE 32767
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
IDropTargetVtbl *_vtbl;
|
||
|
long _refCount;
|
||
|
|
||
|
uint32_t _handle;
|
||
|
HWND _windowHandle;
|
||
|
} DragDropHandler;
|
||
|
|
||
|
static void screenToClient(HWND windowHandle, POINTL *point)
|
||
|
{
|
||
|
ScreenToClient(windowHandle, (LPPOINT)point);
|
||
|
}
|
||
|
|
||
|
static STDMETHODIMP QueryInterface(IDropTarget *this, REFIID riid, LPVOID *ppvObj)
|
||
|
{
|
||
|
// Always set out parameter to NULL, validating it first.
|
||
|
if (!ppvObj)
|
||
|
return E_INVALIDARG;
|
||
|
*ppvObj = NULL;
|
||
|
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDropTarget))
|
||
|
{
|
||
|
// Increment the reference count and return the pointer.
|
||
|
*ppvObj = (LPVOID)this;
|
||
|
((DragDropHandler *)this)->_vtbl->AddRef(this);
|
||
|
return NOERROR;
|
||
|
}
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
static STDULONGMETHODIMP AddRef(IDropTarget *this)
|
||
|
{
|
||
|
InterlockedIncrement(&((DragDropHandler *)this)->_refCount);
|
||
|
return ((DragDropHandler *)this)->_refCount;
|
||
|
}
|
||
|
|
||
|
static STDULONGMETHODIMP Release(IDropTarget *this)
|
||
|
{
|
||
|
// Decrement the object's internal counter.
|
||
|
ULONG ulRefCount = InterlockedDecrement(&((DragDropHandler *)this)->_refCount);
|
||
|
if (0 == ((DragDropHandler *)this)->_refCount)
|
||
|
{
|
||
|
GlobalFree(this);
|
||
|
}
|
||
|
return ulRefCount;
|
||
|
}
|
||
|
|
||
|
static STDMETHODIMP DragEnter(IDropTarget *this, __RPC__in_opt IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect)
|
||
|
{
|
||
|
*pdwEffect = DROPEFFECT_COPY;
|
||
|
|
||
|
wchar_t filePath[DRAGDROP_MAXFILEPATHSIZE];
|
||
|
|
||
|
FORMATETC format;
|
||
|
format.cfFormat = CF_HDROP;
|
||
|
format.ptd = NULL;
|
||
|
format.dwAspect = DVASPECT_CONTENT;
|
||
|
format.lindex = -1;
|
||
|
format.tymed = TYMED_HGLOBAL;
|
||
|
|
||
|
STGMEDIUM medium;
|
||
|
|
||
|
HRESULT result = pDataObj->lpVtbl->GetData(pDataObj, &format, &medium);
|
||
|
if (result != S_OK)
|
||
|
return E_UNEXPECTED;
|
||
|
HDROP drop = (HDROP)GlobalLock(medium.hGlobal);
|
||
|
|
||
|
clearFiles(((DragDropHandler *)this)->_handle);
|
||
|
UINT numberOfFiles = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
|
||
|
for (UINT fileIndex = 0; fileIndex < numberOfFiles; fileIndex++)
|
||
|
{
|
||
|
UINT length = DragQueryFileW(drop, fileIndex, filePath, DRAGDROP_MAXFILEPATHSIZE);
|
||
|
addFile(((DragDropHandler *)this)->_handle, &filePath[0], length);
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(medium.hGlobal);
|
||
|
if (medium.pUnkForRelease != NULL)
|
||
|
medium.pUnkForRelease->lpVtbl->Release(medium.pUnkForRelease);
|
||
|
|
||
|
screenToClient(((DragDropHandler *)this)->_windowHandle, &pt);
|
||
|
onDragEnter(((DragDropHandler *)this)->_handle, pt.x, pt.y);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static STDMETHODIMP DragOver(IDropTarget *this, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect)
|
||
|
{
|
||
|
*pdwEffect = DROPEFFECT_COPY;
|
||
|
screenToClient(((DragDropHandler *)this)->_windowHandle, &pt);
|
||
|
onDragOver(((DragDropHandler *)this)->_handle, pt.x, pt.y);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static STDMETHODIMP DragLeave(IDropTarget *this)
|
||
|
{
|
||
|
onDragLeave(((DragDropHandler *)this)->_handle);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static STDMETHODIMP Drop(IDropTarget *this, __RPC__in_opt IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect)
|
||
|
{
|
||
|
*pdwEffect = DROPEFFECT_COPY;
|
||
|
screenToClient(((DragDropHandler *)this)->_windowHandle, &pt);
|
||
|
onDrop(((DragDropHandler *)this)->_handle, pt.x, pt.y);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static const IDropTargetVtbl DragDropHandlerVtbl = {
|
||
|
QueryInterface,
|
||
|
AddRef,
|
||
|
Release,
|
||
|
DragEnter,
|
||
|
DragOver,
|
||
|
DragLeave,
|
||
|
Drop,
|
||
|
};
|
||
|
|
||
|
static DragDropHandler *newDragDropHandler(HWND windowHandle, uint32_t handle)
|
||
|
{
|
||
|
DragDropHandler *handler = malloc(sizeof(DragDropHandler));
|
||
|
handler->_vtbl = (IDropTargetVtbl *)&DragDropHandlerVtbl;
|
||
|
handler->_refCount = 0;
|
||
|
handler->_windowHandle = windowHandle;
|
||
|
handler->_handle = handle;
|
||
|
return handler;
|
||
|
}
|
||
|
|
||
|
BOOL dragDropInitialized = FALSE;
|
||
|
typedef vector(DragDropHandler *) DragDropHandlers;
|
||
|
DragDropHandlers handlers;
|
||
|
|
||
|
static void VerifyResult(CHAR *component, HRESULT result)
|
||
|
{
|
||
|
if (result == S_OK)
|
||
|
return;
|
||
|
printf("%s failed (error code: %d)\n", component, result);
|
||
|
}
|
||
|
|
||
|
static void initDragDrop(void)
|
||
|
{
|
||
|
if (dragDropInitialized == TRUE)
|
||
|
return;
|
||
|
|
||
|
HRESULT result = OleInitialize(NULL);
|
||
|
VerifyResult("OleInitialize", result);
|
||
|
|
||
|
vector_init(handlers);
|
||
|
|
||
|
dragDropInitialized = TRUE;
|
||
|
}
|
||
|
|
||
|
uint32_t RegisterHandler(void *window)
|
||
|
{
|
||
|
initDragDrop();
|
||
|
|
||
|
size_t handle = handlers.count + 1;
|
||
|
HWND windowHandle = (HWND)window;
|
||
|
DragDropHandler *handler = newDragDropHandler(windowHandle, handle);
|
||
|
vector_append(DragDropHandler *, handlers, handler);
|
||
|
|
||
|
DragAcceptFiles(windowHandle, TRUE);
|
||
|
HRESULT result = RegisterDragDrop(windowHandle, (IDropTarget *)handler);
|
||
|
VerifyResult("RegisterDragDrop", result);
|
||
|
|
||
|
return (uint32_t)handle;
|
||
|
}
|