我很好奇,如果我在理解API时遗漏了一些东西,那么应首先用NULL参数调用以检索所需的缓冲区大小,然后在分配缓冲区后再次调用它们。
我的理解是这个缓冲区长度不会从第一次调用变为第二次。 (好吧,假设我们没有处于“竞争状态”的情况,这是另一个故事。)
所以这是一个简单的现实生活中的例子,我在Windows XP SP2(64位)上观察到。以下方法获取当前用户的SID:
HANDLE hToken;
if(OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
DWORD dwSize = 0;
if(!GetTokenInformation(hToken, TokenUser, NULL, dwSize, &dwSize) &&
::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
BYTE* pb = new (std::nothrow) BYTE[dwSize];
if(pb)
{
TOKEN_USER* pTU = (TOKEN_USER*)pb;
DWORD dwSize2;
if(GetTokenInformation(hToken, TokenUser, pTU, dwSize, &dwSize2) &&
dwSize == dwSize2)
{
LPWSTR pName;
if(ConvertSidToStringSid(pTU->User.Sid, &pName))
{
//Got it!
_tprintf(L"User SID=%s\n", pName);
LocalFree(pName);
}
}
delete[] pb;
}
}
CloseHandle(hToken);
}
我在第二次调用dwSize == dwSize2
后GetTokenInformation
所做的那一部分,因为dwSize
从第一次调用44
返回GetTokenInformation
而失败了},然后dwSize2
从第二次调用返回为36
。
这种行为是否正常?
答案 0 :(得分:2)
在检索所需的字节大小时,API返回更大的值并不是闻所未闻(可能是为了对齐目的而将其舍入等),然后在检索实际时返回较小的值时使用相同的API数据,因为它报告实际写入分配的内存中的字节数。您不必比较这两个大小,相信如果函数说它成功了,那么写入的大小是< =分配的大小。
如果您担心会改变所需字节大小的竞争条件,请使用循环分配内存直到成功:
HANDLE hToken;
if (OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
BYTE* pb = NULL;
DWORD dwSize = 0;
TOKEN_USER* pTU = NULL;
BOOL bRet;
do
{
bRet = GetTokenInformation(hToken, TokenUser, pTU, dwSize, &dwSize);
if (bRet)
break;
if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break;
delete[] pb;
pb = new (std::nothrow) BYTE[dwSize];
if (!pb)
break;
pTU = (TOKEN_USER*)pb;
}
while (true);
if (bRet)
{
// use pTU as needed...
}
delete[] pb;
CloseHandle(hToken);
}
答案 1 :(得分:1)
只要dwSize大于dwSize2,就应该没问题。