如何在Shell扩展的IShellExtInit::Initialize中获取触发菜单的文件路径
正确获取Shell扩展右键菜单触发文件路径的方法
你之前的问题出在错误使用了pidlFolder参数——这个参数是文件所在文件夹的PIDL,并非你右键点击的目标文件本身。要获取触发菜单的文件路径,必须通过IDataObject参数提取CF_HDROP格式的数据,这是Shell传递选中文件信息的标准方式。
以下是修正后的IShellExtInit::Initialize实现代码:
// IShellExtInit HRESULT Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) { std::wstring result; // 先检查IDataObject是否有效 if (!pdtobj) { result += L"IDataObject is null"; MessageBox(NULL, result.c_str(), L"Error", MB_OK); return E_INVALIDARG; } // 准备FORMATETC结构,指定CF_HDROP格式 FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stm; ZeroMemory(&stm, sizeof(stm)); // 从IDataObject中获取HDROP数据 HRESULT hr = pdtobj->GetData(&fe, &stm); if (FAILED(hr)) { result += L"Failed to get HDROP data, HRESULT: " + std::to_wstring(hr); MessageBox(NULL, result.c_str(), L"Error", MB_OK); return hr; } HDROP hDrop = static_cast<HDROP>(stm.hGlobal); if (!hDrop) { result += L"HDROP handle is null"; MessageBox(NULL, result.c_str(), L"Error", MB_OK); ReleaseStgMedium(&stm); return E_FAIL; } // 获取选中文件的数量 UINT fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); if (fileCount == 0) { result += L"No files selected"; MessageBox(NULL, result.c_str(), L"Info", MB_OK); ReleaseStgMedium(&stm); return S_OK; } // 提取第一个文件的路径(如果是多选,可循环处理所有文件) TCHAR path[MAX_PATH]; if (DragQueryFile(hDrop, 0, path, MAX_PATH)) { result += L"Selected file path: " + std::wstring(path); } else { result += L"Failed to get file path"; } MessageBox(NULL, result.c_str(), L"Result", MB_OK); // 释放STGMEDIUM资源 ReleaseStgMedium(&stm); return S_OK; }
关键要点说明:
CF_HDROP是Shell用于传递拖拽/选中文件列表的标准剪贴板格式,右键菜单触发时,Shell会把选中的文件信息打包到这个格式里。- 使用
DragQueryFile可以从HDROP句柄中提取单个或多个文件的路径:第一个参数传0xFFFFFFFF可获取选中文件总数,传索引值(从0开始)可获取对应文件的路径。 - 必须调用
ReleaseStgMedium释放GetData获取的STGMEDIUM资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Joe J
相关产品推荐
相关产品推荐

