吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1228|回复: 12
收起左侧

[已解决] GetLogicalDriveStrings函数的nBufferLength参数疑惑

[复制链接]
mxwawaawxm 发表于 2022-7-2 22:23
本帖最后由 mxwawaawxm 于 2022-7-7 08:24 编辑

[C] 纯文本查看 复制代码
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    // 获取驱动器根路径字符串的长度
    DWORD nBufferLength = GetLogicalDriveStrings(0, NULL);
    printf("%lu\n", nBufferLength);

    if (nBufferLength!=0) {
        // 分配内存,用以存储驱动器的根路径
        PTSTR lpBuffer = (PTSTR)malloc(sizeof(TCHAR)*nBufferLength);
        GetLogicalDriveStrings(nBufferLength, lpBuffer);
        // 依次打印驱动器的根路径
        for (int i=0; i<nBufferLength; i+=4) {
            if (*(lpBuffer+i)!='\0') {
                printf("%s\n", lpBuffer+i);
            } else {
                break;
            }
        }
        free(lpBuffer);
    }

    return 0;
}

以上的代码,主要是调用了GetLogicalDriveStrings函数,把驱动器根路径存储到lpBuffer的内存空间。从结果看出,我本机主要是有3个盘,存储至lpBuffer的内存空间共需要13个字节
2022-07-02_220922.png


但我查看https://docs.microsoft.com/en-us ... ogicaldrivestringsw的函数说明
发现其中对返回值有这样的一串说明,
If the function succeeds, the return value is the length, in characters, of the strings copied to the buffer, not including the terminating null character.
当函数成功执行,返回的是不包含结尾空字符的长度。那这样返回的nBufferLength长度应该是12,但为什么这里返回的是13?
[C] 纯文本查看 复制代码
DWORD nBufferLength = GetLogicalDriveStrings(0, NULL);



另外,这里的说明写着
nBufferLength,The maximum size of the buffer pointed to by lpBuffer, in TCHARs. This size does not include the terminating null character. If this parameter is zero, lpBuffer is not used.
第1个参数nBufferLength指明的大小不包含结尾的'\0'字符。那为什么GetLogicalDriveStrings(nBufferLength, lpBuffer);这一行代码,我写成
[C] 纯文本查看 复制代码
GetLogicalDriveStrings(nBufferLength-1, lpBuffer);

最后的打印结果反而出错。无法打印出E:\盘。
2022-07-02_222038.png


所以,请问大佬们GetLogicalDriveStrings的参数nBufferLength到底有没有包含最后的'\0'字符,这个函数的返回值的长度,有没有包含最后的'\0'字符。

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Pierce 发表于 2022-7-2 23:32
If the buffer is not large enough, the return value is greater than nBufferLength. It is the size of the buffer required to hold the drive strings.
这句已经解释了。
[C] 纯文本查看 复制代码
DWORD nBufferLength = GetLogicalDriveStrings(0, NULL);


后面的,你把 GetLogicalDriveStrings(nBufferLength, lpBuffer);
这句的返回print出来就知道了

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

爱飞的猫 发表于 2022-7-3 02:38
本帖最后由 jixun66 于 2022-7-3 02:40 编辑

因为每个小的字符串都有一个 \0,加上表示列表结束的 \0

[Asm] 纯文本查看 复制代码
[4字节] "C:\" [00]
[4字节] "D:\" [00]
[4字节] "E:\" [00]
[1字节] [00] <-- 表示列表结束


关于返回值,直接上文档:

If the buffer is not large enough, the return value is greater than nBufferLength. It is the size of the buffer required to hold the drive strings.
若缓冲区大小不够,那么返回值将大于传入的 nBufferLength。是缓冲区所需的大小。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

无闻无问 发表于 2022-7-3 07:08
GetLogicalDriveStrings中间盘符以一个\0分隔,末尾以两个\0结束…

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-7-3 10:26
Pierce 发表于 2022-7-2 23:32
If the buffer is not large enough, the return value is greater than nBufferLength. It is the size of ...

谢谢。
DWORD nBufferLength = GetLogicalDriveStrings(0, NULL);
是不是能这么解释,因为第一个参数写成0,所以返回包括结尾\0字符,所以
DWORD nBufferLength = GetLogicalDriveStrings(0, NULL);
返回了13

后面的,我打印了GetLogicalDriveStrings(nBufferLength, lpBuffer);的返回值,发现打印出来的结果是12
这里是不是这么解释,函数成功执行,返回不包括结尾\0字符的长度。
我疑惑的是nBufferLength这个参数的说明不是说This size does not include the terminating null character.

为什么调用GetLogicalDriveStrings(nBufferLength, lpBuffer);时,不应该写成GetLogicalDriveStrings(nBufferLength-1, lpBuffer);吗
为什么还是得写13,而不是12呢
 楼主| mxwawaawxm 发表于 2022-7-3 10:33
jixun66 发表于 2022-7-3 02:38
因为每个小的字符串都有一个 \0,加上表示列表结束的 \0

[mw_shl_code=asm,true]

谢谢。这个返回值,我好像明白了
DWORD nBufferLength = GetLogicalDriveStrings(0, NULL);
因为第一个参数写成0,缓冲区大小不够,所以返回包括结尾\0字符的长度,所以是13

后面我打印了GetLogicalDriveStrings(nBufferLength, lpBuffer);的值
因为缓冲区大小足够,所以返回不包括结尾\0字符的长度,这时返回值是12

但我还有一处不明白的是,nBufferLength这个参数的说明不是说This size does not include the terminating null character.
那为什么写GetLogicalDriveStrings(nBufferLength, lpBuffer);,不是写成
GetLogicalDriveStrings(nBufferLength-1, lpBuffer);
这个参数nBufferLength不是说不包含结尾空字符吗。那怎么不传递12的值,反而要传递13的值?

点评

那看来是文档错了  详情 回复 发表于 2022-7-3 16:25
 楼主| mxwawaawxm 发表于 2022-7-3 11:42
本帖最后由 mxwawaawxm 于 2022-7-3 13:36 编辑

无闻无问 发表于 2022-7-3 07:08
GetLogicalDriveStrings中间盘符以一个\0分隔,末尾以两个\0结束…

请问GetVolumeInformation函数是不能适用于光驱盘符吗
貌似GetVolumeInformation函数用于光驱盘符时,返回值是false
其他盘则是true
爱飞的猫 发表于 2022-7-3 16:25
本帖最后由 jixun66 于 2022-7-3 16:31 编辑
mxwawaawxm 发表于 2022-7-3 10:33
谢谢。这个返回值,我好像明白了
DWORD nBufferLength = GetLogicalDriveStrings(0, NULL);
因为第一个 ...

那看来是文档关于这个参数的描述错了
看 wine 的实现,确实如此。
https://github.com/wine-mirror/w ... nel32/volume.c#L387

不过这样看来反而不如去直接用其底层的 GetLogicalDrives() 方法了,不需要纠结缓冲区大小了

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-7-3 21:58
jixun66 发表于 2022-7-3 16:25
那看来是文档关于这个参数的描述错了
看 wine 的实现,确实如此。
https://github.com/wine-mirror/win ...

谢谢大佬。看了下
if ((count * 4) + 1 > len) return count * 4 + 1;
这里应该是GetLogicalDriveStrings传入的参数长度不足时,返回的值要加1,即count * 4 + 1
而后,如果GetLogicalDriveStrings传入的参数长度等于或大于count * 4 + 1,则返回count * 4(没有加1)
但中间GetLogicalDrives的返回值,还有移位操作,确实看不太懂

点评

DWORD 是 32 位,二进制看下来就是 00000000_00000000_00000000_00000000 最右边开始(分别代表 A - Z),如果该位是 1 就表示该盘符存在。 1  详情 回复 发表于 2022-7-4 02:46
爱飞的猫 发表于 2022-7-4 02:46
本帖最后由 jixun66 于 2022-7-4 02:47 编辑
mxwawaawxm 发表于 2022-7-3 21:58
谢谢大佬。看了下
if ((count * 4) + 1 > len) return count * 4 + 1;
这里应该是GetLogicalDriveStrin ...

DWORD 是 32 位,二进制看下来就是 00000000_00000000_00000000_00000000

最右边开始(分别代表 A - Z),如果该位是 1 就表示该盘符存在。

1 << 0 = 1(0b0001),对应第 1 位,即 A 盘
1 << 1 = 2(0b0010),对应第 2 位,即 B 盘
1 << 2 = 4(0b0100),对应第 3 位,即 C 盘
1 << 3 = 8(0b1000),对应第 4 位,即 D 盘

以此推类。

假设我有 C、D、F 盘,这个值就是 00000000_00000000_00000000_00101100 = 0x0000002C

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 10:50

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表