Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   PWideChar oder PAnsiChar (https://www.delphipraxis.net/195449-pwidechar-oder-pansichar.html)

norwegen60 1. Mär 2018 02:42

PWideChar oder PAnsiChar
 
Hallo zusammen,

meine Frage geht in eine ähnliche Richtung wie der Beitrag "String Kovertierung".

Ich bin dabei meine Warnungen bezüglich impliziten Stringkonvertierungen zu überarbeiten. Dabei bin ich auf folgendes Problem gestoßen:
Delphi-Quellcode:
const
  sDLL = 'Splash.dll';
 
var
   haDLL : Cardinal;

procedure TintSplash.Show(sTitel: string);
const
  sBef = 'Show';
var
  fShow: procedure(Titel: WideString); stdcall;

begin
  haDLL := GetModuleHandle(PWideChar(sDLL)); { prüfen ob DLL schon geladen }
  if haDLL = 0 then
    haDLL := LoadLibrary(PWideChar(sDLL)); { DLL dynamisch laden }

  if haDLL <> 0 then
  begin
    @fShow := GetProcAddress(haDLL, PWideChar(sBef));
    fShow(sTitel);
  end
Gehe ich mit dem Mauszeiger auf
Delphi-Quellcode:
GetProcAddress
bekomme ich als Hilfe
Delphi-Quellcode:
Windows.GetProcAddress(Cardinal,PAnsiChar)Method
.
Ändere ich die Zeile in
Delphi-Quellcode:
 @fShow := GetProcAddress(haDLL, sBef);
bekomme ich die Hilfe
Delphi-Quellcode:
Windows.GetProcAddress(Cardinal,PWideChar)Method
.
Warum wird bei expliziter Wandlung in PWideChar PAnsiChar angezeigt und bei direkter Übergabe des String PWideChar?
Muss ich in den drei Fällen oben überhaupt eine explizite Umwandlung vornehmen? In allen drei Fällen ist der übergebene Parameter eine const die automatisch als String deklariert ist.
Was wäre, wenn ich sDLL als String mit übergeben würde
Delphi-Quellcode:
TintSplash.Show(sDLL, sTitel: string);
.

Danke für eine Antwort
Gerd

Ghostwalker 1. Mär 2018 06:00

AW: PWideChar oder PAnsiChar
 
Da in den letzten Versionen von Delphi, der Typ STRING automatisch auf UNICODESTRING gesetzt wurde, werden demzufolge alle Konstanten auch automatisch Unicodestrings. Da Widestrings und Ansistrings andere Typen sind,
wird hier immer konvertiert (und damit auch eine entsprechende Warnung ausgegeben).

Lösung:

Benutz typisierte Konstanten und definier dabei den gewünschten String-Typ :)

Beispiel:

Delphi-Quellcode:
   const sDll : Widestring = 'Splash.dll';
   const sBuf : widestring = 'Show';

CCRDude 1. Mär 2018 06:22

AW: PWideChar oder PAnsiChar
 
Beispielhaft an einem Aufruf:
Delphi-Quellcode:
haDLL := LoadLibrary(PChar(sDLL)); // mit sDLL: string
haDLL := LoadLibraryA(PAnsiChar(sDLL)); // mit sDLL: AnsiString
haDLL := LoadLibraryW(PWideChar(sDLL)); // mit sDLL: WideString
Wenn Du eine API-Funktion aufrufst, schau unbedingt, welcher Typ erwartet wird! Von den meisten System-APIs, die Text erwarten, gibt es auch die expliziten *A und *W-Varianten; der Aufruf ohne zeigt bis auf in Uralt-Delphis auf *W, früher auf *A.

bepe 1. Mär 2018 06:25

AW: PWideChar oder PAnsiChar
 
Hi,

nicht direkt eine Antwort auf deine Frage aber...

Zu vielen/den meisten API Calls gibt es zwei Varianten: Ansi und Widestring. Zum Beispiel GetModuleHandleA und GetModuleHandleW. Du verwendest aber den Alias GetModuleHandle. Dann solltest du auch beim Datentyp einen Alias verwenden.

Delphi-Quellcode:
haDLL := GetModuleHandle(PWideChar(sDLL));
Das funktioniert wenn GetModuleHandle auf GetModuleHandleW verweist (Unicode Delphis). In älteren Versionen geht der verweis auf GetModuleHandleA und dann stimmt der Datentyp nicht mehr.

Delphi-Quellcode:
haDLL := GetModuleHandleW(PWideChar(sDLL)); // wenn du bewusst WideChar möchtest
haDLL := GetModuleHandleA(PAnsiChar(sDLL)); // wenn du bewusst AnsiChar möchtest

// meistens bessser:
haDLL := GetModuleHandle(PChar(sDLL)); // wenn der Typ egal ist

Trotz rotem Kasten, da ein zwei erklärende Worte mehr...

norwegen60 1. Mär 2018 06:59

AW: PWideChar oder PAnsiChar
 
Hallo zusammen,

Danke für die Antwort. Dann stimmt ja meine obiger Code. An die typisierten Konstanten hatte ich auch schon gedacht.
Drei Fragen sind aber noch offen:
  1. Gibt es irgendetwas was man beachten muss, wenn man PWidechar(sDLL) anwendet?
  2. Warum wird unter dem dem Mauszeiger bei
    Delphi-Quellcode:
    @fShow := GetProcAddress(haDLL, PWideChar(sBef));
    in der Hilfe
    Delphi-Quellcode:
    Windows.GetProcAddress(Cardinal,PAnsiChar)Method
    angezeigt obwohl es für GetProcAddress die A- und die W-Variante gibt?
  3. Bei der Zuweisung
    Delphi-Quellcode:
    sString := wWideString;
    oder
    Delphi-Quellcode:
    wWideString := sString;
    gibt es keine Kompiler-Warnung. Hier gehe ich also davon aus, dass diese absolut konfliktfrei verläuft. Korrekt?

Grüße
Gerd

TiGü 1. Mär 2018 08:55

AW: PWideChar oder PAnsiChar
 
Zitat:

Zitat von norwegen60 (Beitrag 1394893)
Hallo zusammen,

Danke für die Antwort. Dann stimmt ja meine obiger Code. An die typisierten Konstanten hatte ich auch schon gedacht.
Drei Fragen sind aber noch offen:
  1. Gibt es irgendetwas was man beachten muss, wenn man PWidechar(sDLL) anwendet?
  2. Warum wird unter dem dem Mauszeiger bei
    Delphi-Quellcode:
    @fShow := GetProcAddress(haDLL, PWideChar(sBef));
    in der Hilfe
    Delphi-Quellcode:
    Windows.GetProcAddress(Cardinal,PAnsiChar)Method
    angezeigt obwohl es für GetProcAddress die A- und die W-Variante gibt?
  3. Bei der Zuweisung
    Delphi-Quellcode:
    sString := wWideString;
    oder
    Delphi-Quellcode:
    wWideString := sString;
    gibt es keine Kompiler-Warnung. Hier gehe ich also davon aus, dass diese absolut konfliktfrei verläuft. Korrekt?

Grüße
Gerd

1. Nein.
2. Immer mit Strg+Linksklick zur eigentlichen Definition gucken und den Hint ignorieren.
3. Ja.

norwegen60 1. Mär 2018 12:13

AW: PWideChar oder PAnsiChar
 
Zitat:

Zitat von TiGü (Beitrag 1394908)
1. Nein.
2. Immer mit Strg+Linksklick zur eigentlichen Definition gucken und den Hint ignorieren.
3. Ja.

Das nenne ich mal eine eindeutige Antwort.
Linksklick brachte aber für mich auch nicht die Sicherheit, da der trotz PWideChar auf den ersten dieser beiden Implementationen gesprungen ist.
Delphi-Quellcode:
function GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; external kernel32 name 'GetProcAddress';
function GetProcAddress(hModule: HMODULE; lpProcName: LPCWSTR): FARPROC;
Aber jetzt bin ich sicher, dass meine Umstellung korrekt ist

Danke

Luckie 1. Mär 2018 14:23

AW: PWideChar oder PAnsiChar
 
Spätestens seit XP endet jeder API Aufruf bei der W-Version. Selbst wenn man explizit die A-Version aufruft, Windows leitet das intern an die W-Version weiter.

himitsu 1. Mär 2018 14:35

AW: PWideChar oder PAnsiChar
 
Win32API-Typname = Pascal/Delphi-Typename

LPCSTR = PAnsiChar
LPCWSTR = PWideChar

Zitat:

Leitet weiter
Joar, aber inkl. Typkonvertierung, also muß man bei der ANSI-API dennoch ANSI übergeben, auch wenn es letztendlich beim Unicode landet.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:14 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