У меня есть (устаревший) код VB6, который я хочу использовать из кода С#.
Это несколько похоже на этот вопрос, но это относится к передаче массива из VB6, использующего С# dll. Моя проблема противоположна.
В VB есть интерфейс в одной 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
Я обернул эти 2 dll с помощью tlbimp.exe и попытался вызвать функцию из С#.
public void UseFoo()
{
cMyImplementationClass foo;
...
var result = foo.GetErrors();
...
}
Вызов foo.GetErrors() вызывает SafeArrayRankMismatchException. Я думаю, что это указывает на проблему маршалинга, описанную в разделе "Безопасные массивы" здесь.
Кажется, что рекомендуется использовать параметр /sysarray tlbimp.exe или вручную отредактировать произведенный 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" ), а также не использует интерфейс. Когда я запускаю свой код и звоню с С#, я получаю сообщение об ошибке
Метод не найден: 'System.Array MyDll.cImplementationClass.GetErrors()'.
Кажется, что что-то не так в IL, что я редактировал, хотя я не знаю, куда идти отсюда.
Как я могу использовать эту функцию из С# без изменения кода VB6?
- Edit-- Переопределение "msErrors", которое инициализирует закрытый массив, который возвращается.
ReDim Preserve msErrors(1 To mlErrorCount)
Если я правильно понял, то "1" означает, что массив индексируется из 1 вместо 0, что является причиной исключения, которое я вижу, чтобы получить бросок.