Преобразование строки в PAnsiChar в Delphi 2009

18

Я конвертирую свои приложения в Delphi 2009 и сталкиваюсь с интригующей проблемой с некоторыми вызовами, которым необходимо преобразовать строку (широко) в AnsiString.

Вот пример, демонстрирующий проблему:

var
  s: PAnsiChar;

...

s := PAnsiChar(Application.ExeName);

В Delphi 2007 и предыдущих версиях s: = PChar (Application.ExeName) вернет путь EXE-приложения.

с Delphi 2009, s: = PAnsiChar (Application.ExeName) возвращает только «E».

Я предполагаю, что это потому, что я конвертирую строку unicode в строку ansi, но как я могу ее преобразовать, чтобы PAnsiChar получил полную строку?

    
задан smartins 12.11.2008 в 13:14
источник

6 ответов

26

У меня нет Delphi 2009 здесь, поэтому я не могу его проверить. Но, возможно, вам стоит попробовать:

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

Как уже указывал gabr, это не очень хорошая практика, и вы будете использовать ее только в том случае, если вы на 100% уверены. Строка содержит только символы, которые имеют прямое сопоставление с диапазоном ANSI.

Вот почему вы должны получить предупреждение, потому что вы конвертируете Unicode в ANSI.

    
ответ дан Toon Krijthe 12.11.2008 в 13:19
источник
  • Вы не должны, потому что это явное преобразование. И да, это должно сработать. –  gabr 12.11.2008 в 13:40
  • Я знаю, но преобразование в PAnsiChar также немного сомнительно. –  Toon Krijthe 12.11.2008 в 13:49
  • Он работает за счет явного преобразования. Есть ли другая альтернатива? Преобразование в PAnsiChar объясняется в моем ответе ниже. –  smartins 12.11.2008 в 14:04
  • Проблема в том, что у вас всегда есть вероятность потери информации. Возможно, лучше изменить PAnsiChar для строки. –  Toon Krijthe 12.11.2008 в 14:11
4

Вместо использования типа String используйте RawByteString :

s: RawByteString;

s := LoadSomeRegularString(usually a string type);

PAnsiChar(s) <<< all fine.
    
ответ дан Meka 25.02.2010 в 21:20
источник
  • Нет, не делайте этого. Это полное злоупотребление RawByteString. Вместо этого прочитайте документацию для RawByteString и определите, для чего она предназначена. –  David Heffernan 12.02.2015 в 09:26
1

Работа с явным преобразованием Gamecat. Я объясняю проблему более подробно ниже, чтобы, возможно, кто-то мог указать на лучшее решение.

Я использую следующую функцию для получения даты компиляции приложения:

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 требует PAnsiChar для параметра ImageName, поэтому мне нужно преобразовать строку юникода. Есть ли другая альтернатива, чтобы сначала преобразовать в AnsiString?

    
ответ дан smartins 12.11.2008 в 14:10
источник
  • Нет ли Unicode-версии MapAndLoad? –  Toon Krijthe 12.11.2008 в 14:24
  • Нет, я не думаю, что есть версия Unicode. Модуль CodeGear Imagehlp объявляет MapAndLoad как LPSTR, который сопоставляется с PAnsiChar. И не упоминается о msdn о версии Unicode. –  smartins 12.11.2008 в 14:29
  • Вероятно, вы должны добавить комментарий, который вы изменили для совместимости с Unicode, и полностью удалить IFDEF - PAnsiChar и AnsiString уже доступны, по крайней мере, в Delphi 4, и приемы не пострадают в программах Ansi. Чем проще код, тем лучше ИМХО. –  mghie 13.11.2008 в 17:14
  • Этот IFDEF совершенно бессмыслен. Просто напишите PAnsiChar (AnsiString (FileName)), который работает повсюду. Разумеется, хотя лучшим решением является найти альтернативу MapAndLoad, которая не настолько хромает, чтобы требовать ввода ANSI. –  David Heffernan 12.02.2015 в 09:29
  • Лучшее решение, так как вы делаете это в исполняющем модуле, выглядит следующим образом: Результат: = PImageNtHeaders (HInstance + PImageDosHeader (HInstance) ^ ._ lfanew) ^. FileHeader.TimeDateStamp / SecsPerDay + UnixDateDelta; –  David Heffernan 12.02.2015 в 09:31
1

У меня была такая же проблема. % Co_de% указывает только на первый символ. Я написал следующую функцию для обработки старых функций.

// 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;
    
ответ дан Nogabel 05.03.2009 в 14:20
источник
  • PAnsiChar (AnsiString (stringVar)) - это все, что вам нужно. –  David Heffernan 12.02.2015 в 09:27
  • Не будет ли проблема с AnsString, являющейся локальной переменной, и поэтому Result указывает на эту переменную, которая больше не будет доступна после выхода функции? Другими словами, нарушение доступа в ожидании? –  dummzeuch 28.04.2017 в 11:26
0

WideCharToMultiByte может помочь вам.

    
ответ дан Jamie 12.11.2008 в 13:37
источник
  • WideCharToMultiByte используется внутренне в некоторых версиях Delphi –  Daniel Rikowski 30.12.2008 в 22:19
-1

Я думаю, что ты немного ушел. Каждая функция Win32 API имеет юникодную копию, если она ожидает строку. Попробуйте MapAndLoadW вместо MapAndLoad ...

    
ответ дан Usagi Yojimbo 20.04.2009 в 13:34
источник
  • Нет MapAndLoadW. Это было первое, на что я смотрел. Не все API-интерфейсы Win32 имеют юникодные копии, большинство из них делают это, но некоторые вроде этого этого не делают. –  smartins 10.02.2010 в 13:40