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

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

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

var
  s: PAnsiChar;

...

s := PAnsiChar(Application.ExeName);

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

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

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


person smartins    schedule 12.11.2008    source источник


Ответы (6)


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

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

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

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

person Toon Krijthe    schedule 12.11.2008
comment
Вы не должны, потому что это явное преобразование. И да, это должно сработать. - person gabr; 12.11.2008
comment
Я знаю, но преобразование в PAnsiChar тоже немного сомнительно. - person Toon Krijthe; 12.11.2008
comment
Это работает за счет явного преобразования. Есть ли другая альтернатива? Преобразование в PAnsiChar объясняется в моем ответе ниже. - person smartins; 12.11.2008
comment
Проблема в том, что у вас всегда есть шанс потерять информацию. Возможно, лучше заменить PAnsiChar строкой. - person Toon Krijthe; 12.11.2008
comment
В XE5 эта проблема привела к тому, что у меня не выполнялись вызовы dll, включая shellexecute. простое приведение PAnsiChar (myStringVar) вызывало необнаруживаемые и невоспроизводимые ошибки, и я был разочарован, пока то же самое не произошло с внешней dll, и я пришел к этому решению. теперь работает нормально. Любой, у кого есть проблема с запуском оболочки, также должен это проверить. - person user30478; 07.01.2019

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

s: RawByteString;

s := LoadSomeRegularString(usually a string type);

PAnsiChar(s) <<< all fine.
person Meka    schedule 25.02.2010
comment
Нет, не делай этого. Это полное злоупотребление RawByteString. Вместо этого прочтите документацию для RawByteString и выясните, для чего он действительно предназначен. - person David Heffernan; 12.02.2015

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

person smartins    schedule 12.11.2008
comment
Нет, я не думаю, что есть версия Unicode. Модуль CodeGear Imagehlp объявляет MapAndLoad как LPSTR, который сопоставляется с PAnsiChar. И никаких упоминаний в msdn о версии Unicode. - person smartins; 12.11.2008
comment
Вероятно, вам следует добавить комментарий к тому, что вы изменили для совместимости с Unicode, и полностью удалить IFDEF - PAnsiChar и AnsiString уже доступны, по крайней мере, в Delphi 4, а приведение типов не повредит в программах Ansi. ИМХО, чем проще код, тем лучше. - person mghie; 13.11.2008
comment
Этот IFDEF совершенно бессмысленен. Просто напишите PAnsiChar(AnsiString(FileName)), который работает везде. Конечно, лучшее решение - найти альтернативу MapAndLoad, которая не была бы настолько убогой, чтобы требовать ввода ANSI. - person David Heffernan; 12.02.2015
comment
Лучшее решение, поскольку вы делаете это в исполняющем модуле, выглядит следующим образом: Result := PImageNtHeaders(HInstance + PImageDosHeader(HInstance)^._lfanew)^.FileHeader.TimeDateStamp / SecsPerDay + UnixDateDelta; - person David Heffernan; 12.02.2015

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

// 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;
person Community    schedule 05.03.2009
comment
PAnsiChar(AnsiString(stringVar)) - это все, что вам нужно. - person David Heffernan; 12.02.2015
comment
Разве у этого не возникнет проблемы с AnsString, являющимся локальной переменной и, следовательно, с результатом, указывающим на эту переменную, которая больше не будет доступна после выхода из функции? Другими словами, нарушение прав доступа в ожидании? - person dummzeuch; 28.04.2017

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

person Jamie    schedule 12.11.2008
comment
WideCharToMultiByte используется внутри некоторых типов Delphi. - person Daniel Rikowski; 31.12.2008

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

person Community    schedule 20.04.2009
comment
Нет MapAndLoadW. Это было первое, на что я посмотрел. Не все API-интерфейсы Win32 имеют аналоги в Юникоде, большинство из них имеют, но некоторые, подобные этому, нет. - person smartins; 10.02.2010