Ich habe (Legacy) VB6-Code, den ich von C# -Code verbrauchen möchte.Consuming VB6 String-Array in C#
Dies ist etwas ähnlich wie this question, aber es bezieht sich auf die Übergabe eines Arrays von VB6 mit einer C# dll. Mein Problem ist das Gegenteil.
In VB gibt es eine Schnittstelle in einer DLL und eine Implementierung in einer anderen.
Schnittstelle:
[
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 gewickelt diese 2 DLLs mit tlbimp.exe und versuchen, die Funktion von C# zu nennen.
public void UseFoo()
{
cMyImplementationClass foo;
...
var result = foo.GetErrors();
...
}
foo.GetErrors Calling() bewirkt, dass ein SafeArrayRankMismatchException. Ich denke, das deutet auf ein Marshalling-Problem hin, wie es im Abschnitt "Sichere Arrays" beschrieben ist: here.
Die Empfehlung scheint zu sein, den Parameter/sysarray von tlbimp.exe zu verwenden oder die erzeugte IL manuell zu bearbeiten, die ich ausprobierte.
Das Original IL sieht wie folgt aus:
.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
Während die aktualisierte Version ist:
.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 identische Funktionssignatur Änderungen sowohl in der Schnittstelle und Implementierung gemacht. Dieser Prozess wird beschrieben here. Es spezifiziert jedoch keinen Rückgabewert in der Funktion (es verwendet eine "in" -Referenz) und verwendet auch keine Schnittstelle. Wenn ich meinen Code ausführen und von C# aufrufen, erhalte ich den Fehler
Methode nicht gefunden: 'System.Array MyDll.cImplementationClass.GetErrors()'.
Es scheint zu sein, dass etwas in der IL falsch ist, dass ich bearbeitet, obwohl ich nicht weiß, wohin man von hier zu gehen.
Wie kann ich diese Funktion von C# verwenden, ohne den VB6-Code zu ändern?
--Edit-- Neudefinition von "msErrors", die das private Array initialisiert, das zurückgegeben wird.
ReDim Preserve msErrors(1 To mlErrorCount)
Wenn ich richtig verstehe, die „1“ in das bedeutet, dass die Anordnung von 1 indiziert wird anstelle von 0, was die Ursache für die Ausnahme ist, bekomme ich geworfen zu sehen.
Ich verstehe, dass Sie es arbeiten zuerst erhalten möchten, aber die Bearbeitung der IL scheint nicht wie eine langfristige Lösung. –
Vielleicht, aber es ist die empfohlene Praxis für Marshalling Änderungen erwähnt [hier] (https://msdn.microsoft.com/en-us/library/ek1fb3c6 (v = vs.100) .aspx # cpconeditingmicrosoftintermediatelanguagemsilanchor4). FWIW, das/sysarray-Flag scheint denselben Nettoeffekt zu haben, einschließlich des resultierenden Fehlers. – ayers
Sie haben nicht gezeigt, wie Sie das Array deklarieren, das Sie aus VB6-Code zurückgeben. Hat es Rang 1 und untere Grenze 0, d. H. Als etwas wie "Dim msErrors (0 bis N) As String" deklariert? Wenn mbCacheErrors false ist, scheint Ihre aktuelle Implementierung ein nicht initialisiertes Array zurückzugeben. – Joe