2008-11-12 22 views
17

Estoy convirtiendo mis aplicaciones a Delphi 2009 y enfrenté un problema intrigante con algunas llamadas que necesitan convertir una cadena (ancha) a AnsiString.Convertir cadena a PAnsiChar en Delphi 2009

He aquí un ejemplo para demostrar el problema que estoy teniendo:

var 
    s: PAnsiChar; 

... 

s := PAnsiChar(Application.ExeName); 

Con Delphi 2007 y versiones anteriores, s: = PChar (Application.ExeName) devolvería la ruta de aplicación exe.

con Delphi 2009, s: = PAnsiChar (Application.ExeName) devuelve solo 'E'.

Supongo que es porque estoy convirtiendo una cadena Unicode en una cadena ansi, pero ¿cómo puedo convertirla para que un PAnsiChar obtenga la cadena completa?

Respuesta

25

No tengo Delphi 2009 aquí, así que no puedo verificarlo. Pero tal vez usted tiene que tratar:

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

Como ya se señaló Gabr, esto no es una práctica muy buena, y sólo se va a usar si está 100% seguro. La cadena solo contiene caracteres que tienen una asignación directa al rango ANSI.

Es por eso que debería recibir una advertencia porque está convirtiendo Unicode en ANSI.

+0

No debería, porque se trata de una conversión explícita. Y, sí, que debería funcionar. – gabr

+0

lo sé, pero la conversión a PAnsiChar también es un poco cuestionable. –

+1

Funciona a expensas de la conversión explícita. ¿Hay otra alternativa? La conversión a PAnsiChar se explica en mi respuesta a continuación. – smartins

0

WideCharToMultiByte podría ayudarlo. las obras de conversión explícita

+0

WideCharToMultiByte se usa internamente en algunos modelos de Delphi –

1

Gamecat. Estoy explicando el problema con más detalle a continuación para que tal vez alguien pueda señalar una mejor solución.

estoy usando la siguiente función para recuperar la fecha de compilación de aplicaciones:

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 requiere un PAnsiChar para el parámetro ImageName así que necesito para convertir la cadena Unicode. ¿Hay alguna otra alternativa para convertir explícitamente a AnsiString primero?

+0

¿No hay una versión Unicode de MapAndLoad? –

+0

No, no creo que haya una versión Unicode. La unidad CodeGear Imagehlp declara MapAndLoad como LPSTR que se asigna a PAnsiChar. Y ninguna mención en msdn sobre una versión Unicode. – smartins

+2

Probablemente deberías agregar un comentario de lo que cambiaste por la compatibilidad con Unicode, y eliminar el IFDEF por completo: PAnsiChar y AnsiString ya están disponibles al menos en Delphi 4, y las versiones no duelen en los programas de Ansi. Cuanto más simple sea el código, mejor en mi humilde opinión. – mghie

1

que tenían el mismo problema. El PAnsiChar solo apunta al primer caracter. Escribí la siguiente función para manejar la funcionalidad anterior.

// 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)) 'es todo lo que necesita. –

+3

¿No tendrá eso problema con que AnsString sea una variable local y, por lo tanto, el resultado apunte a esa variable que ya no estará disponible después de que la función finalice? En otras palabras, ¿una violación de acceso en la espera? – dummzeuch

-1

Creo que estás un poco apagado. función de la API de Win32 Cada tiene una contraparte Unicode, si se está a la espera de una cadena. Trate MapAndLoadW en lugar de MapAndLoad ...

+0

No hay MapAndLoadW. Fue lo primero que miré. No todas las API de Win32 tienen contrapartes de Unicode, la mayoría lo hace, pero algunas como esta no. – smartins

3

En lugar de utilizar el tipo String, utilice RawByteString:

s: RawByteString; 

s := LoadSomeRegularString(usually a string type); 

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

No, no hagas eso. Eso es un abuso total de 'RawByteString'. En lugar de hacer esto, lea la documentación de 'RawByteString' y averigüe para qué está realmente destinado. –