如何使用C++ Win32 API获取Windows文件夹中右键点击项的名称
实现方案:C++ Win32 API获取资源管理器右键选中项文件名
参考场景:
对应场景下可直接获取右键选中的wordpad.exe文件名
两种常用实现路径
根据使用场景二选一:
- 上下文菜单扩展方案:适合需要将功能集成到系统右键菜单的场景,稳定性最高
- 独立进程主动获取方案:适合在自有程序中主动读取当前资源管理器选中项的场景
方案1:上下文菜单扩展实现
通过实现Shell扩展的IShellExtInit接口,在用户右键点击时直接从资源管理器传入的参数中提取选中文件信息:
#include <shobjidl.h> #include <shlwapi.h> #pragma comment(lib, "shlwapi.lib") STDMETHODIMP CContextMenuExt::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) { if (pdtobj == nullptr) return E_INVALIDARG; // 从数据对象中提取选中文件的HDROP结构 FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stm; if (FAILED(pdtobj->GetData(&fe, &stm))) return E_FAIL; HDROP hDrop = (HDROP)GlobalLock(stm.hGlobal); if (hDrop == nullptr) { ReleaseStgMedium(&stm); return E_FAIL; } // 遍历所有选中文件 UINT fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); for (UINT i = 0; i < fileCount; i++) { WCHAR filePath[MAX_PATH] = {0}; DragQueryFile(hDrop, i, filePath, MAX_PATH); // 提取纯文件名,不需要完整路径可直接使用该值 LPCWSTR fileName = PathFindFileName(filePath); } GlobalUnlock(stm.hGlobal); ReleaseStgMedium(&stm); return S_OK; }
注意事项
- 该方案需要将实现打包为COM DLL,注册到系统的Shell扩展项中,注册时需要管理员权限,32位/64位系统需要对应架构的DLL
- 支持多选场景,可一次性获取所有右键选中的文件名
方案2:独立进程主动获取实现
不需要注册Shell扩展,直接在自有进程中枚举当前打开的资源管理器窗口,读取选中项信息:
#include <exdisp.h> #include <shobjidl.h> #include <shlwapi.h> #pragma comment(lib, "shell32.lib") #pragma comment(lib, "shlwapi.lib") void GetExplorerSelectedFiles() { // 调用前需要先完成COM初始化:CoInitialize(NULL) CComPtr<IShellWindows> pShellWindows; HRESULT hr = pShellWindows.CoCreateInstance(CLSID_ShellWindows); if (FAILED(hr)) return; long wndCount = 0; pShellWindows->get_Count(&wndCount); for (long i = 0; i < wndCount; i++) { CComPtr<IDispatch> pDisp; VARIANT vIndex = {0}; vIndex.vt = VT_I4; vIndex.lVal = i; hr = pShellWindows->Item(vIndex, &pDisp); if (FAILED(hr) || !pDisp) continue; CComQIPtr<IWebBrowserApp> pBrowser(pDisp); if (!pBrowser) continue; CComPtr<IServiceProvider> pSP; hr = pBrowser->QueryInterface(IID_PPV_ARGS(&pSP)); if (FAILED(hr)) continue; CComPtr<IShellBrowser> pShellBrowser; hr = pSP->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&pShellBrowser)); if (FAILED(hr)) continue; CComPtr<IShellView> pShellView; hr = pShellBrowser->QueryActiveShellView(&pShellView); if (FAILED(hr)) continue; CComPtr<IFolderView> pFolderView; hr = pShellView->QueryInterface(IID_PPV_ARGS(&pFolderView)); if (FAILED(hr)) continue; // 获取当前窗口选中项数量 int selectedCount = 0; hr = pFolderView->SelectedItemsCount(&selectedCount); if (selectedCount <= 0) continue; // 遍历选中项提取文件名 for (int j = 0; j < selectedCount; j++) { PCITEMID_CHILD pidl; hr = pFolderView->Item(j, &pidl); if (FAILED(hr)) continue; WCHAR filePath[MAX_PATH] = {0}; // 虚拟文件夹(如库、回收站)无法通过该接口拿到本地路径 if (SHGetPathFromIDList(pidl, filePath)) { LPCWSTR fileName = PathFindFileName(filePath); // 此处可直接使用拿到的文件名 } } } // 程序退出前执行COM反初始化:CoUninitialize() }
注意事项
- 仅支持获取普通文件系统目录下的选中项,虚拟目录无法拿到本地路径
- 不需要管理员权限,可直接在普通权限进程中运行
内容的提问来源于stack exchange,提问作者Benny K
相关产品推荐
相关产品推荐


