I have (legacy) VB6 code that I want to consume from C# code.
This is somewhat similar to this question, but it refers to passing an array from VB6 consuming a C# dll. My problem is the opposite.
In VB, there is an interface in one dll, and an implementation in another.
Interface:
[
odl,
uuid(339D3BCB-A11F-4fba-B492-FEBDBC540D6F),
version(1.0),
dual,
nonextensible,
oleautomation,
helpstring("Extended Post Interface.")
]
interface IMyInterface : IDispatch {
[id(...),helpstring("String array of errors.")]
HRESULT GetErrors([out, retval] SAFEARRAY(BSTR)* );
};
Implementation (fragment) in cMyImplementationClass:
Private Function IMyInterface_GetErrors() As String()
If mbCacheErrors Then
IMyInterface_GetErrors = msErrors
End If
End Function
I wrapped these 2 dlls with tlbimp.exe and attempt to call the function from C#.
public void UseFoo()
{
cMyImplementationClass foo;
...
var result = foo.GetErrors();
...
}
Calling foo.GetErrors() causes a SafeArrayRankMismatchException. I think this indicates a marshaling problem as described in the Safe Arrays section here.
The recommendation seems to be to use the /sysarray parameter of tlbimp.exe or to manually edit the IL produced, which I tried.
The original IL looks like this:
.method public hidebysig newslot virtual
instance string[]
marshal( safearray bstr)
GetErrors() runtime managed internalcall
{
.override [My.Interfaces]My.Interface.IMyInterface::GetErrors
} // end of method cImplementationClass::GetErrors
While the updated version is:
.method public hidebysig newslot virtual
instance class [mscorlib]System.Array
marshal( safearray)
GetErrors() runtime managed internalcall
{
.override [My.Interfaces]My.Interface.IMyInterface::GetErrors
} // end of method cImplementationClass::GetErrors
I made identical function signature changes in both the interface and implementation. This process is described here. However, it doesn't specify a return value in the function (it uses an "in" reference) and also doesn't use an interface. When I run my code and call from C#, I get the error
Method not found: 'System.Array MyDll.cImplementationClass.GetErrors()'.
It seems to be that something is wrong in the IL that I edited, though I don't know where to go from here.
How can I consume this function from C# without changing the VB6 code?
--Edit-- Redefinition of "msErrors", which initializes the private array that gets returned.
ReDim Preserve msErrors(1 To mlErrorCount)
If I understand correctly, the "1" in that means that the array is indexed from 1 instead of 0, which is the cause of the exception I see get thrown.