COM C#, How to use C++ to call COM

2019-07-07 01:25发布

问题:

I used a online example of C# COM and call it through C++. The following is the C# COM code, only one interface "ICalc" and one class "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;
    }
}
}

The following code is in C++ to call this this function. It is worked. However, I am confused with the code in second line. where is the "ICalcPtr" come from? Or is this some mechanism?

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;

回答1:

If you code works, its because somewhere in the C++ project, there is the following statement defined (it's automatic if you used a #import directive for example):

_COM_SMARTPTR_TYPEDEF(ICalc, __uuidof(ICalc));

_COM_SMARTPTR_TYPEDEF is a macro that defines a "smart pointer" on ICalc. It's a Microsoft Visual C++ magical extension for easier COM support. The official documentation is here: _com_ptr_t Class

A smart pointer is usually referenced by the typedef definition provided by the _COM_SMARTPTR_TYPEDEF macro. This macro takes an interface name and the IID and declares a specialization of _com_ptr_t with the name of the interface plus a suffix of Ptr.



回答2:

I'm not sure what tools you used to export the .NET class to C++, but I suspect COMLib::ICalPtr is simply a typedef to a smart pointer class that manages an underlying raw pointer inside it.

Have you tried stepping through in the debugger to see what the implementation of CreateInstance does? I suspect you see auto-generated code that eventually calls CoCreateInstance and possibly QueryInterface. Maybe some code to translate methods like Factorial into IDispatch::Invoke() calls.



回答3:

ICalcPtr holds the instance of your class that is created by COM.

For the same reason we cannot export classes from a c++ dll, COM objects must be returned to an interface.

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

This article helped me understand the concept.

Now, selbie is correct, the PTR at the end of your interface name is a smartpointer to your interface. For your purposes it's is essentially transparent and can be treated as if it was just and ICalc object. It will however take care of cleanup for you automatically. ICalcPtr is generated for you behind the scenes.



标签: c# c++ com