I have a .NET DLL that exposes a method that looks like this in C#:
void TestMethod(ref TestClass[] parameter)
Where TestClass is a regular C# class that has a COM-visible interface, and I'm supposed to call the method with an array with one element. I can't figure out how to invoke this via COM from a C++ program.
That parameter becomes a SAFEARRAY**. Currently, I'm doing this, where m_Object is a smart pointer to the class that has TestMethod:
VARIANT* current = NULL;
HRESULT hrx = SafeArrayAccessData(ret, (LPVOID*)¤t);
ITestClassPtr item;
item.CreateInstance(__uuidof(TestClass));
current->vt = VT_UNKNOWN;
current->punkVal = item.GetInterfacePtr();
SafeArrayUnaccessData(ret);
HRESULT hr = (*m_Object)->TestMethod(&ret);
This results in 0x80131533 "A mismatch has occurred between the runtime type of the array and the sub type recorded in the metadata".
I have also tried:
ITestClassPtr item; item.CreateInstance(__uuidof(TestClass)); long i = 0; SafeArrayPutElement(ret, &i, item); HRESULT hr = (*m_Object)->TestMethod(&ret);
Which results in an unhelpful 0x80131600.
I've also tried using a CComSafeArray, but I'm getting the same results (it's just a wrapper around SAFEARRAY anyway).
I do not have sources for the DLL, and I can't debug into it. I've searched around the web, and I can find lots of examples for how to invoke a C# DLL via COM, but none that covers specifically how to pass ref arrays of classes from C++ to C#.
Any ideas?
Let's suppose you have these C# classes:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class TestClass1
{
public void SayHello()
{
Console.WriteLine("Hello 1");
}
public void TestMethod(ref TestClass2[] parameter)
{
parameter[0].SayHello();
}
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class TestClass2
{
public void SayHello()
{
Console.WriteLine("Hello 2");
}
}
You can register it and create the type library with a command line like this:
%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe ClassLibrary1.dll /codebase /tlb
If you look at the typelib created using OleView from Windows SDK, TestMethod
is declared like this:
[id(0x60020005)]
HRESULT TestMethod([in, out] SAFEARRAY(_TestClass2*)* parameter);
So its a SAFEARRAY
of _TestClass2
pointers (IUnknown
-derived), and you can create it and use it like this (assuming Visual Studio support):
...
#import "c:\mypath\ClassLibrary1.tlb" raw_interfaces_only
using namespace ClassLibrary1;
int main()
{
CoInitialize(NULL);
{
// warning: all error checks omitted
CComPtr<_TestClass1> tc1;
tc1.CoCreateInstance(__uuidof(TestClass1));
tc1.SayHello(); // outputs "Hello 1"
CComPtr<_TestClass2> tc2;
tc2.CoCreateInstance(__uuidof(TestClass2));
SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);
LONG index = 0;
// note this will call AddRef on tc2 so it's safe
SafeArrayPutElement(psa, &index, (_TestClass2*)tc2);
tc1->TestMethod(&psa); // Outputs "Hello 2"
SafeArrayDestroy(psa);
}
CoUninitialize();
return 0;
}
User contributions licensed under CC BY-SA 3.0