【问题标题】:Using MSVC++, how to create COM object implementing existing classes and interfaces?使用 MSVC++,如何创建实现现有类和接口的 COM 对象?
【发布时间】:2021-12-27 04:52:58
【问题描述】:

我有一个进程内 COM 服务器 FooObject.dll,我不再拥有它的源代码,但我想使用相同的接口在非托管 C++ 中编写一个新实现。我正在使用 Visual Studio 2019 最新更新。

我该怎么做?


到目前为止,我建立了一个这样的项目:

  • 使用https://stackoverflow.com/a/42074044/1505939 中的说明提取FooObject.tlb
  • 使用 OleView.exe 从 FooObject.tlb 创建 FooObject.idl
  • 在 Visual Studio 中创建一个类型为“ATL 项目”的新项目,使用选项“允许合并代理/存根代码”和“支持 COM+ 1.0”以及“dll”类型。

我(单独)尝试了以下事情

  • 在“源文件”下,右键单击 -> 添加现有项 -> FooObject.idl.

    • 这导致ATLProject1_i.c.h 重新生成,只包含来自FooObject.idl 的定义,然后dllmain.h 无法编译,因为它引用了LIBID_ATLProject1Lib,它曾经在ATLProject1_i.c 中但不是现在。所以我想这不是预期的方法。
    • 还尝试添加FoOObject.idl 和删除ATLProject1.idl,它再次成功构建,甚至允许使用注册所有相同类的regsvr32 注册(可以通过OleView 中的类型库浏览器查看);但仍然没有实现,并且在测试容器中创建一个对象会给出 80040154,就好像它没有注册一样。
  • #import "FooObject.dll 添加到ATLProject1.cpp 的顶部,在includes 下。项目编译没有错误,但没有生成导入文件。

  • importlib "FooObject.idl" 添加到 ATLProject1.idl 文件。它再次编译没有错误,但不生成任何导入文件。

  • 使用midl /header FooObject.h /env win32 FooObject.idl 手动创建导入文件。这确实创建了导入文件,我可以将它们包含在 #include "FooObject.h" 中并且不会出错。

在所有最后 3 种情况下都没有错误,但不清楚如何为 FooObject.idl 中的 CoClasses 生成实现代码,就像我去“添加新项目”并选择要添加的 ATL 简单对象时出现的那样.所以我不确定如何从这里开始为我正在尝试创建的对象中的函数体编写代码。

(我之前的经验是使用非 Microsoft 供应商,其编辑器只允许您从注册表中添加任何 CoClass,它会生成框架代码)。

【问题讨论】:

    标签: c++ com visual-studio-2019 atl idl


    【解决方案1】:

    ATL 很棒,但您应该避免使用 ATL 向导创建项目。自 90 年代以来,该向导尚未在 Visual Studio 中更新。在空白项目中使用 ATL 设置 DLL com 服务器很容易。

    从 Visual Studio 中的空 Win32 DLL 项目开始。 (使用“桌面向导项目”)

    添加一个新的源文件“MyFooObject.cpp”,如下所示。这是一个最小的 COM DLL 项目。

    #include <windows.h>
    #include <atlbase.h>
    #include <atlcom.h>
    
    
    struct DECLSPEC_UUID("DEADBEEF-FFFF-EEEE-DDDD-CCCCBBBBAAAA") IFooObject: public IUnknown
    {
        virtual HRESULT __stdcall DoSomething() = 0;
    };
    
    class MyModule : public CAtlDllModuleT<MyModule>
    {
    
    };
    
    
    class DECLSPEC_UUID("ABBADABA-1111-2222-3333-444455556666") MyFooObject :
        public CComObjectRootEx<CComMultiThreadModel>,
        public CComCoClass<MyFooObject>,
        public IFooObject
    {
    public:
    
        DECLARE_NO_REGISTRY();
    
        BEGIN_COM_MAP(MyFooObject)
            COM_INTERFACE_ENTRY(IFooObject)
        END_COM_MAP()
    
        // IFooObject
        HRESULT __stdcall DoSomething() override;
    };
    
    
    HRESULT MyFooObject::DoSomething()
    {
        MessageBoxA(NULL, "Something just happened", "COM sample", MB_OK);
        return S_OK;
    }
    
    OBJECT_ENTRY_AUTO(__uuidof(MyComClass), MyComClass);
    
    

    以下是您如何修改步骤以利用上述内容:

    1. 对您之前提取的 IDL 文件运行 MIDL。这应该创建一个带有接口声明的头文件作为 C++ 类。对于 COM DLL 项目,您可以忽略生成的代理/存根代码。您只需要 MIDL 生成的头文件:FooObject.h,其中包含您的接口的类声明

    2. 将 FooObject.h 复制到您的源代码目录。在上面添加#include "FooObject.h" to the list of includes after #include `。

    3. 删除我已经提供的 IFooObject 声明,因为它现在已在 FooObject.h 中声明

    4. 从声明 MyFooObject 中删除“DoSomething”并替换为 IFooObject 声明的公共方法。不要尝试实现 AddRef、Release 或 QueryInterface。

    5. 将 MyFooObject::DoSomething() 的定义替换为您在第 4 步中声明的方法。

    6. 构建您的项目。

    7. 你必须自己做 COM 注册表的事情。

    【讨论】:

    • 那么没有办法自动创建class MyFooObject 类定义,给定IDL? (即使它是在使用向导向 IDL 添加新的 CoClass 时自动创建的!)。
    • @MM - ATL 向导的想法是它是起点(它创建 .idl、.cpp 和 .h,还有 .rgs 等),而不是 .idl 本身
    • @SimonMourier 是的,我有 IDL,问题步骤是从那个到定义 CoClasses 的 C++ 实现。 selbie 似乎在说这一切基本上都必须手工完成
    • @M.M - 我也是这么说的。 ATL 向导不是从 IDL 开始,而是创建 IDL。 AFAIK 在 Visual Studio 中没有任何东西可以从 IDL 创建样板 C/C++ 实现代码。
    猜你喜欢
    • 2011-01-12
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2015-07-03
    相关资源
    最近更新 更多