Autor Beitrag
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2229
Erhaltene Danke: 415

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Sa 01.09.18 16:52 
Hallo Forum

Problemstellung:
Folgende Funktion soll nach C# übersetzt werden:

ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
BOOL VFWAPI capGetDriverDescriptionA (UINT wDriverIndex,
        _Out_writes_(cbName) LPSTR lpszName, _In_ int cbName,
        _Out_writes_(cbVer) LPSTR lpszVer, _In_ int cbVer);

BOOL VFWAPI capGetDriverDescriptionW (UINT wDriverIndex,
        _Out_writes_(cbName) LPWSTR lpszName, _In_ int cbName,
        _Out_writes_(cbVer) LPWSTR lpszVer, _In_ int cbVer);

Die Zeiger auf den jeweiligen String bereiten mir dabei Probleme.
Ich könnte stattdessen jeweils einen StringBuilder verwenden, der mir den gewünschten Wert fehlerfrei liefert, jedoch missfällt mir die Handhabe, StringBuilder nutzen zu müssen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
[DllImport("Avicap32.dll", CharSet = CharSet.Auto)]
public static extern bool capGetDriverDescription(
    uint wDriverIndex,
    StringBuilder lpszName
    int cbName,
    StringBuilder lpszVer,
    int cbVer);

// Aufruf
StringBuilder _name = new StringBuilder(256);
StringBuilder _version = new StringBuilder(256);

capGetDriverDescription(0, _name, _name.Capacity, _version, _version.Capacity); // .Capacity  nachträglich korrigiert
MessageBox.Show(_name.ToString() + " - " + _version.ToString());

Versuche ich es mit dem gemarshalten LPTStr, kommt es an der Stelle zu einer AccessViolationException:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
[DllImport("Avicap32.dll", CharSet = CharSet.Auto)]
public static extern bool capGetDriverDescription(
    uint wDriverIndex,
    [MarshalAs(UnmanagedType.LPTStr)]
    ref string lpszName,

    int cbName,
    [MarshalAs(UnmanagedType.LPTStr)]
    ref string lpszVer,
,
    int cbVer);

// Aufruf
string _name = "";
string _version = "";

capGetDriverDescription(0ref _name, 256ref _version, 256);
MessageBox.Show(_name + " - " + _version);

Was genau verursacht den Fehler?

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)


Zuletzt bearbeitet von Frühlingsrolle am So 02.09.18 14:37, insgesamt 1-mal bearbeitet
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3949
Erhaltene Danke: 810

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: So 02.09.18 08:47 
Beim StringBuilder gibst du ja die Größe (256 Bytes) schon im Konstruktor mit, während du bei der (unteren) String-Variante ja noch selber Speicher für den String reservieren müßtest, z.B. string _name = new string(' '256);
Es gäbe auch noch die Variante mittels eines byte- oder (für WideChar) char-Arrays (wie man es ja auch direkt in C bzw. C++ macht).

Ich persönlich finde die StringBuilder-Variante besser, da sie sich auch bei anderen C#-Projekten durchgesetzt hat (daß man nachher dann noch explizit (bzw. implizit) ToString() aufrufen muß, um an den eigentlichen String-Inhalt zu gelangen, sehe ich sogar eher positiv).

PS: Das "+ 1" bei _name.Capacity + 1 ist aber auch fehlerhaft, da du dann ja in deinem Beispiel 257 als Länge übergeben würdest (die abschließende '\0' muß ja bei der Puffergröße mitberechnet werden, d.h. bei einem Puffer von 256 Bytes kann der zurückgegebene String max. 255 Bytes groß sein).

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2229
Erhaltene Danke: 415

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: So 02.09.18 13:00 
Hab' vielen Dank Th69!
Mit einem char-Array wäre es etwas mehr Schreibarbeit, und es müsste am Ende zu einem string konvertiert werden: string s = new string(charArray);
Mit der Puffergröße + 1 hast du recht.
Die zweite Variante sieht nun so aus und funktioniert:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
[DllImport("Avicap32.dll", CharSet = CharSet.Auto)]
public static extern bool capGetDriverDescription(
    uint wDriverIndex,
    [MarshalAs(UnmanagedType.LPTStr)]
    string lpszName, 
    int cbName,
    [MarshalAs(UnmanagedType.LPTStr)]
    string lpszVer,
    int cbVer);

// Aufruf
string _name = new string(' '256);
string _version = new string(' '256);

capGetDriverDescription(0, _name, _name.Length, _version, _version.Length);
MessageBox.Show(_name + " - " + _version);


Das Thema hat sich erledigt !!!

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)