0

我在 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_ENTRYCOM 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,但我已经搜索了几个小时,但我不明白我做错了什么。

4

0 回答 0