C++实现win32窗口文件拖拽

如题,C++如何实现win32窗口文件拖拽,直接上代码

方法1:使用win32消息实现

此方法的弊端在于,无法过滤可以拖拽的文件,拖拽时显示的图标也默认的,无法像资源管理器那样自定义。实现步骤大致分为以下三步:

第一步:首先创建窗口时必须在exStyle加上WS_EX_ACCEPTFILES属性,或者调用DragAcceptFiles(HWND, TRUE)允许文件拖拽

第二步:需要过滤拖拽消息、否则程序以管理员启动会导致拖动无效

BOOL ChangeWndMessageFilter(UINT uMessage, BOOL bAllow) {
  typedef BOOL(WINAPI* ChangeWindowMessageFilterFn)(UINT, DWORD);
  HMODULE hUserMod = NULL;
  BOOL bResult = FALSE;
  hUserMod = LoadLibrary(L"user32.dll");
  if (hUserMod == NULL)
    return FALSE;

  // 获取ChangeWindowMessageFilter函数接口指针  
  ChangeWindowMessageFilterFn pfnChangeWindowMessageFilter = (ChangeWindowMessageFilterFn)GetProcAddress(hUserMod, "ChangeWindowMessageFilter");
  if (pfnChangeWindowMessageFilter == NULL) {
    ::FreeLibrary(hUserMod);
    return FALSE;
  }

  bResult = pfnChangeWindowMessageFilter(uMessage, bAllow ? 1 : 2); // 1-MSGFLT_ADD, 2-MSGFLT_REMOVE
  ::FreeLibrary(hUserMod);

  return bResult;
}
ChangeWndMessageFilter(0x0049, MSGFLT_ADD);
ChangeWndMessageFilter(WM_DROPFILES, MSGFLT_ADD);

第三步:处理拖拽消息

if(uMsg == WM_DROPFILES) {
  HDROP hDrop = (HDROP)wParam;
  UINT uCount = ::DragQueryFileA(hDrop,0xFFFFFFFF,NULL,0);
  if(uCount > 0) {
    char buffer[MAX_PATH]={0};
    char path[MAX_PATH]={0};
    for (UINT i=0;i<uCount;++i) {
      ::DragQueryFileA(hDrop,i,path,MAX_PATH);
      sprintf_s(buffer,"第%d个文件:%s\n",i,path);
      OutputDebugStringA(buffer);
    }
  }
  ::DragFinish(hDrop);
  DragAcceptFiles(m_hWnd,FALSE);
}

方法二:(使用com组件IDropTarget实现)

#include <windows.h>
#include <winerror.h>
#include <Shobjidl.h>
#include <ShlGuid.h>

class MyIDropTarget : public IDropTarget {
public:
  MyIDropTarget()
    :m_pDropTargetHelper(NULL) {
    if (FAILED(CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,
      IID_IDropTargetHelper, (LPVOID*)&m_pDropTargetHelper)))
      m_pDropTargetHelper = NULL;
  }
  ~MyIDropTarget() {
    if (m_pDropTargetHelper != NULL) {
      m_pDropTargetHelper->Release();
      m_pDropTargetHelper = NULL;
    }
  }

  virtual HRESULT STDMETHODCALLTYPE QueryInterface(
    /* [in] */ REFIID riid,
    /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) {
    return S_OK;
  }

  virtual ULONG STDMETHODCALLTYPE AddRef(void) {
    return 1;
  }

  virtual ULONG STDMETHODCALLTYPE Release(void) {
    return 0;
  }

  virtual HRESULT STDMETHODCALLTYPE DragEnter(
    /* [unique][in] */ __RPC__in_opt IDataObject* pDataObj,
    /* [in] */ DWORD grfKeyState,
    /* [in] */ POINTL pt,
    /* [out][in] */ __RPC__inout DWORD* pdwEffect) {
    if (pDataObj == NULL)
      return E_INVALIDARG;

    if (m_pDropTargetHelper)
      m_pDropTargetHelper->DragEnter(g_hWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);

    *pdwEffect = DROPEFFECT_COPY;
    return S_OK;
  }

  virtual HRESULT STDMETHODCALLTYPE DragOver(
    /* [in] */ DWORD grfKeyState,
    /* [in] */ POINTL pt,
    /* [out][in] */ __RPC__inout DWORD* pdwEffect) {
    if (m_pDropTargetHelper)
      m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);

    *pdwEffect = DROPEFFECT_COPY;

    return S_OK;
  }

  virtual HRESULT STDMETHODCALLTYPE DragLeave(void) {
    if (m_pDropTargetHelper)
      m_pDropTargetHelper->DragLeave();

    return S_OK;
  }

  virtual HRESULT STDMETHODCALLTYPE Drop(
    /* [unique][in] */ __RPC__in_opt IDataObject* pDataObj,
    /* [in] */ DWORD grfKeyState,
    /* [in] */ POINTL pt,
    /* [out][in] */ __RPC__inout DWORD* pdwEffect) {
    if (pDataObj == NULL)
      return E_INVALIDARG;

    if (m_pDropTargetHelper)
      m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);

    *pdwEffect = DROPEFFECT_NONE;

    return S_OK;
  }

private:
  struct IDropTargetHelper* m_pDropTargetHelper;  // 这个用来实现资源管理器那种拖放图标
};

// 使用::RegisterDragDrop(g_hWnd, g_MyDragFiles);注册