Discussion:
PAnsiChar to (Unicode)String
(zu alt für eine Antwort)
k***@gmail.com
2018-02-06 18:18:54 UTC
Permalink
Hallo,

Ich stehe gerade auf'm Schlauch und sehe den Wald vor lauter Bäumen nicht mehr. Ich migriere ein D5-Projekt zu Delphi 10.2 Starter (Tokyo), zu Unicode.

In der ItemProp-Unit von Brad Stowers wird die Funktion GetCommandString (vom ContextMenu) verwendet. Hier wird der Funktion eine Variable vom Typ PAnsiChar übergeben, in der dann ein String zurückgegeben wird. Das MSDN sagt ausdrücklich, dass im Falle von UniCode-Verwendung dieser Funktion ebenso ein PAnsiChar verwendet werden soll, und man den danach typecasten soll(*). Einen anderen Parameter als einen PAnsiChar akteptiert die Funktion auch gar nicht. So weit, so gut.

Nun rufe ich die Funktion auf:

[...]
var Name: AnsiString;
[...]
SetLength(Name, MAX_PATH);
Name[1] := #0;
GetCommandString(DWParam.Lo - CMD_ID_OFFSET, GCS_VERBW, NIL, PAnsiChar(Name), MAX_PATH);

Jetzt habe ich in "Name" (dem AnsiString) einen Unicode-String. Zu erkennen daran, dass der Debugger als Inhalt anzeigt: "F#0o#0o#0B#0a#0r#0"

Wie kann ich jetzt diesen AnsiString in einen normalen Delphi-(Unicode)String umwandeln, um ihn dann weiterzuverwenden? Ich verrenne mich gerade total - meine Versuche bisher ergaben alle einen String mit Inhalt 'F#0o#0o#0B#0a#0r#0' (er wird also nicht als Unicode interpretiert)

Danke für einen Denkanstoß, und Grüße,
KT

*) https://msdn.microsoft.com/de-de/library/windows/desktop/bb776094(v=vs.85).aspx
"Even though pszName is declared as an LPSTR, you must cast it to UINT_PTR and return a Unicode string if uFlags is set to either GCS_HELPTEXTW or GCS_VERBW."
Hans-Peter Diettrich
2018-02-06 22:15:43 UTC
Permalink
Post by k***@gmail.com
Hallo,
Ich stehe gerade auf'm Schlauch und sehe den Wald vor lauter Bäumen nicht mehr. Ich migriere ein D5-Projekt zu Delphi 10.2 Starter (Tokyo), zu Unicode.
In der ItemProp-Unit von Brad Stowers wird die Funktion GetCommandString (vom ContextMenu) verwendet. Hier wird der Funktion eine Variable vom Typ PAnsiChar übergeben, in der dann ein String zurückgegeben wird. Das MSDN sagt ausdrücklich, dass im Falle von UniCode-Verwendung dieser Funktion ebenso ein PAnsiChar verwendet werden soll, und man den danach typecasten soll(*). Einen anderen Parameter als einen PAnsiChar akteptiert die Funktion auch gar nicht. So weit, so gut.
[...]
var Name: AnsiString;
[...]
SetLength(Name, MAX_PATH);
Name[1] := #0;
GetCommandString(DWParam.Lo - CMD_ID_OFFSET, GCS_VERBW, NIL, PAnsiChar(Name), MAX_PATH);
Jetzt habe ich in "Name" (dem AnsiString) einen Unicode-String. Zu erkennen daran, dass der Debugger als Inhalt anzeigt: "F#0o#0o#0B#0a#0r#0"
Wie kann ich jetzt diesen AnsiString in einen normalen Delphi-(Unicode)String umwandeln, um ihn dann weiterzuverwenden?
Deine Beobachtung/Vermutung paßt nicht zur MS Beschreibung.

Ich würde GCS_VERBA verwenden, dann sollte immer ein Ansi String
geliefert werden.

Dann die Länge des zurückgegebenen C-Strings ermitteln (die wäre in
Deinem Fall 0!?), und Name auf diese Länge setzen. Zuletzt Name an eine
Unicode Stringvariable zuweisen.

DoDi
k***@gmail.com
2018-02-07 07:38:48 UTC
Permalink
Post by Hans-Peter Diettrich
Ich würde GCS_VERBA verwenden, dann sollte immer ein Ansi String
geliefert werden.
Ja, mit VERBA klappt alles. Dann kriege ich einen normalen AnsiString. Aber ich will die Unicode-Variante (VERBW). Und dann steht im Rückgabestring auch Unicode, aber ich weiß nicht, wie ich den in einem Delphi-(Wide)String umwandeln kann.
Post by Hans-Peter Diettrich
Dann die Länge des zurückgegebenen C-Strings ermitteln (die wäre in
Deinem Fall 0!?), und Name auf diese Länge setzen. Zuletzt Name an eine
Unicode Stringvariable zuweisen.
Genau das hatte ich versucht: dann kommt das o.g. Ergebnis raus.

Na, ich werde noch ein wenig experimentieren.

Danke und ciao
KT
Hans-Peter Diettrich
2018-02-07 13:48:54 UTC
Permalink
Post by k***@gmail.com
Post by Hans-Peter Diettrich
Ich würde GCS_VERBA verwenden, dann sollte immer ein Ansi String
geliefert werden.
Ja, mit VERBA klappt alles. Dann kriege ich einen normalen AnsiString. Aber ich will die Unicode-Variante (VERBW). Und dann steht im Rückgabestring auch Unicode, aber ich weiß nicht, wie ich den in einem Delphi-(Wide)String umwandeln kann.
Solange das erste Zeichen in Name #0 bleibt, hat der Aufruf nicht
funktioniert, bzw. nur einen leeren String geliefert. Rückgabewert testen!

DoDi
k***@gmail.com
2018-02-07 17:47:20 UTC
Permalink
Post by Hans-Peter Diettrich
Solange das erste Zeichen in Name #0 bleibt, hat der Aufruf nicht
funktioniert, bzw. nur einen leeren String geliefert. Rückgabewert testen!
Bei Nutzung von VERBA (Ansi-Variante) bekomme ich in "Name" einen normalen String (8-Bit), z.B.

'Explorer'#0

Bei der Unicode-Variante (VERBW) steht im Rückgabestring

'E'#0'x'#0'p'#0'l'#0'o'#0'r'#0'e'#0'r'#0#0#0

Ciao
KT
Hans-Peter Diettrich
2018-02-07 22:46:57 UTC
Permalink
Post by k***@gmail.com
Post by Hans-Peter Diettrich
Solange das erste Zeichen in Name #0 bleibt, hat der Aufruf nicht
funktioniert, bzw. nur einen leeren String geliefert. Rückgabewert testen!
Bei Nutzung von VERBA (Ansi-Variante) bekomme ich in "Name" einen normalen String (8-Bit), z.B.
'Explorer'#0
Bei der Unicode-Variante (VERBW) steht im Rückgabestring
'E'#0'x'#0'p'#0'l'#0'o'#0'r'#0'e'#0'r'#0#0#0
Dann ändere doch Name in WideString, dann muß nichts mehr konvertiert
werden.

DoDi
k***@gmail.com
2018-02-08 03:31:59 UTC
Permalink
Post by Hans-Peter Diettrich
Dann ändere doch Name in WideString, dann muß nichts mehr konvertiert
werden.
Danke, hab jetzt nach vielem Probieren die Lösung gefunden:

var Name: WideString;
MeinZielString: string; // UnicodeString
[...]
SetLength(Name, MAX_PATH);
CM.GetCommandString(DWParam.Lo - CMD_ID_OFFSET, GCS_VERBW, NIL, PAnsiChar(Name), MAX_PATH);
SetLength(Name, StrLen(PWideChar(Name)));
MeinZielString := string(Name);

Danke an alle.

Ciao
KT
Hans-Peter Diettrich
2018-02-08 10:00:15 UTC
Permalink
Post by k***@gmail.com
Post by Hans-Peter Diettrich
Dann ändere doch Name in WideString, dann muß nichts mehr konvertiert
werden.
var Name: WideString;
MeinZielString: string; // UnicodeString
[...]
SetLength(Name, MAX_PATH);
CM.GetCommandString(DWParam.Lo - CMD_ID_OFFSET, GCS_VERBW, NIL, PAnsiChar(Name), MAX_PATH);
SetLength(Name, StrLen(PWideChar(Name)));
MeinZielString := string(Name);
Ich würde noch ausprobieren, ob die beiden letzten Typecasts nicht
weggelassen werden können. In C sind Typecasts oft notwendig und ein
Quell beliebigen Ärgers, in Pascal sind sie meist überflüssig und können
bei falscher Anwendung ebenfalls Ärger bereiten.

DoDi

Gerd Thieme
2018-02-07 14:15:19 UTC
Permalink
Post by k***@gmail.com
Ja, mit VERBA klappt alles. Dann kriege ich einen normalen AnsiString.
Aber ich will die Unicode-Variante (VERBW). Und dann steht im
Rückgabestring auch Unicode, aber ich weiß nicht, wie ich den in
einem Delphi-(Wide)String umwandeln kann.
Was spricht dagegen, die Zielvariable Name nicht als AnsiString, sondern
gleich korrekt als WideString zu deklarieren?

Dann sollte es keine Notwendigkeit für eine Konvertierung mehr geben.

Gerd
--
Um seine Kinder braucht sich heutzutage niemand zu sorgen. Wenn sie zu
nichts taugen, können sie noch immer in die Politik gehen. (Montaigne)
Gerd Thieme
2018-02-07 14:19:50 UTC
Permalink
Post by k***@gmail.com
Ja, mit VERBA klappt alles. Dann kriege ich einen normalen AnsiString.
Aber ich will die Unicode-Variante (VERBW). Und dann steht im
Rückgabestring auch Unicode, aber ich weiß nicht, wie ich den in
einem Delphi-(Wide)String umwandeln kann.
Was spricht dagegen, die Zielvariable Name nicht als AnsiString, sondern
gleich korrekt als WideString zu deklarieren?

Dann sollte es keine Notwendigkeit für eine Konvertierung mehr geben.

[Supersedes: Folgenden Hinweis ergänzt]

Gegebenenfalls muß der Pseudo-Typecast zu PAnsiChar durch einen
richtigen Typecast zu Pointer ersetzt werden. Das ist ohnehin
effizienter.

Gerd
--
Um seine Kinder braucht sich heutzutage niemand zu sorgen. Wenn sie zu
nichts taugen, können sie noch immer in die Politik gehen. (Montaigne)
Soeren Muehlbauer
2018-02-07 09:24:00 UTC
Permalink
Hi,


var Name: String;
[...]
SetLength(Name, MAX_PATH);
Name[1] := #0;
GetCommandString(DWParam.Lo - CMD_ID_OFFSET, GCS_VERBW, NIL,
PWideChar(Name), MAX_PATH);

HTH, Sören
k***@gmail.com
2018-02-07 17:40:12 UTC
Permalink
Post by Soeren Muehlbauer
var Name: String;
[...]
SetLength(Name, MAX_PATH);
Name[1] := #0;
GetCommandString(DWParam.Lo - CMD_ID_OFFSET, GCS_VERBW, NIL,
PWideChar(Name), MAX_PATH);
Ja, wenn's nur so einfach wäre :-) (das hatte ich auch schon probiertr)

[dcc32 Error] E2010 Incompatible types: 'PAnsiChar' and 'PWideChar'

Ciao
KT
Loading...