【问题标题】:GetTempPathA how would I know size in advance?GetTempPathA 我怎么会提前知道大小?
【发布时间】:2021-10-05 07:21:00
【问题描述】:

我正在使用 C 语言编写代码,使用 Windows API。

我正在查看 GetTempPathA() 函数here,并在下面包含了该函数的语法。

DWORD GetTempPathA(
  DWORD nBufferLength,
  LPSTR lpBuffer
);

我可以看到路径将存储在 lpBuffer 中,但我不明白我如何知道将 DWORD nBufferLength 设置为的大小 - 我希望具有更多 Windows 开发经验的人会告诉我这是一个值ANSI 语言系统和另一个用于 Unicode 的语言系统,但我更愿意向 Stackoverflow 上的专业人士寻求指导?

我认为它需要设置为文件路径可能的最长值,因为用户可能以某种方式将默认位置更改为系统其他地方的更长路径,但我只是猜测。

这似乎只是一个 ANSI 函数,但是在我查看 MSDN 上的文档期间,我经常发现具有 ANSI 和 Unicode 函数(分别以 A 和 W 结尾)的函数。我确实理解它们之间的区别,但是如果我必须创建一个缓冲区,那么最大输入大小是多少?

最后,在回答时请记住,我确实喜欢编写向后兼容的应用程序,因为我的许多朋友生活在第三世界国家,无法使用最新的 Windows 操作系统。

【问题讨论】:

  • 为什么你使用这个函数的ANSI版本而不是Unicode版本?
  • @DavidHeffernan 在 MSDN 上,它似乎只有一个 ANSI 版本,我想要向后兼容。此 ANSI 版本适用于较旧的操作系统,但会以资源为代价在较新的操作系统上将 ANSI 转换为 Unicode。
  • 您没有在 Windows 98 上运行您的代码。再次查看文档,当然有 Unicode 版本。而且 Windows 是使用 Unicode 实现的,因此当您调用 ANSI 函数时,转换成本更高。不要使用 ANSI 版本。使用 Unicode。
  • @questioner Google 通常在搜索函数名称时显示 ANSI 版本。如果函数名后面有一个 A,那么总是有一个 UNICODE 版本
  • @DavidHeffernan 我这样做是为了好玩。我已经在 Windows 98 上运行了用 Visual Studio 2010 编译的 hello world 程序。诀窍是链接到 msvcrt.dll 而不是 msvcr100.dll。

标签: c windows winapi unicode ansi


【解决方案1】:

您可以使用 固定大小 缓冲区来容纳最大可能的路径长度(例如 char buffer[MAX_PATH+1];),或者,如果您想分配 足够 缓冲区空间,调用 GetTempPathA 函数,初始时 nBufferLength 参数为零,NULL 值为 lpBuffer。 (据我所见,后者没有完全记录,但下面的代码有效,并且该系统用于许多其他需要给定大小的缓冲区的 WinAPI 调用。)

测试代码:

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    DWORD answer = GetTempPathA(0, NULL);
    printf("%lu\n", answer);
    char* buffer = malloc(answer);
    answer = GetTempPathA(answer, buffer);
    printf("Temp path is: >>>%s<<< (length = %lu)\n", buffer, answer);
    free(buffer);
    return 0;
}

请注意,第一次调用中answer 的值将比第二次调用中的值大一(因为前者将包含nul 终止符的空间)。

来自documentation

返回值

如果函数成功,则返回值是复制到lpBuffer的字符串的长度,以TCHARs为单位,不包括 终止空字符。如果返回值大于 nBufferLength,返回值是 TCHARs 中的长度 保存路径所需的缓冲区。

或者,对于“通用”工作的版本,对于 Unicode 和多字节 (ANSI) 构建,请使用以下内容:

#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    DWORD answer = GetTempPath(0, NULL);
    _tprintf(TEXT("%lu\n"), answer);
    TCHAR* buffer = malloc(sizeof(TCHAR) * answer);
    answer = GetTempPath(answer, buffer);
    _tprintf(TEXT("Temp path is: >>>%s<<< (length = %lu)\n"), buffer, answer);
    free(buffer);
    return 0;
}

【讨论】:

  • 别忘了在生产代码中进行足够的错误处理——检查GetTempPath()的返回值是否为0,检查malloc()的返回值是否为NULL等
  • @RemyLebeau 好点。为了简洁起见,我省略了这些检查,但也许我应该包括它们?
【解决方案2】:

MSDN 明确指出,通常最大路径长度为 260 个字符:

在 Windows API 中(下面将讨论一些例外情况 段落),路径的最大长度为 MAX_PATH,即 定义为 260 个字符。

https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd

文章还指出,从某些 Windows 版本开始,应用程序可以通过清单选择加入长路径。

【讨论】:

  • 我听说较新版本的 Windows 允许超过 260 个字符的路径。另外,如果我使用 260 个字符,我应该为 DWORD 大小执行 260 * 8 = 2080 吗?
  • @questioner 我提供的链接地址较新的 Windows 版本。不,你不需要乘以任何东西。 DWORD 是参数的类型(基本上是 long int)。
  • DWORD nBufferLength = 260;这对我的程序来说足够了吗?
  • @questioner 如果您不选择加入较新的长路径行为,则路径不能超过 260 个字符(使用 MAX_PATH 定义,不要在您的代码)。如果您选择加入,则必须相应地使用合适的值,但 8 may not be sufficient,取决于用户的实际配置。
  • @questioner 调用传递 NULL 的函数以便在使用分配的缓冲区再次调用之前获得所需的长度是常见的做法。一点也不哈克。事实上的最佳实践。
猜你喜欢
  • 2011-04-16
  • 2017-05-17
  • 2020-12-14
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
相关资源
最近更新 更多