#include <windows.h>
#include <shlobj.h>
#include <string>
#include <vector>
#include <sstream>
#include "resource.h"
#pragma comment(lib, "ole32.lib")
bool IsCursorInSameProcess() {
POINT pt;
if (GetCursorPos(&pt)) {
HWND hwnd = WindowFromPoint(pt);
if (hwnd) {
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
DWORD currentPid = GetCurrentProcessId();
return pid == currentPid;
}
}
return false;
}
class CDataObject : public IDataObject {
public:
CDataObject(const std::vector<std::wstring>& filePaths) : m_refCount(1) {
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL, { 0 }, NULL };
size_t totalSize = sizeof(DROPFILES);
for (const auto& path : filePaths) {
totalSize += (path.size() + 1) * sizeof(wchar_t);
}
totalSize += sizeof(wchar_t);
stg.hGlobal = GlobalAlloc(GHND, totalSize);
if (stg.hGlobal) {
DROPFILES* pDropFiles = (DROPFILES*)GlobalLock(stg.hGlobal);
pDropFiles->pFiles = sizeof(DROPFILES);
pDropFiles->fWide = TRUE;
wchar_t* pData = (wchar_t*)(pDropFiles + 1);
for (const auto& path : filePaths) {
wcscpy(pData, path.c_str());
pData += path.size() + 1;
}
*pData = L'\0';
GlobalUnlock(stg.hGlobal);
}
m_stg = stg;
m_fmt = fmt;
}
~CDataObject() {
if (m_stg.hGlobal) {
ReleaseStgMedium(&m_stg);
}
}
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override {
if (riid == IID_IDataObject || riid == IID_IUnknown) {
*ppvObject = this;
AddRef();
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() override {
return InterlockedIncrement(&m_refCount);
}
STDMETHODIMP_(ULONG) Release() override {
ULONG refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0) {
delete this;
}
return refCount;
}
STDMETHODIMP GetData(FORMATETC* pFormatetc, STGMEDIUM* pMedium) override {
if (pFormatetc->cfFormat == m_fmt.cfFormat &&
pFormatetc->tymed & m_fmt.tymed &&
pFormatetc->dwAspect == m_fmt.dwAspect) {
pMedium->tymed = TYMED_HGLOBAL;
pMedium->hGlobal = OleDuplicateData(m_stg.hGlobal, m_fmt.cfFormat, 0);
return S_OK;
}
return DV_E_FORMATETC;
}
STDMETHODIMP GetDataHere(FORMATETC* pFormatetc, STGMEDIUM* pMedium) override {
return E_NOTIMPL;
}
STDMETHODIMP QueryGetData(FORMATETC* pFormatetc) override {
return (pFormatetc->cfFormat == m_fmt.cfFormat &&
pFormatetc->tymed & m_fmt.tymed &&
pFormatetc->dwAspect == m_fmt.dwAspect) ? S_OK : DV_E_FORMATETC;
}
STDMETHODIMP GetCanonicalFormatEtc(FORMATETC* pFormatetcIn, FORMATETC* pFormatetcOut) override {
return DATA_S_SAMEFORMATETC;
}
STDMETHODIMP SetData(FORMATETC* pFormatetc, STGMEDIUM* pMedium, BOOL fRelease) override {
return E_NOTIMPL;
}
STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppEnumFormatEtc) override {
return E_NOTIMPL;
}
STDMETHODIMP DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD* pdwConnection) override {
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHODIMP DUnadvise(DWORD dwConnection) override {
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHODIMP EnumDAdvise(IEnumSTATDATA** ppEnumAdvise) override {
return OLE_E_ADVISENOTSUPPORTED;
}
private:
ULONG m_refCount;
FORMATETC m_fmt;
STGMEDIUM m_stg;
};
class CDropSource : public IDropSource {
public:
CDropSource() : m_refCount(1) {}
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override {
if (riid == IID_IDropSource || riid == IID_IUnknown) {
*ppvObject = this;
AddRef();
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() override {
return InterlockedIncrement(&m_refCount);
}
STDMETHODIMP_(ULONG) Release() override {
ULONG refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0) {
delete this;
}
return refCount;
}
STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) override {
if (fEscapePressed) {
return DRAGDROP_S_CANCEL;
}
if (!IsCursorInSameProcess() && !(grfKeyState & MK_LBUTTON)) {
return DRAGDROP_S_DROP;
}
return S_OK;
}
STDMETHODIMP GiveFeedback(DWORD dwEffect) override {
return DRAGDROP_S_USEDEFAULTCURSORS;
}
private:
ULONG m_refCount;
};
std::wstring GetErrorMessage(HRESULT hr) {
LPWSTR pszMessage = nullptr;
DWORD dwLength = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&pszMessage,
0,
NULL
);
std::wstring message;
if (dwLength > 0) {
message = pszMessage;
LocalFree(pszMessage);
} else {
message = L"未知错误";
}
return message;
}
void SimulateFileDrop(const std::vector<std::wstring>& filePaths) {
if (SUCCEEDED(OleInitialize(NULL))) {
CDataObject* pDataObject = new CDataObject(filePaths);
CDropSource* pDropSource = new CDropSource();
DWORD dwEffect;
HRESULT hr = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect);
if (FAILED(hr)) {
std::wstringstream ss;
ss << L"拖放操作失败: " << GetErrorMessage(hr);
MessageBoxW(NULL, ss.str().c_str(), L"错误", MB_ICONERROR);
} else if (hr == DRAGDROP_S_DROP) {
MessageBoxW(NULL, L"拖放操作成功!", L"提示", MB_OK);
} else if (hr == DRAGDROP_S_CANCEL) {
MessageBoxW(NULL, L"拖放操作被取消。", L"提示", MB_OK);
}
pDataObject->Release();
pDropSource->Release();
OleUninitialize();
}
}
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_BUTTON_SIMULATE_DROP: {
std::vector<std::wstring> filePaths = { L"C:\\Dandy\\开发 JD.txt" };
SimulateFileDrop(filePaths);
MessageBoxW(hwndDlg, L"文件拖放模拟完成!", L"提示", MB_OK);
break;
}
case IDC_BUTTON_CLOSE:
EndDialog(hwndDlg, 0);
break;
}
return TRUE;
case WM_CLOSE:
EndDialog(hwndDlg, 0);
return TRUE;
}
return FALSE;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
DialogBoxParamW(hInstance, (LPCWSTR)MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc, 0);
return 0;
}
永久链接