2008-11-12 11 views
17

Konwertuję moje aplikacje na Delphi 2009 i napotkałem intrygujący problem z niektórymi wywołaniami, które muszą przekonwertować ciąg (szeroki) na AnsiString.Konwertuj ciąg znaków na PAnsiChar w Delphi 2009

Oto przykład wykazać problem mam:

var 
    s: PAnsiChar; 

... 

s := PAnsiChar(Application.ExeName); 

z Delphi 2007 i wcześniejszych wersjach, S: = PChar (Application.ExeName) zwróci ścieżkę exe aplikacji.

z Delphi 2009, s: = PAnsiChar (Application.ExeName) zwraca tylko "E".

Zgaduję, że to dlatego, że konwertuję ciąg znaków Unicode na ciągi ansi, ale w jaki sposób mogę go przekonwertować tak, aby PAnsiChar otrzymał pełny ciąg znaków?

Odpowiedz

25

Nie mam tutaj Delphi 2009, więc nie mogę tego sprawdzić. Ale może trzeba spróbować:

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

Jak Gabr już wspomniano, nie jest to bardzo dobra praktyka, i będzie go używać tylko wtedy, gdy jesteś w 100% pewien. Łańcuch zawiera tylko znaki, które mają bezpośrednie odwzorowanie na zakres ANSI.

Dlatego powinieneś otrzymać ostrzeżenie, ponieważ konwertujesz Unicode na ANSI.

+0

nie powinien, ponieważ jest to jednoznaczne przekształcenie. I, tak, to powinno działać. – gabr

+0

Wiem, ale konwersja do PAnsiChar jest również nieco wątpliwa. –

+1

To działa kosztem jawnej konwersji. Czy jest jakaś inna alternatywa? Konwersja do PAnsiChar została wyjaśniona w mojej odpowiedzi poniżej. – smartins

1

Działa wyraźna zamiana Gamecat. Poniżej wyjaśniam problem, aby być może ktoś wskazał lepsze rozwiązanie.

używam następującą funkcję aby pobrać datę kompilacji aplikacji:

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 wymaga PAnsiChar dla imageName Parametr więc trzeba przekonwertować ciąg Unicode. Czy jest jakaś inna alternatywa, aby najpierw przekonwertować na AnsiString?

+0

Czy nie ma wersji MapAndLoad w wersji Unicode? –

+0

Nie, nie sądzę, że istnieje wersja Unicode. Jednostka CodeGear Imagehlp deklaruje MapAndLoad jako LPSTR, która mapuje do PAnsiChar. I nie wspomina się o msdn na temat wersji Unicode. – smartins

+2

Powinieneś prawdopodobnie dodać komentarz, co zmieniłeś ze względu na kompatybilność z Unicode, i całkowicie usunąć IFDEF - PAnsiChar i AnsiString są już dostępne przynajmniej w Delphi 4, a typecasts nie działają w programach Ansi. Im prostszy kod, tym lepiej IMHO. – mghie

1

Miałem dokładnie ten sam problem. PAnsiChar wskazuje tylko na pierwszy znak. Napisałem następującą funkcję do obsługi starej funkcjonalności.

// 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)) 'to wszystko, czego potrzebujesz. –

+3

Czy to nie będzie miało problemu z tym, że AnsString jest zmienną lokalną i dlatego Wynik wskazuje na tę zmienną, która nie będzie już dostępna po wyjściu funkcji? Innymi słowy, naruszenie dostępu w oczekiwaniu? – dummzeuch

-1

Myślę, że jesteś trochę wolny. Każda funkcja Win32 API ma odpowiednik w standardzie Unicode, jeśli oczekuje ciąg znaków. Spróbuj MapAndLoadW zamiast MapAndLoad ...

+0

Brak mapy MapAndLoadW. To była pierwsza rzecz, na którą patrzyłem. Nie wszystkie interfejsy API Win32 mają odpowiedniki w standardzie Unicode, ale większość z nich nie. – smartins

3

Zamiast typ String, użyj RawByteString:

s: RawByteString; 

s := LoadSomeRegularString(usually a string type); 

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

Nie, nie rób tego. Jest to całkowite nadużycie 'RawByteString'. Zamiast tego przeczytaj dokumentację dla 'RawByteString' i ustal, do czego jest on przeznaczony. –