Archive for Oktober 11th, 2007

SOFTWARE: Alles neu macht der Sven!

Der SpeedCommander ist jetzt offiziell in Version 12 verfügbar, schreibt Golem. Die Beta-Tests sind also somit abgeschlossen und das gute Stück ist final. Download wie üblich beim SpeedProject und von dieser Stelle aus ganz lieben Gruß an Sven.

Gutes Tool, definitiv sein Geld wert.

DOTNET: Mehrdimensionales Char-Array aus C++-Komponente abrufen

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. ;-)