【问题标题】:Unicode problems with Delphi 2009 / 2010 and windows API callsDelphi 2009 / 2010 和 windows API 调用的 Unicode 问题
【发布时间】:2009-09-14 10:41:59
【问题描述】:

您好,我一直在 Delphi 2006 中使用此功能,但现在使用 D2010 时会引发错误。 我认为这与切换到 Unicode 有关。

  Function TWinUtils.GetTempFile(Const Extension: STRING): STRING;
  Var
     Buffer: ARRAY [0 .. MAX_PATH] OF char;
  Begin
    Repeat
      GetTempPath(SizeOf(Buffer) - 1, Buffer);
      GetTempFileName(Buffer, '~~', 0, Buffer);
      Result := ChangeFileExt(Buffer, Extension);
    Until not FileExists(Result);
  End;

我应该怎么做才能让它工作?

编辑

当调用 ChangeFileExt 时,我得到一个“访问冲突”

【问题讨论】:

  • 您应该编辑您的问题以包含错误消息(一个好习惯 - 有意义,对吧?)
  • 请参阅以下链接以获取对问题的讨论(几乎相同的代码)和更好的版本,该版本考虑了 API 文档中关于最大缓冲区大小的更多内容。 forums.embarcadero.com/thread.jspa?threadID=18246
  • 此链接不再有效。按线程 id 搜索的正确方法是什么?

标签: delphi delphi-2009 delphi-2010


【解决方案1】:

Windows.Pas

function GetTempFileName(lpPathName, lpPrefixString: PWideChar;
  uUnique: UINT; lpTempFileName: PWideChar): UINT; stdcall;

function GetTempPath(nBufferLength: DWORD; lpBuffer: PWideChar): DWORD; stdcall;

SysUtils.Pas

function ChangeFileExt(const FileName, Extension: string): string;

试试这个

  Function TWinUtils.GetTempFile(Const Extension: STRING): STRING;
  Var
     Buffer: ARRAY [0 .. MAX_PATH] OF WideChar;
  Begin
    Repeat
      GetTempPath(Length(Buffer), Buffer);
      GetTempFileName(Buffer, '~~', 0, Buffer);
      Result := ChangeFileExt(Buffer, Extension);
    Until not FileExists(Result);
  End;

或者这个

  Function GetTempFile(Const Extension: String): String;
  Var
     Buffer: String;
  Begin
      SetLength(Buffer,MAX_PATH);
    Repeat
      GetTempPath( MAX_PATH, PChar( Buffer) );
      GetTempFileName(PChar( Buffer), '~~', 0, PChar( Buffer));
      Result := ChangeFileExt(Buffer, Extension);
    Until not FileExists(Result);
  End;

对于 Delphi,Char 和 PChar 类型分别是 WideChar 和 PWideChar 类型。

如果您使用任何将数据返回到字符缓冲区的 Windows API,则需要将这些缓冲区重新声明为字节数组或 AnsiChar 数组。

如果您正在调用这些 Windows API 并在缓冲区中发送,如果在告诉 API 您的缓冲区有多长时一直使用 sizeof 函数。这些调用需要更改为 Length 函数,因为Windows Widechar API 需要字符数,而不是字节数

再见。

【讨论】:

  • 旧代码出现问题的原因是 GetTempPath() 中的 SizeOf(Buffer) - 1。字符数组的 SizeOf 与 2009 年之前 Delphi 的 Length 相同,因为 SizeOf(AnsiChar) = 1。对于 Delphi 2009 及更高版本,SizeOf(Char) = SizeOf(WideChar) = 2,所以代码询问 GetTempPath()用比它可以容纳的更多的字符填充缓冲区。
  • 我在“delphi 2010”中尝试了这两个选项,它们都工作正常。 ;)
  • 字符不是 Widechar!它是 UnicodeChar。略有不同。
  • gamecat in delphi 2010 help ms-help://embarcadero.rs2010/rad/Simple_Types.html "一般的字符类型是Char,相当于WideChar现在默认的字符串类型是UnicodeString "。
  • @Gamecat: D2009+ 中的Char 确实是WideChar 的别名。没有UnicodeChar 类型,而且从来没有。
【解决方案2】:

在 Delphi 2009 中,Char 是 unicode char。该函数可能需要一个 AnsiChar 数组。

刚刚检查过了。 GetTempFilename 和 GetTempPath 都需要 PWideString。

错误信息是什么?

【讨论】:

  • 你不应该说PWideChar吗? PWideString 完全是另外一回事。
【解决方案3】:

我建议总是,而且我的意思是总是,查看有关每个 API 函数对 dwSize 参数和/或返回值的确切期望的文档。

不幸的是,有很多不同的情况,所以仅仅说“所有字符串函数都需要/返回字符数”并不完全正确,可能会让读者陷入零星无效指针 AV 的噩梦。

  • 大多数 API 函数确实期望/返回字符数,但有些 不。
  • 有些计算终止空字符,有些不计算。
  • 传递 nil 指针与传递 nil 指针时,某些函数的行为会有所不同 非零指针被传递。
  • 还有一些函数根本不提供任何方法来指示所需的缓冲区大小。

所有这些内容都可以在文档中轻松找到,但应该阅读它。真的。它可以节省您的时间。

【讨论】:

    【解决方案4】:

    使用GetTempPathAGetTempFileNameAGetTempPathGetTempFileName 的Ansi 版本。它们在 Delphi 2009 中仍然可用,并且在 Delphi 2009 帮助文件中提到,但没有做广告。

    【讨论】:

    • 在 Windows NT 操作系统版本上,如果不是全部的话,大多数 *A 版本的 API 函数只是用于转换参数并调用同一函数的 *W 版本的存根。因此,在 Delphi 2009+ 中,您将内部宽字符数据转换为 Ansi,调用 *A 函数,该函数在内部转换为宽字符并返回,程序将获取结果并将其转换回宽字符。你说走这条路有意义吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多