当前位置:首页 > c++ > 正文内容

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

xuwenyan2年前 (2021-03-15)c++372

如题,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
",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);注册
    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/522

    分享给朋友:

    “C++实现win32窗口文件拖拽” 的相关文章

    Visual Studio编译7z源代码

    Visual Studio编译7z源代码

    源代码下载打开地址https://www.7-zip.org/download.html,选择源码下载,可以选择自己需要的版本下载7z.dll编译1:解压源代码包,打开vs解决方案,CPP7zipBundlesFormat7zFFormat7z.dsw,vs会提示升级,不用管,选择升级。2:修改7z...

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    例如,我用VC2015的工程向导新建一个ATL的工程名字叫myAtl,那么VC会同时给我生成一个叫做myAtlPS的工程。这个myAtlPS工程是做什么的?什么情况下可以不需要它?什么情况下它又是必须存在的? PS工程是什么?可以不要吗? 这个PS工程叫做代理与存根(proxy&nbs...

    解决程序在xp系统总是莫名奇妙的崩溃问题(/Zc:threadSafeInit- )

    解决程序在xp系统总是莫名奇妙的崩溃问题(/Zc:threadSafeInit- )

    现象:程序在xp系统上面总是莫名其妙的崩溃,检查代码看不出任何问题,感觉代码都很好。即使你远程调试,找到了崩溃的点,当你注释了崩溃点之后,还是会崩溃到别的地方。当你遇到了这种情况的时候,不妨参照一下下面的方法看看,说不定可以解决问题。如何解决?将崩溃程序相关的所有工程代码全部关闭全局变量的线程安全检...

    ATL实现windows右键菜单扩展(ContextMenu)

    ATL实现windows右键菜单扩展(ContextMenu)

    右键菜单,即用户右击shell对象时弹出的上下文菜单(context menu)。本文记录了如何创建右键菜单的基本过程,跟着步骤一步一步来,即可创建出一个右键菜单工程。第一步,新建一个ATL工程Visual Studio—>新建项目—>ATL—>使用默认配置(一直按下一步即可)。注...

    uafxcwd.lib(afxmem.obj) : error LNK2005:

    uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)"解决办法

    如果在编译MFC程序的时候出现下列及类似的错误: 1˃uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) 已经在 LIBCMTD.lib(new...

    C++ 获取进程所在目录(进程全路径)

    C++ 获取进程所在目录(进程全路径)

    打开windows任务管理器,会看到很多的进程在运行,随机挑选一个,如何通过c++代码获取某一个进程的所在全路径呢?这也是在windows软件开发中经常遇到的需求。通过进程名获取进程全路径由于可能很多进程叫同一个名字,所以获得的结果也有可能是多个#include <windows.h...