Das hat mich jetzt geschlagene 36 Stunden gekostet (gefühlt drei Wochen): Ich musste ein mehrdimensionales Char-Array aus einer C++-Komponente abholen. Dieses Char-Array ist definiert als
char (*parmWertArray)[100][20]
Also wird im Grunde ein String-Array mit fester Länge definiert. “Jut”, denkt sich da der geneigte Entwickler, “kann ja nicht so schwer sein”. Also wird flugs in die Trickkiste gegriffen und ein Array von StringBuildern verwendet (denn wir wissen bereits, dass Rückgaben in StringBuilder kommen sollen). Schnell mal sowas wie
Dim parameters(99) As StringBuilder
geschrieben und in einer Schleife initialisiert. Hoffnungsvoll an die Komponente übergeben, und dann… Nix. Steht nix drin. Nirgendwo.
Okay, dann nehmen wir einen einzelnen StringBuilder, den wir als
Dim parameters As New StringBuilder(2000)
definieren, denn 100 * 20 Zeichen macht 2000 Zeichen. Schnell übergeben, und siehe! Es gab ein Ergebnis: Einen einzelnen Wert. Um genau zu sein, den ersten Wert des String-Arrays. Das stimmt froh. Inhaltlich aber eher nicht.
Dann eben IntPtr, denn der Kollege Entwickler hat mal gelesen, dass man sowas mit IntPtr abrufen kann. Geht wahrscheinlich auch, nicht aber bei dieser Komponente, denn die erwartet ein vorinitialisiertes Array. Und kann mit einem per Referenz übergebenen IntPtr-Array nix anfangen.
Char-Array? Vielleicht als
Dim parameters(99, 19) As Char
definiert? Nutzlos, geht nicht.
Nachdem mittlerweile 36 Stunden ins Land gegangen sind, besinnt sich der Entwickler auf seinen guten Freund, der ihm letztens bereits schonmal geholfen hat. Dem schickt er den Krempel und bekommt binnen 90 Minuten die Lösung: Byte-Array verwenden!
Dim parameters(99, 19) As Byte
Die zurückgegebenen Bytes müssen nun noch in Chars umgewandelt und dann weiterverarbeitet werden. Das erledigt folgende Methode, die ebenfalls auf dem Lösungsansatz des lieben Kollegen basiert:
Public Shared Function GetArrayValues( _
ByVal aryData As Byte(,), _
ByVal intItemsInArray As Int32) As String
‘ Hier kommt die Rückgabe rein
Dim objResult As New StringBuilder(aryData.Length)
‘ Das Try-Catch kann auch weg, aber ich
‘ habe jetzt keine Lust dazu. Ist ja mein Blog.
Try
Dim objChar As Char
Dim intMaxLength As Int32 = intItemsInArray – 1
If intMaxLength > aryData.GetUpperBound(0) Then
intMaxLength = aryData.GetUpperBound(0)
End If
‘ Beide Arrays durchlaufen
For i As Int32 = 0 To intMaxLength
For j As Int32 = 0 To aryData.GetUpperBound(1)
‘ Aktuellen Byte-Wert konvertieren
‘ und dem Ergebnis anfügen
If aryData(i, j) > Byte.MinValue Then
objChar = ChrW(aryData(i, j))
objResult.Append(objChar)
End If
‘ Irgendwas zum Trennen der verschiedenen Werte
If (j = aryData.GetUpperBound(1)) Then
objResult.Append(“;”)
End If
Next
Next
Catch ex As Exception
End Try
‘ Fertig
Return objResult.ToString
End Function
Der Aufruf ist dann extrem simpel:
‘ Abruf der Daten
Dim aryData(99, 19) As Byte
…
‘ Ermitteln der tatsächlichen Werte
Dim strValue As String = GetArrayValues(aryData, 99)
‘ In String-Array konvertieren oder irgendwas anderes machen
Dim aryValues() As String = strValue.Split(“;”)
Manchmal überlege ich mir ernsthaft, ob ich dem Kerl mal ein paar Blumen schicken soll. Und ob ich für P/Invoke zu doof bin. Aber letzteres nicht ernsthaft.