COM C#, 如何使用 C++ 调用 COM

Posted

技术标签:

【中文标题】COM C#, 如何使用 C++ 调用 COM【英文标题】:COM C#, How to use C++ to call COM 【发布时间】:2013-04-29 03:16:06 【问题描述】:

我使用了一个 C# COM 的在线示例,并通过 C++ 调用它。下面是C#的COM代码,只有一个接口“ICalc”和一个类“Calc”。

namespace COMLib

[Guid("F40D7BC9-CF53-4613-AA5E-F269AD73808F")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICalc

    [DispId(1)]
    long Factorial(int n);


[Guid("8EE38F2E-75BE-4B45-87B6-3F6D15FDBBC5")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ICalc))]
[ProgId("MyCalc")]
public class Calc : ICalc

    long ICalc.Factorial(int n)
    
        long fact = 1;
        for (int i = 1; i <= n; i++)
            fact *= i;
        return fact;
    


以下代码在 C++ 中调用此函数。它是有效的。但是,我对第二行中的代码感到困惑。 “ICalcPtr”从何而来?还是这是某种机制?

CoInitialize(NULL);
    COMLib::ICalcPtr pCalc;
    HRESULT hRes = pCalc.CreateInstance(__uuidof(COMLib::Calc));
    if(FAILED(hRes))
        printf("ICalcPtr::CreateInstance failed w/err 0x%08lx\n", hRes);
    else
    
        printf("%d\n", pCalc->Factorial(3));
    
    system("pause");
    CoUninitialize();
    return 0;

【问题讨论】:

您有#import 声明吗?这是基于 COM 类型库 (.tlb) 生成类的 Visual Studio 扩展。 msdn.microsoft.com/en-us/library/8etzzkb6%28v=vs.71%29.aspx 【参考方案1】:

如果你的代码有效,那是因为在 C++ 项目的某个地方,定义了以下语句(例如,如果你使用 #import directive,它是自动的):

_COM_SMARTPTR_TYPEDEF(ICalc, __uuidof(ICalc));

_COM_SMARTPTR_TYPEDEF 是一个在ICalc 上定义“智能指针”的宏。这是一个 Microsoft Visual C++ 神奇的扩展,用于更轻松的 COM 支持。官方文档在这里:_com_ptr_t Class

智能指针通常由 typedef 定义引用 _COM_SMARTPTR_TYPEDEF 宏提供。这个宏需要一个 接口名称和 IID 并声明 _com_ptr_t 的特化 接口名称加上后缀Ptr

【讨论】:

谢谢,这正是我需要的。顺便说一句,我是 COM 和智能指针的更新者。你建议我需要学习什么,因为我面临一个需要使用基于 COM 的 API 的项目。我手头有>。 哇,这在我的脑海里已经过时了 :-) 我有 Essential COM 是的,还有 Wrox 的“专业 DCOM 编程”、“专业 ATL COM 编程”以及“ATL 内部:”。请注意,如果您了解 ATL,您将了解 COM 的真正工作原理。 ATL 不是必需的,但它是学习 COM 的一种方式。 至少阅读“基本 COM”的前 4 章 - 它涵盖了编写 COM 客户端所需了解的 >90%。不过,.NET 和 C++ 之间的 COM 互操作部分可能很复杂。 谢谢你们。你很有帮助【参考方案2】:

我不确定您使用什么工具将 .NET 类导出到 C++,但我怀疑 COMLib::ICalPtr 只是智能指针类的 typedef,它管理其中的底层原始指针。

您是否尝试过在调试器中单步执行以查看 CreateInstance 的实现是做什么的?我怀疑您会看到最终调用 CoCreateInstance 和可能 QueryInterface 的自动生成的代码。也许一些代码可以将 Factorial 等方法转换为 IDispatch::Invoke() 调用。

【讨论】:

【参考方案3】:

ICalcPtr 保存由 COM 创建的类的实例。

出于同样的原因,我们不能从 c++ dll 导出类,COM 对象必须返回到接口。

http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL

这篇文章帮助我理解了这个概念。

现在,selbie 是正确的,接口名称末尾的 PTR 是指向接口的智能指针。出于您的目的,它本质上是透明的,可以将其视为只是 ICalc 对象。但是,它会自动为您进行清理。 ICalcPtr 在幕后为您生成。

【讨论】:

以上是关于COM C#, 如何使用 C++ 调用 COM的主要内容,如果未能解决你的问题,请参考以下文章

如何使用JNI管理C ++代码中的静态变量?

如何在不通过 COM 的情况下从 VB6 调用 C++ DLL?

如何调试 c++ dll 的 ctypes 调用?

C++调用C#dll类库中的方法(非显性COM)

如何中断从 c# interop 调用的 c++ 代码

如何在 C++ 中创建一个公开返回对象的函数的 COM Dll?