2016-11-19 2 views
0

Ich habe eine DLL, die von VBA-Code in einem Excel-Arbeitsblatt verwendet wird. Die Dinge funktionieren gut - außer es gibt eine Funktion, die einen SAFEARRAY benötigt.So verwenden Sie SAFEARRAY in C# für C++ DLL-Funktion geschrieben für Excel vba

Abbreviated Excel-VBA-Code sieht wie folgt aus:

Private sub ExcelFoo() 
    Dim v(115,17) 
    ...stuff ... 
    MyFunctionCollectionLib.SetMatrix v 

Dies erfordert eine DLL, in C++ geschrieben. Die C++ Funktion sieht wie folgt aus:

void _stdcall SetMatrix(SAFEARRAY **psaMatrix) 
    ... store matrix somewhere ... 

Alles in Ordnung in Excel funktioniert.

Jetzt möchte ich die gleiche Funktion in C# verwenden. Der Objekt-Browser zeigt die folgenden Informationen über die Funktion (in der DLL):

Sub SetMatrix(psaMatrix() As Double) 

Also habe ich eine DLL-Wrapper schrieb wie folgt:

// void _stdcall SetMatrix(SAFEARRAY **psaMatrix) 
[DllImport("MyFunctionCollectionLib.dll", CallingConvention = CallingConvention.StdCall)] 
public extern static void SetMatrix(ref double[,] psaMatrix); 

Ein dann in C# ich versuchen, es zu verwenden, wie folgt:

public void ReadDefaultValues() 
{ 
    double[,] tMatrix = _TestData.ReadDefaultValues(); 
    DllWrapper.DllWrapper.SetMatrix(ref tMatrix); 

der Debugger mir zeigt, dass TMatrix ursprünglich ein Doppel [115, 17] ist - wie definiert sind, aber es kommt zu einem Doppel [1] nach dem SetMatrix() -Aufruf geändert wird.

Es gibt ein paar andere Kuriositäten, die mich zweifeln lassen, dass ich das richtig mache. Ich weiß wirklich nichts über Excel/vba und all das. So werde ich von vielen "Gotchas" erwischt, da ich wirklich nicht in meinem Bereich bin.

Gibt es Dokumentation über SAFEARRAY, die einfach verfügbar ist? (Es muss nicht leicht lesbar sein) Meine Google-Suchen bringen viele etwas obskure Seiten über COM und Marshalling. Diese Seiten scheinen nicht direkt zu adressieren, wonach ich suche. Die Microsoft-Dokumentation beschreibt die SAFEARRAY-Struktur, scheint jedoch keine nähere Erläuterung zur Verwendung zu bieten.

============================================== =========================

Wenn ich die vorgeschlagene Dokumentation verstehen, was ich tun muss, ist meine Wrapper zu ändern:

// void _stdcall SetMatrix(SAFEARRAY **psaMatrix) 
[DllImport("MyFunctionCollectionLib.dll", CallingConvention = CallingConvention.StdCall)] 
[In][Out][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] double[,] pArrayOfDouble 

Für den Wrapper gibt es einen VT_DECIMAL, aber keinen VT_DOUBLE-Typ - also nehme ich an, ich sollte VT_VARIANT als Typ verwenden.

Der obige Code fehlschlägt (kopiert hier):

double[,] tMatrix = _TestData.ReadDefaultValues(); 
    DllWrapper.DllWrapper.SetMatrix(ref tMatrix); 

, wenn ich mit var versuchen (? Das ist die C# Variante) es scheitert auch

var tMatrix = _TestData.ReadDefaultValues(); 
    DllWrapper.DllWrapper.SetMatrix(ref tMatrix); 

Die Fehlermeldung ist in beiden Fällen : Das angegebene Array war nicht der erwartete Typ.

Wo finde ich den erwarteten Typ?Der Stack-Trace-Sendungen:

at MyFunctionCOllection.MyFunctionCOllectionWrapper.SetMatrix(Double[,] pArrayOfDouble) 
+0

[Marshaling ein SAFEARRAY der verwalteten Strukturen von P/rufen Sie Teil 1] (https://limbioliong.wordpress.com/2012/02/28/marshaling-a-safearray-of-managed-structures-by-pinvoke -part-1 /) – Phil1970

+0

[Marshaling ein SAFEARRAY von verwalteten Strukturen von P/rufen Sie Teil 2] (https://limbioliong.wordpress.com/2012/02/29/marshaling-a-safearray-of-managed-structures -by-pinvoke-part-2 /) – Phil1970

+0

[Marshalling-Arrays von VARIANT mit P/Invoke] (http://stackoverflow.com/questions/18716314/marshalling-arrays-of-variant-using-p-invoke) – Phil1970

Antwort

0

ok, anscheinend wollte er die C# "Wrapper" neu zu definieren oder was auch immer es heißt:

[DllImport("MyFunctionCollectionLib.dll", CallingConvention = CallingConvention.StdCall)] 
[In][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_R8)] double[,] pArrayOfDouble 

Dann kann ich es ohne Referenz-Code:

var tMatrix = _TestData.ReadDefaultValues(); 
DllWrapper.DllWrapper.SetMatrix(tMatrix); 

Ich habe VT_R8 nicht als definierende Doppelgänger gesehen. Jetzt hörte zumindest das Ding auf, sich über Datentypen und dergleichen zu beklagen.

Verwandte Themen