错误234“;更多数据可供参考;使用GetComputerNameEx

错误234“;更多数据可供参考;使用GetComputerNameEx,c,string,winapi,C,String,Winapi,我通过GetComputerNameEx函数获得了更多可用数据,但不知道如何修复它 这是我的代码: int wmain() { COMPUTER_NAME_FORMAT nameType = ComputerNameDnsFullyQualified; WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD size = ARRAYSIZE(computerName); BOOL pcName = GetCo

我通过
GetComputerNameEx
函数获得了更多可用数据,但不知道如何修复它

这是我的代码:

int wmain()
{
    COMPUTER_NAME_FORMAT nameType = ComputerNameDnsFullyQualified;
    WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1];
    DWORD size = ARRAYSIZE(computerName);

    BOOL pcName = GetComputerNameEx(nameType, computerName, &size);

    DWORD error = GetLastError();



    if (pcName != 0)
    {
        wprintf("Computer name: %s\n", computerName);
    }
    else
    {
        wprintf(L"Error getting the name. Code: %li\n", error);
    }

    return 0;
}

不知道如何将
size
变量设置为输出,以便我可以正确声明
computerName
数组。

您必须调用函数两次;一次使用空指针获取所需大小,另一次使用(至少)指定大小的缓冲区。正如文件所说:

要确保此缓冲区足够大,请将此参数设置为NULL 并使用lpnSize参数中返回的所需缓冲区大小

这是Win32函数的常见模式。是的,它确实会导致可能的比赛状态,但这就是它的工作原理

示例

DWORD dwSize = 0;
if (GetComputerNameEx(nameType, nullptr, &dwSize))
{
    WCHAR* computerName;
    computerName = (WCHAR*)malloc(dwSize * sizeof(WCHAR));
    if (GetComputerNameEx(nameType, computerName, &dwSize))
    {
        // use the name
    }
    free(computerName); // don't forget to free
}

该错误意味着
GetComputerNameEx
函数需要更大的缓冲区来存储返回的字符串

为了避免乔纳森·波特回答中提到的种族条件,你可以这样做:

LONG error = ERROR_MORE_DATA;
WCHAR* buffer = NULL;
DWORD bufferLength = /* Some initial reasonable length for the string buffer */;
while (error == ERROR_MORE_DATA) {
    // Create a buffer with bufferLength size (measured in WCHARs)
    buffer = realloc(buffer, bufferLength * sizeof(WCHAR));

    if (GetComputerNameEx(nameType, buffer, &bufferLength)) {
        error = ERROR_SUCCESS;
    } else {
        error = GetLastError();
    }
}
if (error != ERROR_SUCCESS) {
    // Some error occurred
    ...
}

// Use buffer containing computer name

// Don't forget to free(buffer)

根据
GetComputerNameEx()
文档:

lpBuffer[out]
指向接收计算机名或群集虚拟服务器名的缓冲区的指针

名称的长度可能大于
MAX\u COMPUTERNAME\u length
字符
,因为DNS允许更长的名称。要确保此缓冲区足够大,请将此参数设置为
NULL
,并使用
lpnSize
参数中返回的所需缓冲区大小

lpnSize[输入,输出]
在输入时,指定缓冲区的大小,单位为
TCHAR
s。输出时,接收复制到目标缓冲区的
TCHAR
s数,不包括终止的空字符

如果缓冲区太小,函数将失败,
GetLastError
返回
ERROR\u MORE\u数据
。此参数接收所需缓冲区的大小,包括终止空字符

如果
lpBuffer
为空,则此参数必须为零

例如:

int wmain()
{
    COMPUTER_NAME_FORMAT nameType = ComputerNameDnsFullyQualified;
    WCHAR *computerName = NULL, *computerNameNew;
    DWORD size = 0;
    BOOL pcName;
    DWORD error;

    do
    {
        pcName = GetComputerNameExW(nameType, computerName, &size);
        if (pcName) break;

        error = GetLastError();
        if (error != ERROR_MORE_DATA) break;

        computerNameNew = (WCHAR*) realloc(computerName, sizeof(WCHAR) * size);
        if (!computerNameNew) {
            error = ERROR_OUTOFMEMORY;
            break;
        }

        computerName = computerNameNew;
    }
    while (1);

    if (pcName)
    {
        wprintf("Computer name: %s\n", computerName);
    }
    else
    {
        wprintf(L"Error getting the name. Code: %ul\n", error);
    }

    free(computerName);
    return 0;
}

--lpBuffer太小。lpnSize参数包含接收名称所需的字节数。请注意,
MAX\u COMPUTERNAME\u LENGTH
不起作用的原因是,这是非限定名称的最大长度,OP的代码要求限定名称。我不确定DNS全名的长度是否有任何固定限制。但我无法在第一次调用
GetComputerNameEx
后设置
computerName[size]
,因为Visual Studio说
表达式必须有一个常量值。我能做什么?我没有使用您的实际代码,因为我使用的是C。请使用
malloc/free
而不是
new/delete
。我已经更新了示例。我发布了一个答案,其中的代码我认为不会受到竞争条件的影响。仅供参考,当
GetComputerNameEx()
ERROR\u MORE\u DATA
而失败时,
dwSize
的值已经包含空终止符的空间,因此您不需要
++dwSize
。这是有文档记录的行为:“如果缓冲区太小,函数将失败,
GetLastError
返回
ERROR\u MORE\u DATA
。此参数接收所需缓冲区的大小,包括终止空字符。”如果要使用
malloc()
,至少可以使用
realloc()
而不是循环时的
free()
。否则,请考虑使用<代码> LoalalLoCo()/代码> /<代码> LoalRealCube()/<代码>。另外,您需要使用
GetLastError()
来获取
错误
值,它不是由
GetComputerNameEx()
本身返回的。谢谢您的评论。我已经更新了代码。无论如何,我使用
free
+
malloc
而不是
realloc
的原因之一是在重新分配之间不需要保留以前的内存内容。True。另一方面,根据内存管理器的实现,
realloc()
可以简单地扩展现有内存块,而不必在内存中的其他位置搜索和保留一个全新的块。