我在 Windows 7 SP1 x64 上使用 Visual Studio 2010。
我需要制作一个与 win32 应用程序通信的自定义桌带,编译为 32 位应用程序。
我使用这篇 CodeProject 文章作为起点: http: //www.codeproject.com/Articles/39189/Shell-Extensibility-Explorer-Desk-Band-Tray-Notifi
桌带 dll(为 x64 编译)工作正常 - 我在任务栏等中看到它。
它是使用“以管理员身份运行”的 cmd.exe 中的 regsvr32 注册的。rgs 文件是这样的:
HKCR
{
NoRemove CLSID
{
ForceRemove {8D330AEA-90D1-4632-804B-4710F2358A18} = s 'my deskbar'
{
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
}
}
}
基于这个stackoverflow答案:How to add and implementation a new interface to an Inproc COM server
我在 IDL 文件中创建了一个接口:
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(35662650-07D0-4F31-B5F0-3C21FCA4BDA2),
version(1.0),
oleautomation
//dual,
//pointer_default(unique)
]
interface IGEDeskBand : IDispatch
{
HRESULT BadgeSet([in] long arg);
HRESULT BadgeClear(void);
HRESULT BadgeBlink(void);
};
[
uuid(33EB8C00-F66A-493C-8607-529060FAA378),
version(1.0),
helpstring("GamEffective DeskBand Library")
]
library GEDeskBandLib
{
importlib("stdole32.tlb");
[
uuid(8D330AEA-90D1-4632-804B-4710F2358A18),
helpstring("GEDeskBand Class")
]
coclass GEDeskBand
{
[default] interface IGEDeskBand;
};
cpp_quote("const size_t MAX_GUID_STRING_LEN = 39;")
};
,Visual Studio 使用 midl 编译它生成生成的头文件,我包含生成的代码:#include "GEDeskBand_i.h"
,我让我的类继承自
public IDispatchImpl<IGEDeskBand, &__uuidof(IGEDeskBand), &LIBID_GEDeskBandLib, /* wMajor = */ 1, /* wMinor = */ 0>
,向COM_INTERFACE_ENTRY
COM MAP 添加了一个 with 接口并添加了方法:
STDMETHOD(BadgeSet)(/* [in] */ long arg);
STDMETHOD(BadgeClear)();
STDMETHOD(BadgeBlink)();
(好吧,我使用了Visual Studio Wizard:类视图->右键单击类,添加->实现接口),目前方法的实现只是return E_NOTIMPL;
,我希望这不是问题。这就是我对服务器上的代码所做的所有事情,关于我的界面并尝试从另一个进程与这个对象进行通信。
使用#define _ATL_DEBUG_QI
本文(http://msdn.microsoft.com/en-us/library/ezs95xhx%28v=vs.80%29.aspx),我在附加到 explorer.exe 时在 Visual Studio 的输出窗口中看到(加载deskbar dll并且我的COM对象存在的位置)使用正确的接口查询QueryInterface并且没有说“失败”。
这是加载桌面栏的时间:
CComClassFactory - IClassFactory
CGEDeskBand - IDeskBand
CGEDeskBand - IPersistStreamInit
CGEDeskBand - IDeskBand2
CGEDeskBand - IDeskBand
CGEDeskBand - {EA5F2D61-E008-11CF-99CB-00C04FD64497} - failed
CGEDeskBand - IObjectWithSite
CGEDeskBand - {7FE80CC8-C247-11D0-B93A-00A0C90312E1} - failed
CGEDeskBand - IOleCommandTarget - failed
CGEDeskBand - IDeskBandInfo - failed
CGEDeskBand - IDeskBand
CGEDeskBand - IOleWindow
CGEDeskBand - IPersist
CGEDeskBand - IDeskBand2
这是我运行演示问题的测试器时:
CGEDeskBand - IDeskBand
CGEDeskBand - {00000003-0000-0000-C000-000000000046} - failed
CGEDeskBand - {00000003-0000-0000-C000-000000000046} - failed
CGEDeskBand - {0000001B-0000-0000-C000-000000000046} - failed
CGEDeskBand - IUnknown
CGEDeskBand - {00000018-0000-0000-C000-000000000046} - failed
CGEDeskBand - {00000019-0000-0000-C000-000000000046} - failed
CGEDeskBand - {4C1E39E1-E3E3-4296-AA86-EC938D896E92} - failed
CGEDeskBand - IDeskBand
CGEDeskBand - IDeskBand
CGEDeskBand - IPersist
CGEDeskBand - IPersist
CGEDeskBand - {1C733A30-2A1C-11CE-ADE5-00AA0044773D} - failed
CGEDeskBand - {35662650-07D0-4F31-B5F0-3C21FCA4BDA2}
最后一个是我的 IID,它没有说失败。
这是演示问题的测试代码:
#include <Shobjidl.h>
#include "GEDeskBand_i.h"
#include "GEDeskBandGuids.h"
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr;
CComPtr<IUnknown> spBandService;
CComPtr<IBandSite> spBandSite;
CoInitialize(NULL);
hr = spBandService.CoCreateInstance(CLSID_TrayBandSiteService);
if (SUCCEEDED(hr)) {
hr = spBandService->QueryInterface(&spBandSite);
if (SUCCEEDED(hr)) {
DWORD dwBandId = 0;
UINT num_bands = spBandSite->EnumBands((UINT)-1, &dwBandId);
for (UINT uBand = 0; uBand < num_bands; uBand++) {
if (SUCCEEDED(spBandSite->EnumBands(uBand, &dwBandId))) {
IDeskBand *band;
if (SUCCEEDED(spBandSite->GetBandObject(dwBandId, IID_IDeskBand, (void**)&band))) {
IPersist* pPersist = NULL;
if (SUCCEEDED(band->QueryInterface(IID_IPersist, (void**)&pPersist))) {
CLSID clsid = CLSID_NULL;
if (SUCCEEDED(pPersist->GetClassID(&clsid))) {
if (clsid == CLSID_GEDeskBand) {
// reaches here fine
IGEDeskBand *pGEDeskBand = NULL;
hr = band->QueryInterface(IID_IGEDeskBand, (void**)&pGEDeskBand);
if (SUCCEEDED(hr)) {
// never reaches here, always get E_NOINTERFACE
pGEDeskBand->BadgeSet(1);
}
break;
}
}
}
}
}
}
spBandSite.Release();
}
spBandService.Release();
}
CoUninitialize();
return 0;
}
问题是,虽然我看到了我的 DeskBand 对象的 IDeskBand 或 IPersist(CLSID 匹配,我知道它是我的对象,并且我知道它实现了该接口),但使用我的接口 IID_IGEDeskBand 的 QueryInterface 永远不会成功。
QueryInterface 确实找到了 IID,但它没有到达我的客户端。我想是因为编组。
我尝试将测试仪编译为 x64,但没有奏效。
Raymond Chen 写道:http: //blogs.msdn.com/b/oldnewthing/archive/2004/12/13/281910.aspx
我从那篇博文中了解到的只是我需要处理编组。我以为它应该是自动的?
我看到解决此问题的一种方法是构建中间生成的代理存根:CoCreateInstance 返回 E_NOINTERFACE 即使找到接口
我已经建立并注册了一个代理存根 dll,一个 32 位的,通过让 midl 创建 32 位代理代码和来自这里的配方:http: //msdn.microsoft.com/en-us/library/aa366768%28VS。 85%29.aspx
这也不起作用 - 运行测试器时,我没有看到在测试器进程中加载了代理存根 DLL。我是不是该?它似乎注册正确。
我不太了解 COM 甚至一般的 win32,但我已经搜索了几个小时,但我不明白我做错了什么。