2008-11-12 8 views
17

Je suis en train de convertir mes applications en Delphi 2009 et j'ai été confronté à un problème intrigant avec certains appels qui ont besoin de convertir une chaîne (wide) en AnsiString.Convertir une chaîne en PAnsiChar en Delphi 2009

Voici un exemple pour illustrer la question que je vais avoir:

var 
    s: PAnsiChar; 

... 

s := PAnsiChar(Application.ExeName); 

Avec Delphi 2007 et les versions précédentes, s: = PChar (Application.ExeName) retournera le chemin exe application. Avec Delphi 2009, s: = PAnsiChar (Application.ExeName) renvoie uniquement 'E'. Je suppose que c'est parce que je convertis une chaîne unicode en une chaîne ansi, mais comment puis-je la convertir pour que PAnsiChar obtienne la chaîne complète?

Répondre

25

Je n'ai pas Delphi 2009 ici, donc je ne peux pas le vérifier. Mais peut-être que vous devez essayer:

s := PAnsiChar(AnsiString(Application.ExeName)); 

Comme Gabr déjà souligné, ce n'est pas une très bonne pratique, et vous ne l'utilisez si vous êtes sûr à 100%. La chaîne contient uniquement les caractères qui ont un mappage direct vers la plage ANSI.

C'est pourquoi vous devriez recevoir un avertissement parce que vous convertissez Unicode en ANSI.

+0

Vous ne devriez pas parce qu'il est une conversion explicite. Et, oui, ça devrait marcher. – gabr

+0

Je sais, mais la conversion en PAnsiChar est également un peu discutable. –

+1

Cela fonctionne au prix de la conversion explicite. Il y a t'il d'autres solutions? La conversion en PAnsiChar est expliquée dans ma réponse ci-dessous. – smartins

0

WideCharToMultiByte pourrait vous aider.

+0

WideCharToMultiByte est utilisé en interne dans certaines versions de Delphi –

1

La conversion explicite de Gamecat fonctionne. J'explique le problème plus en détail ci-dessous afin que peut-être quelqu'un peut pointer vers une meilleure solution.

J'utilise la fonction suivante pour récupérer la date de compilation de l'application:

function LinkerTimeStamp(const FileName: string): TDateTime; 
var 
    LI: TLoadedImage; 
begin 
    {$IFDEF UNICODE} 
    Win32Check(MapAndLoad(PAnsiChar(AnsiString(FileName)), nil, @LI, False, True)); 
    {$ELSE} 
    Win32Check(MapAndLoad(PChar(FileName), nil, @LI, False, True)); 
    {$ENDIF} 
    Result := LI.FileHeader.FileHeader.TimeDateStamp/SecsPerDay + UnixDateDelta; 
    UnMapAndLoad(@LI); 
end; 

MapAndLoad nécessite un PAnsiChar pour le paramètre ImageName donc je dois convertir la chaîne unicode. Existe-t-il une autre alternative pour convertir explicitement en AnsiString en premier?

+0

Existe-t-il une version Unicode de MapAndLoad? –

+0

Non, je ne pense pas qu'il existe une version Unicode. L'unité Imagehlp de CodeGear déclare MapAndLoad en tant que LPSTR qui correspond à PAnsiChar. Et aucune mention sur msdn à propos d'une version Unicode. – smartins

+2

Vous devriez probablement ajouter un commentaire sur ce que vous avez changé pour la compatibilité Unicode, et supprimer complètement le IFDEF - PAnsiChar et AnsiString sont déjà disponibles au moins dans Delphi 4, et les typecasts ne font pas de mal dans les programmes Ansi. Le plus simple le code le mieux à mon humble avis. – mghie

1

J'ai eu exactement le même problème. Le PAnsiChar pointe uniquement vers le premier caractère. J'ai écrit la fonction suivante pour gérer l'ancienne fonctionnalité.

// This function converts a string to a PAnsiChar 
// If the output is not the same, an exception is raised 
// Author: [email protected] 

function StringToPAnsiChar(stringVar : string) : PAnsiChar; 
Var 
    AnsString : AnsiString; 
    InternalError : Boolean; 
begin 
    InternalError := false; 
    Result := ''; 
    try 
    if stringVar <> '' Then 
    begin 
     AnsString := AnsiString(StringVar); 
     Result := PAnsiChar(PAnsiString(AnsString)); 
    end; 
    Except 
    InternalError := true; 
    end; 
    if InternalError or (String(Result) <> stringVar) then 
    begin 
    Raise Exception.Create('Conversion from string to PAnsiChar failed!'); 
    end; 
end; 
+0

'PAnsiChar (AnsiString (stringVar)) 'est tout ce dont vous avez besoin. –

+3

Cela ne posera-t-il pas un problème avec AnsString étant une variable locale et donc Result pointant vers cette variable qui ne sera plus disponible après la sortie de la fonction? En d'autres termes, une violation d'accès dans l'attente? – dummzeuch

-1

Je pense que vous êtes un peu éteint. Chaque fonction de l'API Win32 a une contrepartie unicode, si elle attend une chaîne. Essayez MapAndLoadW au lieu de MapAndLoad ...

+0

Il n'y a pas de MapAndLoadW. C'était la première chose que je regardais. Toutes les API Win32 n'ont pas leurs homologues Unicode, la plupart le font mais certaines ne ressemblent pas à celles-ci. – smartins

3

Au lieu d'utiliser le type String, utilisez RawByteString:

s: RawByteString; 

s := LoadSomeRegularString(usually a string type); 

PAnsiChar(s) <<< all fine. 
+0

Non, ne faites pas ça. C'est un abus total de 'RawByteString'. Au lieu de cela, lisez la documentation pour 'RawByteString' et déterminez ce à quoi il est vraiment destiné. –

Questions connexes