Skip to content

Instantly share code, notes, and snippets.

@hb3p8
Created February 1, 2023 20:28
Show Gist options
  • Save hb3p8/0f689bb2cc50acc58144cd501a700f46 to your computer and use it in GitHub Desktop.
Save hb3p8/0f689bb2cc50acc58144cd501a700f46 to your computer and use it in GitHub Desktop.
#include <ole2.h>
#include <ShObjIdl.h>
#include <vector>
#include <string>
class CDropTarget : public IDropTarget
{
public:
CDropTarget() {};
~CDropTarget() {};
// IUnknown methods
HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObject);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
// IDropTarget methods
HRESULT __stdcall DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
HRESULT __stdcall DragLeave();
HRESULT __stdcall Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
int m_RefCount = 0;
DropHandler m_dropHandler;
std::vector<std::vector<char> > m_filenames;
};
namespace lt {
// This one is called externally
bool RegisterDragDropWin (HWND__* in_windowHandle, const DropHandler& in_handler)
{
if (::OleInitialize (NULL) != S_OK)
{
return false;
}
CDropTarget* pDropTarget = new CDropTarget;
pDropTarget->m_dropHandler = in_handler;
return ::RegisterDragDrop (in_windowHandle, pDropTarget) == S_OK;
}
} // namespace lt
HRESULT CDropTarget::QueryInterface (REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == IID_IDropTarget)
{
*ppvObject = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ULONG CDropTarget::AddRef()
{
return ++m_RefCount;
}
ULONG CDropTarget::Release()
{
if (--m_RefCount == 0)
{
delete this;
return 0;
}
return m_RefCount;
}
void FetchFileNames (IDataObject* pDataObj, std::vector<std::vector<char> >& out_filenames)
{
out_filenames.clear();
FORMATETC format = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg;
if (SUCCEEDED(pDataObj->GetData(&format, &stg)))
{
HDROP hDrop = (HDROP)stg.hGlobal;
UINT count = ::DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
for (UINT i = 0; i < count; i++)
{
UINT num_chars = ::DragQueryFileW(hDrop, i, nullptr, 0) + 1;
WCHAR* buffer = new WCHAR[num_chars];
::DragQueryFileW (hDrop, i, buffer, num_chars);
const int bytes_needed = WideCharToMultiByte (CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
out_filenames.emplace_back (bytes_needed, '\0');
WideCharToMultiByte (CP_UTF8, 0, buffer, -1, out_filenames.back().data(), bytes_needed, NULL, NULL);
delete[] buffer;
}
::DragFinish (hDrop);
}
// release the data object
ReleaseStgMedium (&stg);
}
HRESULT CDropTarget::DragEnter (IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
GetGuiState().fileDropHovering = true;
FetchFileNames (pDataObj, m_filenames);
// Can use names of dragged files here as well
return S_OK;
}
HRESULT CDropTarget::DragOver (DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
GetGuiState().fileDropHovering = true;
return S_OK;
}
HRESULT CDropTarget::DragLeave()
{
GetGuiState().fileDropHovering = false;
return S_OK;
}
HRESULT CDropTarget::Drop (IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
FetchFileNames (pDataObj, m_filenames);
if (m_filenames.size() > 0)
{
m_dropHandler (m_filenames[0].data());
}
return S_OK;
}
@hb3p8
Copy link
Author

hb3p8 commented Feb 1, 2023

The code might have some bits from sokol_app.h

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment