我正在尝试编写一个数据处理程序shell扩展。在Windows开发人员中心,它说“在对dragShell对象执行拖放操作时会调用数据处理程序。它使您能够为放置目标提供其他剪贴板格式。”我正在尝试在复制或拖动后立即获取所选文件目录。
我可以看到GUID已在注册表中注册,并且在注册表时已调用DllMain和DllRegisterServer。但DllGetClassObject从未被任何进程调用过。我期待explorer.exe在复制或拖动文件时会调用它。
我很确定我在x64配置下编译dll,因为我的操作系统是Windows 7 64位。在VS 2010中使用“创建GUID”工具创建CLSID。注册后,我可以看到CLSID位于shellex下DataHandler的子项下。 dll的完整目录也在该CLSID注册表入口点。所以我想不出有什么理由不加载我的dll。
尽管我可以找到一些关于shell扩展的文章,但大多数都是关于其他处理程序的。唯一相关的是以下链接:
http://msdn.microsoft.com/en-us/library/windows/desktop/cc144163(v=vs.85).aspx
我哪里错了?任何帮助将不胜感激!!
这是DllMain中的代码
// {A097432A-44BE-44FC-AF1D-A012B65392F5}
static const GUID CLSID_DragObjectInfoExt =
{ 0xA097432A, 0x44BE, 0x44FC, { 0xAF, 0x1D, 0xA0, 0x12, 0xB6, 0x53, 0x92, 0xF5 } };
HINSTANCE g_hInst = NULL;
long g_cDllRef = 0;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
MessageBox(NULL, L"DllMain", L"QueryDragObject", MB_OK);
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
g_hInst = hModule;
DisableThreadLibraryCalls(hModule);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
MessageBox(NULL, L"DllGetClassObject", L"QueryDragObject", MB_OK);
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
if (IsEqualCLSID(CLSID_DragObjectInfoExt, rclsid))
{
hr = E_OUTOFMEMORY;
ClassFactory *pClassFactory = new ClassFactory();
if (pClassFactory)
{
hr = pClassFactory->QueryInterface(riid, ppv);
pClassFactory->Release();
}
}
return hr;
}
STDAPI DllCanUnloadNow(void)
{
MessageBox(NULL, L"DllCanUnloadNow", L"QueryDragObject", MB_OK);
return g_cDllRef > 0 ? S_FALSE : S_OK;
}
STDAPI DllRegisterServer(void)
{
/* while(true) {
Sleep(100);
}*/
MessageBox(NULL, L"DllRegisterServer", L"QueryDragObject", MB_OK);
HRESULT hr;
wchar_t szModule[MAX_PATH];
if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
return hr;
}
// Register the component.
hr = RegisterInprocServer(szModule, CLSID_DragObjectInfoExt,
L"TxtShellExtDragObjectHandler.DragObjectInfoExt Class", // Friendly name
L"Apartment"); // Threading model
if (SUCCEEDED(hr))
{
hr = RegisterShellExtDragInfoHandler(L"*",
CLSID_DragObjectInfoExt,
L"TxtShellExtDragObjectHandler.DragObjectInfoExt");
}
else
{
MessageBox(NULL, L"DllRegisterServer failed", L"DragObjectInfoHandler", MB_OK);
}
return hr;
}
STDAPI DllUnregisterServer(void)
{
MessageBox(NULL, L"DllUnregisterServer", L"QueryDragObject", MB_OK);
HRESULT hr = S_OK;
wchar_t szModule[MAX_PATH];
if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
return hr;
}
// Unregister the component.
hr = UnregisterInprocServer(CLSID_DragObjectInfoExt);
if (SUCCEEDED(hr))
{
// Unregister the context menu handler.
hr = UnregisterShellExtDragInfoHandler(L"*",
CLSID_DragObjectInfoExt);
}
else
{
MessageBox(NULL, L"DllUnregisterServer failed", L"DragObjectInfoHandler", MB_OK);
}
return hr;
}
答案 0 :(得分:1)
最后找出我做错的地方。
我在ContextMenu示例中使用了reg.h / cpp文件,只修改了一些地方。事实上,ContextMenuHandlers和DataHandler的注册表树结构有点不同。正确的结构应如下所示:
HKEY_CLASSES_ROOT
.fileType
(Default) = MyProgram.1
CLSID
{00000000-1111-2222-3333-444444444444}
InProcServer32
(Default) = C:\MyDir\MyCommand.dll
ThreadingModel = Apartment
MyProgram.1
(Default) = MyProgram Application
Shellex
DataHandler
(Default) = {00000000-1111-2222-3333-444444444444}
之前就像:
HKEY_CLASSES_ROOT
.fileType
(Default) = MyProgram.1
CLSID
{00000000-1111-2222-3333-444444444444}
InProcServer32
(Default) = C:\MyDir\MyCommand.dll
ThreadingModel = Apartment
MyProgram.1
(Default) = MyProgram Application
Shellex
DataHandler
{00000000-1111-2222-3333-444444444444} =
'Friendly Name'
希望这篇文章可以防止其他人犯同样的错误。