2

我试图在我的 C++ win32 应用程序中使用 GetDiskFreeSpaceEx 来获取“当前”驱动器上的总可用字节数。我在 Windows 7 上。

我正在使用这个示例代码:http: //support.microsoft.com/kb/231497

它有效!嗯,差不多。如果我提供驱动器,它会起作用,例如:

...

szDrive[0] = 'C'; // <-- specifying drive
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = '\0';

pszDrive = szDrive;

...

fResult = pGetDiskFreeSpaceEx ((LPCTSTR)pszDrive,
                             (PULARGE_INTEGER)&i64FreeBytesToCaller,
                             (PULARGE_INTEGER)&i64TotalBytes,
                               (PULARGE_INTEGER)&i64FreeBytes);

fResult 变为true,我可以继续准确计算可用的空闲字节数。

然而,问题是我希望不必指定驱动器,而只需使用“当前”驱动器。我在网上找到的文档(这里)状态:

lpDirectoryName [输入,可选]

磁盘上的目录。如果此参数为NULL,则该函数使用当前磁盘的根。

但是,如果我为目录名称传入 NULL,则 GetDiskFreeSpaceEx 最终会返回false,并且数据仍然是垃圾。

fResult = pGetDiskFreeSpaceEx (NULL,
                             (PULARGE_INTEGER)&i64FreeBytesToCaller,
                             (PULARGE_INTEGER)&i64TotalBytes,
                               (PULARGE_INTEGER)&i64FreeBytes);

//fResult == false 

这很奇怪吗?我肯定错过了什么吗?任何帮助表示赞赏!

编辑

根据 JosephH 的评论,我进行了 GetLastError() 调用。它返回了 DWORD:

ERROR_INVALID_NAME 123 (0x7B)

  The filename, directory name, or volume label syntax is incorrect.

第二次编辑

埋在我提到的评论中:

我尝试了 GetCurrentDirectory 并返回正确的绝对路径,除了它的前缀\\?\

4

2 回答 2

5

它返回正确的绝对路径,除了它的前缀\\?\

这就是解开这个谜团的关键。你得到的是带有原生 api路径名的目录名。Windows 是一个操作系统,其内部看起来与您熟悉的 winapi 编程非常不同。Windows 内核有一个完全不同的 api,它与 DEC VMS 操作系统非常相似。并非巧合,大卫卡特勒曾经为 DEC 工作。在原生操作系统之上最初是三个 api 层,Win32、POSIX 和 OS/2。它们使将程序从其他操作系统移植到 Windows NT 变得容易。没有人关心 POSIX 和 OS/2 层,它们在 XP 时代被丢弃了。

Win32 中一个臭名昭著的限制是 MAX_PATH 的值,260。它设置存储文件路径名的 C 字符串的最大允许大小。本机 api 允许更大的名称,32000 个字符。您可以通过使用原生 api 格式的路径名绕过 Win32 限制。这与您熟悉的路径名称相同,但前缀为\\?\.

因此,您从 GetCurrentDirectory() 返回这样一个字符串的原因肯定是因为您当前的目录名称超过 259 个字符。进一步推断,GetDiskFreeSpaceEx() 失败是因为它有一个错误,它拒绝在您传递 NULL 时看到的长名称。可以理解的是,通常不会要求它处理长名称。每个人都只是传递驱动器名称。

当您创建具有如此长名称的目录时,这是相当典型的。东西只是开始随机掉落。一般来说,周围有很多使用 MAX_PATH 的 C 代码,当它必须处理比这更长的路径名时,该代码将失败。这也是一个非常可利用的问题,因为它能够在 C 程序中创建堆栈缓冲区溢出,从技术上讲,精心设计的文件名可用于操纵程序和注入恶意软件。

这个问题没有真正的解决方法,GetDiskFreeSpaceEx() 中的错误不会很快得到修复。删除那个目录,它会造成更多的麻烦,把它写下来作为学习经验。

于 2013-02-15T10:03:57.550 回答
1

我很确定您必须检索当前驱动器和目录并将其传递给函数。我记得尝试GetDiskFreeSpaceEx()将目录名称用作".",但这不起作用。

于 2013-02-15T01:39:04.387 回答