Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ? (https://www.delphipraxis.net/194272-pchar-pansichar-pwidechar-integer-lparam.html)

Glados 4. Nov 2017 17:36

PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
In einem anderen Thema wurde darüber diskutiert, ob man lieber LPARAM() oder Integer() nutzt als letzten Parameter bei SendMessage.
Es wurde aber angedeutet, dass LPARAM richtig sei.

Ich frage mich jetzt aber: was ist wirklich richtig? Herr Puff (Moderator hier im Forum) hat damals selber Integer() genutzt.
http://www.delphipraxis.net/110825-f...n-dateien.html

Außerdem: PChar, PAnsiChar, PWideChar? Was wann?
Im oben genannten beispiel steht
Delphi-Quellcode:
Integer(PChar(
. Partname ist ein string. Ist das heute noch richtig (Delphi 10 Starter)

Dazu lese ich im Netz
Zitat:

Hinweis: PChar ist unsicher, wenn er in Kombination mit normalen string-Werten verwendet wird. PChar unterliegt nicht der Referenzzählung und wird beim Zuweisen nicht kopiert ("Copy-On-Written-Semantik"). Dies kann zur Beschädigung der string-Werte oder zu Speicherlecks führen.
Implizieren die damit, dass man PWideChar nehmen soll?

EWeiss 4. Nov 2017 17:44

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Lese doch meinen vorherigen Post.
LPARAM ist Integer unter 32BIT warum jetzt dafür einen neuen Thread aufmachen?

Delphi-Quellcode:
LPARAM = INT_PTR;
INT_PTR = Integer;
PChar wird automatisch nach PWideChar gekastet kann aber nicht sagen ab welcher Delphi Version.

Ich gehe immer danach wenn keine Warnung oder Fehler seitens des Compiler kommt dann ist es schon richtig.

gruss

Zacherl 4. Nov 2017 17:48

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zu
Delphi-Quellcode:
LPARAM
ist alles gesagt. Im Grunde IMMER den korrekten Typen aus dem Funktionsprototyp verwenden, dann ist man auf der sicheren Seite.

Delphi-Quellcode:
PChar = PWideChar
bei Unicode Delphi Versionen und
Delphi-Quellcode:
PChar = PAnsiChar
bei älteren nicht-Unicode Delphi Versionen. Referenzzählung hast du hier in keinem Falle.

Zitat:

Zitat von Glados (Beitrag 1385157)
Implizieren die damit, dass man PWideChar nehmen soll?

Eher, dass du
Delphi-Quellcode:
String
verwenden sollst.

Glados 4. Nov 2017 17:48

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

PChar wird automatisch nach PWideChar
Heißt das ich kann ohne Probleme alle PChar durch PWideChar ersetzen?

Zitat:

PChar = PWideChar bei Unicode Delphi Versionen und PChar = PAnsiChar bei älteren nicht-Unicode Delphi Versionen.
Diese Information war gut.
Gilt das für alles wo Wide und Ansi drin steht?

Zitat:

Referenzzählung hast du hier in keinem Falle.
Kenne ich nicht, brauche ich nicht :stupid:

EWeiss 4. Nov 2017 17:51

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Zitat von Glados (Beitrag 1385160)
Zitat:

PChar wird automatisch nach PWideChar
Heißt das ich kann ohne Probleme alle PChar durch PWideChar ersetzen?

Zitat:

PChar = PWideChar bei Unicode Delphi Versionen und PChar = PAnsiChar bei älteren nicht-Unicode Delphi Versionen.
Diese Information war gut.
Gilt das für alles wo Wide und Ansi drin steht?

Zitat:

Referenzzählung hast du hier in keinem Falle.
Kenne ich nicht, brauche ich nicht :stupid:

Das macht Delphi selbst der Einfachheit halber.
Damit du wenn du portierst das nicht alles von Hand selbst erledigen musst.

Hatte ich doch geschrieben.

Zitat:

Eher, dass du String verwenden sollst.
Ist mir neu den viele Funktionen erwarten nun mal PWideChar und nicht string.


gruss

Zacherl 4. Nov 2017 17:52

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Zitat von Glados (Beitrag 1385160)
Zitat:

PChar wird automatisch nach PWideChar
Heißt das ich kann ohne Probleme alle PChar durch PWideChar ersetzen?

Wenn du sicher bist, dass dein Code nie auf einer Ansi-Version von Delphi kompiliert werden wird, ja. Würde die explizite Verwendung von
Delphi-Quellcode:
PWideChar
bzw.
Delphi-Quellcode:
PAnsiChar
aber tatsächlich nur dann empfehlen, wenn du eine Funktion oder API hast, die ebenfalls diesen expliziten Typen erwartet.

Delphi definiert bei WinAPIs auch in der Regel z.b.
Delphi-Quellcode:
MessageBoxA
,
Delphi-Quellcode:
MessageBoxW
und dann einmal noch nur
Delphi-Quellcode:
MessageBox
, welches dann auf eine der beiden Varianten verweist. Dadurch brauchst du dir über A/W keine Gedanken machen und einfach
Delphi-Quellcode:
MessageBox(PChar(), ...)
aufrufen. Willst du in irgendeinem Falle mal eine explizite Version, dann solltest du auch den Typen in die explizite Form casten:
Delphi-Quellcode:
MessageBoxA(PAnsiChar(), ...)
.

Glados 4. Nov 2017 17:55

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Wenn du sicher bist, dass dein Code nie auf einer Ansi-Version von Delphi kompiliert werden wird, ja
Warum sollte man eine 10 jahre alte Delphi-Version verwenden?

Ich hab hier zum Beispiel
Delphi-Quellcode:
:= GetFileAttributes(PWideChar(
.
Erwartet wird hier tatsächlich Winapi.Windows.LPCWSTR. Hier besser als auf LPCWSTR casten?

himitsu 4. Nov 2017 19:51

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Warum sollte man eine 10 jahre alte Delphi-Version verwenden?
Weil es nicht nur Delphi gibt?

z.B. FreePascal und Lazarus (die bekannteste IDE und GUI-Framework dafür)
Da hat man sich zu großen Teilen für UTF-8 entschieden, als man auf Unicode umstellte, während Delphi sich an der WinAPI orientiert, also UTF-16 (seit WinXP) und UCS-2 (Win2K).

Zitat:

Zitat von Glados (Beitrag 1385154)
Habe selbe Zeile auch schon mit DWORD gesehen.
Hier wird u.a. auch Integer verwendet http://www.cryer.co.uk/brian/delphi/...eforfolder.htm

DWORD ist noch falscher, als Integer.

Die Parameter von SendMessage sind Systemabhängig, also unter 64 Bit sind sie ebenfalls 64 Bit.

DWORD ist immer nur 4 Byte.
Integer/Cardinal waren mal Systemtypen > in Windows 3.1 16 Bit waren sie ebenfalls 16 Bit, aber bei der Entwiclung zu 64 Bit hatten sich die großen Entscheider entschiden den Integer einzufrieren und einen neuen Typ zu erfinden. In Delphi nennen sie sich Delphi-Referenz durchsuchenNativeInt und Delphi-Referenz durchsuchenNativeUInt.

Vergleichbar Char, PChar und String, welche sich anpassen.
AnsiString, AnsiChar PAnsiChar usw. sind immer fest definiert.

Passend zu diesen Typen gibt es auch sich selbt anpassende Funktionen.
z.B. CreateFile (PChar) und CreateFileA (PAnsiChar) oder CreateFileW (PWideChar).

Vorallem in der WinAPI hat eine API-Funktion auch genau eine Parameterdefinition, je Systemkonfiguration (ANSI/Unicode + 32/64 Bit).
Es gibt die beiden ANSI- und Unicode-Versionen und einen Alias, der auf das aktuell hauptsächlich unterstützte System verweist.


Also erstmal kommt die Entscheidung ob der geschriebene Code statisch oder dynamisch ist.
> ist er immer nur ANSI oder Unicode (bzw. 32 oder 64 Bit)
> oder passt er sich ans System an

Dementsprechend muß man dann auch die passenden Typen und Funktionen verwenden (statisch oder dynamisch).
Bei der Vermischung von statisch und dynamisch kommt es zu problemen, wenn das System sich ändert, da sich dann ein Teil ans system anpasst und der Andere bleibt unverändert.

Glados 4. Nov 2017 19:57

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Statisch? Dynamisch? Jetzt bin ich voll hinterm Berg. Ich bin ein ganz normaler Noob der Delphi privat nutzt.

Habe eben einfach alle PChar durch PWideChar ausgetauscht. Das war nämlich auch was, was die Funktionen alle erwartet haben.
PChar ist wie ich verstanden habe zwar auch PWideChar, aber ich nehme lieber PWideChar da ich eh nicht auf ein älteres Delphi zurück gehe.

EWeiss 4. Nov 2017 20:02

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

aber ich nehme lieber PWideChar da ich eh nicht auf ein älteres Delphi zurück gehe.
Da machste nix falsch.


gruss

p80286 4. Nov 2017 20:43

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Nicht daß es zu Mißverständnissen kommt. Wenn Du einen Pwidechar übergibst, der auf einen Ansistring zeigt, dann ist das formal durchaus korrekt, aber der Inhalt des Strings wird höchstwahrscheinlich falsch interpretiert.

Gruß
K-H

Glados 4. Nov 2017 20:58

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Ich definiere grundsätzlich
Delphi-Quellcode:
string
.

DeddyH 4. Nov 2017 21:04

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
AnsiString oder UnicodeString?

Glados 4. Nov 2017 21:05

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Ehrlich gesagt.... weiß ich nicht. Einfach nur
Delphi-Quellcode:
string
:thumb:
Aber ich nehme an es ist automatisch Unicode.

DeddyH 4. Nov 2017 21:08

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Ab Delphi 2009 schon. Worauf ich hinauswollte: wenn man einen PChar auf einen String zeigen lassen möchte, dann sollte man das auch so schreiben und nicht einerseits den Typalias benutzen und andererseits wieder nicht.
Delphi-Quellcode:
var
  Dings: string;
...
  ApiFunc(PChar(Dings)); //immer richtig
  ApiFunc(PWideChar(Dings)); //erst ab Delphi 2009 richtig
  ApiFunc(PAnsiChar(Dings)); //nur bis Delphi 2007 richtig

Glados 4. Nov 2017 21:14

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Delphi-Quellcode:
ApiFunc(PChar(Dings)); //immer richtig .. //erst ab Delphi 2009 richtig
Ich benutze ab sofort nur PWideChar denn ich habe keine Absicht zurück zu D2009 oder drunter zu gehen.

Warum sollte man auch.

DeddyH 4. Nov 2017 21:17

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Ab Delphi 2009 entspricht PChar PWideChar. Wieso also nicht konsequent die richtigen Typaliase verwenden? Da fehlt mir ehrlich gesagt das Verständnis.

Glados 4. Nov 2017 21:24

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Meinst du damit jetzt, dass man ab D2009 PChar oder PWideChar nutzen soll?

DeddyH 4. Nov 2017 21:43

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Nein, ich meine damit, dass man bei Verwendung von String auch PChar verwenden soll. Erst, wenn man das aus welchen Gründen auch immer nicht kann, sollte man die expliziten Typen nehmen (die Funktion gibt es nur in Ansi? AnsiString und PAnsiChar nehmen).

Dalai 4. Nov 2017 21:48

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Man sollte immer den für die Aufgabe passenden Typen benutzen, egal in welcher Version von Delphi oder FreePascal (bzw. jeder anderen Programmiersprache). Beispiel:
Delphi-Quellcode:
MessageBox(0, PChar(...));
MessageBoxA(0, PAnsiChar(...));
MessageBoxW(0, PWideChar(...));
Das funktioniert auf allen Delphi-Versionen, egal wie alt oder neu, wahrscheinlich auch mit FreePascal.

Warum nicht sowas wie
Delphi-Quellcode:
MessageBox(0, PWideChar(...));
, von dem du ja sagst, die IDE meint, der Parameter wäre PWideChar? Nun, bei einem aktuellen Delphi macht das keinen Unterschied, weil PChar nur ein Alias für PWideChar ist (und MessageBox ein Alias für MessageBoxW), d.h. der Compiler liest den Code als
Delphi-Quellcode:
MessageBoxW(0, PWideChar(...));
.

Aber sobald man denselben Code auf einem alten Delphi oder FreePascal benutzen will, kommen Warnungen wegen impliziter String-Umwandlung mit potentiellem Datenverlust. Warum? Weil MessageBox ein Alias ist, genau wie PChar. Der Compiler liest den Code daher als
Delphi-Quellcode:
MessageBoxA(0, PWideChar(...));
- Type mismatch. PAnsiChar, PWideChar sowie MessageBoxA und MessageBoxW sind keine Aliase sondern konkrete Typen.

Ist eigentlich gar nicht so schwer zu verstehen. Manchmal braucht man konkrete Typen wie PAnsiChar, PWideChar, in allen anderen Fällen sollte man die Aliase (PChar, String usw) benutzen, weil der Code dann ohne Anpassungen wiederverwendbar ist. Manchmal muss man bei Code nicht nur an sich selbst denken sondern auch Code weitergeben; da ist es sehr hilfreich, wenn dieser korrekt funktioniert und keine Warnungen produziert. Warnungen zu bearbeiten, macht nämlich viel Arbeit (ich bearbeite derzeit derartigen fremden Code...).

Grüße
Dalai

Glados 4. Nov 2017 22:01

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Nur woher soll ich dann den richtigen Typen kennen, wenn die IDE mir schon PWideChar anzeigt?

Beispiele

Delphi-Quellcode:
// #1
var
 pName: PWideChar;
begin
 pName := PWideChar('Test');
 CopyData.dwData := 0;
 CopyData.cbData := (StrLen(pName) + 1) * SizeOf(WideChar);
 CopyData.lpData := pName;
 SendMessage(hExistingInstance, WM_COPYDATA, 0, LPARAM(@CopyData));
end;

// #2
... := FindWindow(PWideChar('Test'));

// #3
... := GetFileAttributes(PWideChar('Test'));

Dalai 4. Nov 2017 22:14

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Zitat von Glados (Beitrag 1385193)
Nur woher soll ich dann den richtigen Typen kennen, wenn die IDE mir schon PWideChar anzeigt?

Ich sehe es so: Einfach immer PChar und String benutzen, bis der Compiler meckert. Manchmal weiß man es sogar vorher, dass (API-)Funktionen einen konkreten Typen wie PWideChar oder WideString erwarten, weil man eine Funktion bereits in der Vergangenheit benutzt hat.

Zitat:

Beispiele

Delphi-Quellcode:
// #1
var
 pName: PWideChar;
begin
 pName := PWideChar('Test');
 CopyData.dwData := 0;
 CopyData.cbData := (StrLen(pName) + 1) * SizeOf(WideChar);
 CopyData.lpData := pName;
 SendMessage(hExistingInstance, WM_COPYDATA, 0, LPARAM(@CopyData));
end;

// #2
... := FindWindow(PWideChar('Test'));

// #3
... := GetFileAttributes(PWideChar('Test'));

GetFileAttributes und FindWindow sind beides Aliase (für FindWindowA/W bzw. GetFileAttributesA/W). Daher sollte hier besser jeweils PChar benutzt werden. Bzgl. des SendMessage kommt es darauf an, was der Empfänger der Nachricht erwartet - das kann man nicht pauschal sagen. Anders ausgedrückt: erwartet der Empfänger einen Zeiger auf einen Ansi-String, ist die Verwendung von PWideChar mit Sicherheit falsch.

Grüße
Dalai

Glados 4. Nov 2017 22:15

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Ich sehe es so: Einfach immer PChar und String benutzen, bis der Compiler meckert.
Werde ich mir merken.

Dalai 4. Nov 2017 22:22

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Wobei "meckern" in dem Zusammenhang nicht nur bedeuten kann, dass der Code nicht kompiliert, sondern auch, dass der Compiler Warnungen bzgl. impliziter Stringumwandlung ausgibt. Also immer schön auf die Meldungen des Compilers achten, und versuchen, Warnungen zu verstehen und zu beheben.

Grüße
Dalai

Luckie 5. Nov 2017 03:30

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Zitat von Glados (Beitrag 1385157)
Ich frage mich jetzt aber: was ist wirklich richtig? Herr Puff (Moderator hier im Forum) hat damals selber Integer() genutzt.
http://www.delphipraxis.net/110825-f...n-dateien.html

Ach du scheiße. Wer gräb denn solche Jungendsünden aus? :shock: Das war noch zu 32-Bit Zeiten, da entsprach einem positiven Integer der LPARAM. Der Cast zu LPARAM wäre natürlich besser und sicherer gewesen.

HolgerX 5. Nov 2017 08:56

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Hmm...

Zitat:

Zitat von Glados (Beitrag 1385193)
Nur woher soll ich dann den richtigen Typen kennen, wenn die IDE mir schon PWideChar anzeigt?

Dann nimm doch direkt den direkten Aufruf und nicht den Alias:

(Auszug D6)

Delphi-Quellcode:
function FindWindow; external user32 name 'FindWindowA';
function FindWindowA; external user32 name 'FindWindowA';
function FindWindowW; external user32 name 'FindWindowW';
Somit kannst Du unter jedem Delphi

FindWindowA mit PAnsiChar
FindWindowW mit PWideChar

verwenden!

Kein Alias, keine Verwechslung und der Compiler meckert nur noch zurecht!

Unter D6 verwende ich impliziert die 'W'-Funktionen mit PWideChar und meine Funktionen geben WideString als Result, diese kann ich nun als WideString weiterverwenden (z.B. TNT-Controls) und bin damit auch bedingt UNICode tauglich und dass mit D6! ;)

Glados 5. Nov 2017 12:30

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Wer gräb denn solche Jungendsünden aus?
Ich :lol:

Zitat:

Dann nimm doch direkt den direkten Aufruf und nicht den Alias:
Muss ich mir heute mal angucken. Es sind vielleicht ein paar dutzend Winapi-Aufrufe die ich abändern muss.

Eine echt dumme Frage nur noch. Wenn ich den Alias verwende, verwendet Delphi dann in der heutigen Zeit ausnahmslos immer bei Übergabe von string die W-Variante?

himitsu 5. Nov 2017 13:36

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Zitat:

Zitat von Glados (Beitrag 1385193)
Nur woher soll ich dann den richtigen Typen kennen, wenn die IDE mir schon PWideChar anzeigt?

In die OH oder die Deklaration schauen? (Letzeres geht bei den Starter leider nicht)

Wie bereits gesagt, am Einfachsten immer String/PChar verwenden, da Delphi seine Deklarationen auch so schreibt.
Außer man weiß schon genau, dass hier feste Typen verwendet werden müssen.

Es gibt einige APIs, die es nur in einer Version (ANSI/Unicode) gibt.
Und auch Daten nach Extern (z.B. in Datei oder Stream zu einem anderen Programm) sollten besser immer statisch sein. (so lange nicht irgendwo das Format mit übergeben wird)
Wenn das eine Programm als ANSI compiliert wurde und das Andere als Unicode, würde es sonst Probleme geben. Das gilt auch für die Übergabe zwischen EXE und DLL.
Nur bei 32 und 64 Bit gibt es mit EXE und DLL keine Probleme, da Beide gleich sein müssen. (abgesehn von einem OutOfProcess-Server bei COM-DLLs)

Alias werden "leider" nicht angezeigt. Das wäre mal ein gutes Feature, aber nach dem Compilieren ist nur der "Ursprungstyp" und nicht der Alias bekannt, da der Alias beim Compilieren durch diesen Typen ersetzt wird.

Glados 5. Nov 2017 13:40

AW: PChar, PAnsiChar, PWideChar, Integer, LPARAM, ... ?
 
Mein Kopf raucht und ich verstehe nichts. Ich bleibe einfach bei den Alias-Aufrufen mit PChar, Ende.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:13 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz