我有一个(遗留的)VB6代码,我想从C#代码中使用它。
这与这个问题有些相似,但它是关于从VB6传递数组来使用C# dll。我的问题则相反。
在VB中,有一个接口在一个dll中,实现在另一个dll中。
接口:
[
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)* );
};
cMyImplementationClass中的实现(片段):
Private Function IMyInterface_GetErrors() As String()
If mbCacheErrors Then
IMyInterface_GetErrors = msErrors
End If
End Function
我使用 tlbimp.exe 将这两个 dll 文件打包,并尝试从 C# 中调用函数。
public void UseFoo()
{
cMyImplementationClass foo;
...
var result = foo.GetErrors();
...
}
调用 foo.GetErrors() 会导致 SafeArrayRankMismatchException 异常。我认为这表明了一个与 Safe 数组相关的内部处理问题,可以在此处 查看详细信息。
建议使用 tlbimp.exe 的 /sysarray 参数或手动编辑生成的 IL。我已经尝试过。
原始的 IL 如下所示:
.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
虽然更新后的版本是:
.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
我在接口和实现中都进行了相同的函数签名更改,具体过程请参考这里。但是,函数中没有指定返回值(它使用了“in”引用),也没有使用接口。当我运行代码并从C#中调用时,出现了以下错误:
Method not found: 'System.Array MyDll.cImplementationClass.GetErrors()'。
看起来我编辑的IL存在问题,但我不知道如何继续下去。
我怎样才能在不更改VB6代码的情况下从C#中使用此函数?
--编辑-- 重新定义“msErrors”,初始化将被返回的私有数组。
ReDim Preserve msErrors(1 To mlErrorCount)
如果我理解正确,那里的“1”表示该数组是从1开始索引而不是0,这就是我看到抛出异常的原因。
Dim msErrors(0 To N) As String
?此外,如果mbCacheErrors为false,则你当前的实现似乎会返回一个未初始化的数组。 - Joevar
关键字,将其声明为System.Array。 - Hans Passantvar
和Array
是个坑。我有一些模糊的直觉,为什么会这样,但我还没有找到详细的资料。你能指出一些关于这种情况的文档吗? - ayers