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;
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.
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 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 ClassICalcPtr 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.