来自GetVolumeInformation()的不同磁盘序列号

时间:2015-01-28 13:37:21

标签: c++ winapi disk hardware-id

DWORD disk_serialINT[MAX_PATH + 1];
GetVolumeInformationA(NULL, NULL, NULL, disk_serialINT, NULL, NULL, NULL, NULL);
char* disk_serialANSI;
sprintf(disk_serialANSI, "%d", disk_serialINT);
std::string HDDserial = disk_serialANSI;

这是我得到hdd序列号的代码片段,但问题是每次程序执行时值都不同。有人可以解释一下吗?

解决:

DWORD disk_serialINT;
GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL, NULL, NULL, NULL);
std::string HDDserial = std::to_string(disk_serialINT);

感谢。

3 个答案:

答案 0 :(得分:7)

这两行会给你undefined behavior

char* disk_serialANSI;
sprintf(disk_serialANSI, "%d", disk_serialINT);

您声明了一个指针变量,但实际上并没有指向任何地方。未初始化的局部变量具有不确定的值(实际上它看起来是随机的),并且通过使用该未初始化的指针,您不知道 {/ 1}}调用将写入


由于您使用C ++编程,因此有几种解决方案。

  • 过时的方法是使sprintf成为一个字符数组,大小足以容纳数字(包括字符串终结符)。另一种方法是为指针手动分配内存,然后在完成后再次释放该内存。

  • 使用std::ostringstream格式化数据并获得disk_serialANSI

  • 使用std::to_string直接转换为字符串。

  • 使用Boost Lexical cast

答案 1 :(得分:3)

除了Joachim所说的,你没有正确传递序列号。您应该将指针传递给单个值。

DWORD disk_serialINT;
GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL, NULL, NULL, NULL);

在您的代码中,您在此处所做的事情更加复杂:

sprintf(disk_serialANSI, "%d", disk_serialINT);

忽略Joachim的答案涵盖的未初始化变量disk_serialANSI,您将传递指向"%d"格式字符串的指针。将disk_serialINT更改为单个值后,事情会更好。但是,您将无符号值传递给单个格式字符串。

现在是时候放弃这些粗糙的C格式化函数,并使用C ++标准库在积分值和文本之间进行转换。

最后一点要强调的是,您必须检查对Win32 API的调用的返回值。你不知道函数调用是否成功。你不能认为它确实如此。这些都包含在文档中:https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993.aspx

该程序打印包含当前目录的卷的序列号:

#include <Windows.h>
#include <iostream>

int main()
{
    DWORD disk_serialINT;
    if (!GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL,
        NULL, NULL, NULL))
    {
        std::cout << "Failed: " << GetLastError() << std::endl;
        return 1;
    }
    std::cout << "Current directory volume serial numnber: " << std::hex 
        << disk_serialINT << std::endl;

    return 0;
}

答案 2 :(得分:0)

万一有人来看看这段代码,这里的解决方案就是我的看法:

问题1

DWORD disk_serialINT[MAX_PATH + 1];
  • 只需要一个DWORD值的数组时就声明它。
  • 使用MAX_PATH宏(并向其添加1)而不了解其用途。
  • 不知道类型(在INT类型为 unsigned 时命名变量DWORD)。
  • 不了解问题域(在变量disk_serial实际上是序列号时对其进行命名)。

问题2

GetVolumeInformationA(NULL, NULL, NULL, disk_serialINT, NULL, NULL, NULL, NULL);
  • 没有错误处理(不检查函数返回值是否失败)。
  • 不了解按值传递参数和按引用传递参数之间的区别(不传递disk_serialINT变量的地址)。

问题3

char* disk_serialANSI;
  • 不了解数组和指针之间的区别。
  • 不了解静态分配和动态分配之间的区别。

问题4

sprintf(disk_serialANSI, "%d", disk_serialINT);
  • 使用未初始化的变量disk_serialANSI
  • 使用错误的变量类型(使用char数组,或者保留指针但分配内存,然后再释放它)。
  • 不了解问题域(卷序列号使用错误的格式,应为%08lX)。
  • 不使用安全版本的sprintf

问题5

std::string HDDserial = disk_serialANSI;
  • 没有充分理由混合C和C ++。

换句话说,所有典型的初学者程序员错误。希望他们在此期间能学到更多,而不仅仅是在Stack Overflow上找到问题的答案。

上面已经有一个由David Heffeman提供的C ++解决方案,因此为了回答完整起见,这里是等效的C解决方案:

#include <stdio.h>
#include <windows.h>

int main()
{
    const int VolumeSerialLength = 9; // 8 hex digits + zero termination
    char VolumeSerial[VolumeSerialLength] = { 0 };
    DWORD VolumeSerialNumber;

    if (GetVolumeInformationA(NULL, NULL, NULL, &VolumeSerialNumber, NULL, NULL, NULL, NULL) {
        sprintf_s(VolumeSerial, VolumeSerialLength, "%08lX", VolumeSerialNumber);
        printf("Volume serial number: %8.8s.\n", VolumeSerial);
        return 0;
    } else {
        printf("GetVolumeInformationA() error: %08lX\n", GetLastError());
        return 1;
    }
}