【问题标题】:embarcadero delphi and widechar : simple function that doesn't workembarcadero delphi 和widechar :不起作用的简单功能
【发布时间】:2011-09-10 20:57:36
【问题描述】:

我真的不明白为什么这个功能不起作用:

function GetNomRepertoireTemporaire:WideString;
var
  PathLocal : array[0..MAX_PATH+1] of WideChar;
begin
  Result := '';
  if GetTempPath(SizeOf(PathLocal)-1, PathLocal)>0 then
  begin
    Result := PathLocal;
  end;
end;

当我这样称呼它时:

var
  t : wideString;
initialization
  t := GetNomRepertoireTemporaire;

我等待大约 10 秒,然后我收到一个 AV at 0x000000 address 0000000

谁能解释我做错了什么?

【问题讨论】:

  • 看看 Delphi 给你的警告。你能列出来吗?
  • 为什么是宽字符串和宽字符?为什么不用字符串和字符?

标签: delphi


【解决方案1】:

您应该在代码中使用 Length 而不是 SizeOf:

function GetNomRepertoireTemporaire:WideString;
var
  PathLocal : array[0..MAX_PATH] of WideChar;
begin
  Result := '';
  if GetTempPath(Length(PathLocal), PathLocal)>0 then
  begin
    Result := PathLocal;
  end;
end;

以上代码假设您使用的是Unicode Delphi 版本。正如 David 在评论中提到的,您可以更改函数以使其与 Unicode 和非 Unicode Delphi 兼容:

function GetNomRepertoireTemporaire:String;
var
  PathLocal : array[0..MAX_PATH] of Char;
begin
  Result := '';
  if GetTempPath(Length(PathLocal), PathLocal)>0 then
  begin
    Result := PathLocal;
  end;
end;

解释:GetTempPath 函数用零填充它接收到的整个缓冲区。 OP 代码设置了无效的缓冲区大小(实际大小的两倍),因此函数将 PathLocal 变量后面的内存归零,从而导致 AV。

【讨论】:

  • +1 是最快的并删除了我自己的相同答案。
  • 不要从缓冲区大小中减去 1。文档说要给它缓冲区的大小,文档还说返回的缓冲区是空终止的。因此,您不需要在最后保留任何东西。但如果您确实在最后保留一个位置,请务必设置它。另外,请注意缓冲区的长度为 MAX_PATH + 2 个元素。
  • @Rob:已更正(删除 -1)。
  • 当然你的缓冲区应该是0..MAX_PATH-1
  • 不,应该是0..MAX_PATH
【解决方案2】:

您可以使用普通字符串来处理此问题,并完全避免使用 array of char。这是处理 Windows api 调用的好方法,因为您可以动态设置缓冲区的长度,并且SetLength 函数将与 AnsiStrings 以及 WideStrings 一起使用。

function GetNomRepertoireTemporaire: String;
var
  iSize: DWORD;
begin
  SetLength(Result, MAX_PATH);
  iSize := GetTempPath(MAX_PATH, PChar(Result));
  // reduce buffer to the effectively used size. if the api call
  // was successful, the terminating #0 is not included in iSize.
  SetLength(Result, iSize);
end;

Delphi 版本将决定是使用 AnsiString 还是 WideString。

【讨论】:

    【解决方案3】:

    虽然这并不能直接回答问题,但调用内置的 RTL 方法IOUtils.TPath.GetTempPath 可能会更好。

    【讨论】:

    • 你从不睡觉,是吗? +1 最短的解决方案。
    【解决方案4】:

    阅读您的源代码后,我想到了两件事。

    第一个是对方法本身的调用。我为函数 GetTempPath 找到的信息表明参数应为 Char(8 位字符)。如果您确实需要宽字符串中的临时路径,您可能必须在调用 GetTempPath 后将获得的路径转换为宽字符表示(只是猜测,因为我手头没有 API 文档)。

    第二点是第二个参数的传递。根据Delphi How To,您必须提供指向字符数组的指针。因此,对于您的示例,调用应如下所示

    if GetTempPath(MAX_PATH, @PathLocal) > 0 then
    

    希望对你有帮助。

    【讨论】:

    • 您的第二段实际上是不正确的。 GetTempPath,正如 WinAPI 中的规范一样,有 ANSI 和 Unicode 版本,分别是 GetTempPathA 和 GetTempPathW。我们必须假设 OP 是支持 Unicode 的 Delphi,因此调用 GetTempPathW。
    【解决方案5】:

    如果您阅读 API GetTempPath 的帮助文件,您会看到第一个参数是缓冲区的大小,以 TCHAR 为单位。 (即缓冲区中的字符数)

    现在,您正在为函数提供缓冲区中的字节数,这是字符数的两倍。

    像这样改变你的函数:

    if GetTempPath(Length(PathLocal)-1, PathLocal)>0 then 
    

    【讨论】:

    • ↑ 这个答案实际上是按照 OP 的要求解释
    • 有点,@User。这个答案确实提到 GetTempPath 被错误地调用,但它没有说明为什么会导致报告的错误。 GetTempPath 是否会覆盖缓冲区的其余部分,即使它不需要?我觉得不太可能。即使是这样,访问地址 0 处的内存的尝试在哪里?
    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 2014-11-20
    • 2015-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多