Using .NET components from unmanaged COM
The first piece of plumbing necessary is the .NET interface that will also be the COM interface.
using System.Runtime.InteropServices;
namespace Core.VRAF.Compatibility
{
// The common interface between the .NET environment and the COM environment.
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IDotNETDispatch
{
}
}
The second piece of plumbing is the actual class implementing the interface. The most essential part is the actual attribute instructing the compiler / regasm.exe not to create a class interface. Class interfaces are not as good as the actual interface we declared above.
using System.Runtime.InteropServices;
namespace Core.VRAF.Compatibility
{
// The .NET class implementing the interface.
[ClassInterface(ClassInterfaceType.None)]
{
}
}
As soon as the implementation class in done it is time to create the type library. The easiest way is to run the regasm.exe on the .NET assembly library containing the classes and interfaces. Using the /tlb option will also create a .tlb file that may be used in the unmanaged COM environment to do early binding, but it is not required.
After running regasm the .NET library is now ready to be used from an unmanaged COM environment. It is now a simple matter of creating the .NET component / class / object from C++.
IDispatchPtr m_pd;
// Create and instance of the DotNETDispatch object
_bstr_t dotNETDispatch = "Core.VRAF.Compatibility.DotNETDispatch";
HRESULT hr = m_pd.CreateInstance((LPCSTR)dotNETDispatch);
Now all that remains is to call a method on the dispatch pointer. This will basically call the method on the .NET component / object.
_bstr_t methodName = "CreateObject";
HRESULT hr = GetIDOfName(m_pd, methodName, &dispid);
if (FAILED(hr))
return hr;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
_variant_t argument1;
_variant_t argument2;
argument1.boolVal = bSuperClass;
argument1.vt = VT_BOOL;
// Add the arguments for the function.
// Remember to add the arguments in reverse, last argument in the 0th position
_variant_t avaArg[2];
avaArg[1] = argument1;
avaArg[0] = argument2;
dispparams.cArgs = 2;
dispparams.rgvarg = avaArg;
EXCEPINFO excepInfo;
memset(&excepInfo, 0, sizeof(excepInfo));
hr = m_pd->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL);
return hr;