標籤:
就是用getLastErr可以得到錯誤號碼,同時,會將需要的長度寫到參數裡,再進行第二次調用,以此來節約記憶體空間。
神奇的長見識了。
相關說法如下:
======================
The error occurs because the buffer is insufficient. :-) It‘s not large enough for the content. Once again, I refer you to the documentation. If the function fails, the ReturnLength parameter is set to the size of the buffer needed, so you can allocate sufficient memory and call the function again. The general rule for many API calls that have variable buffer requirements is "Call the function once with a NULL buffer to determine the buffer size needed, allocate the memory, and then call it again to actually retrieve the information"
======================
The TOKEN_USER structure contains pointers (in particular, a pointer to a SID that itself has variable length). Those pointers have to point somewhere. The API function will expect a buffer big enough to hold not only the the TOKEN_USER structure, but also all the things that structure points to. The function tells you how much memory it needs for everything. It will all reside in adjacent memory.
======================
最近又在重新編寫一些以前已經實現過的功能, 一來是溫習之前學的一些東西, 二是希望多次重寫一個功能的過程中提升自己現有的編程技術和水平, 今天這篇文章算是一個小的總結.
在寫之前請容許我嘮叨片刻, 文章中涉及的技術與程式碼範例可能早遍布在百度與GOOGLE上的各種原創或轉載文章中, 所以我的內容多少也會與那些文章中的東西有所相同, 對於那些已經看過那些文章或者早已熟悉這些技術朋友可能會略顯平庸, 不過這都算是自己對技術積累的心得吧, 見笑了, 那麼言歸正傳了. Win32 API中提供了GetTokenInformation與SetTokenInformation函數, 這2個函數別分是檢索與設定一個存取權杖的資訊, 關於存取權杖的具體細節有興趣的朋友可以去MSDN上找, 因為與文章主題沒有直接的關係, 所以就不在具體細說了.以下是GetTokenInformation的API原型(如果想對這個函數的細節做更多瞭解, 可以去MSDN上查詢它的詳細資料)
WINADVAPI
BOOL
WINAPI
GetTokenInformation (
_In_ HANDLE TokenHandle,
_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
_Out_opt_ LPVOID TokenInformation, _In_
DWORD TokenInformationLength, _Out_
PDWORD ReturnLength
);
總得來說, 這個函數算是Win32 API中比較有代表性的一個, 參數的含義也都是一目瞭然, 這裡就不再過多獒述了(注: 關於GetTokenInformation參數含義這裡倒是有一個趣事, 如果有興趣看的朋友可以在文章最後找到我對它的說明), 有興趣的朋友可以去MSDN上找這個API的具體文檔, 下面我用一段程式碼範例來示範如何使用GetTokenInformation函數檢索進程的所有特權資訊
static PTOKEN_GROUPS GetProcessGroups(HANDLE hProcess)
{
HANDLE hToken;
PTOKEN_GROUPS pGroups = NULL;
DWORD neededSize;
// 這裡會先獲得一個進程存取權杖的控制代碼, 並且只允許該控制代碼具有資訊查詢的許可權.
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
return NULL;
// 這裡第一次調用GetTokenInformation是為了擷取令牌資訊需要的緩衝區的大小,
// 這是在使用Win32 API中的一個常用做法, 很多Win32 API都可以這樣使用, 目的
// 是不用讓程式員總是建立一個假設一定足夠的緩衝區, 這在很多時候會造成空間上的浪費
neededSize = 0;
GetTokenInformation(hToken, TokenGroups, NULL, neededSize, &neededSize);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && neededSize > 0)
{
pGroups = HeapAlloc(GetProcessHeap(), 0, neededSize);
if (pGroups != NULL)
{
// 這裡是真正去檢索特權資訊, 並且檢查成功或失敗.
if (!GetTokenInformation(hToken, TokenGroups, pGroups, neededSize, &neededSize))
{
HeapFree(GetProcessHeap(), 0, pGroups);
pGroups = NULL;
}
}
}
CloseHandle(hToken);
return pGroups;
}
這個函數是用C編寫的, 關鍵性的代碼旁邊都有注釋說明其函數, 到這裡文檔的主要內容也就結束了, 不過值得多說一句的是, GetTokenInformation不僅可以擷取進程的特權資訊, 同時還能得到其它更多的資訊, 比如進程所屬的所有使用者組, 進程擁有者以及虛擬化資訊等, 而TOKEN_INFORMATION_CLASS會告訴GetTokenInformation你想要哪種資訊.
關於GetTokenInformation函數參數的趣事
我在使用GetTokenInformation過程中發現了一個有趣的事情, 那就是Microsoft似乎在維護文檔與Platform SDK標頭檔時出現了歧義,
BOOL
WINAPI
GetTokenInformation (
__in HANDLE TokenHandle,
__in TOKEN_INFORMATION_CLASS TokenInformationClass,
__out_bcount_part_opt(TokenInformationLength, *ReturnLength) LPVOID TokenInformation,
__in DWORD TokenInformationLength,
__out_opt PDWORD ReturnLength
);
此時ReturnLength這個參數帶有_out_opt這樣的修飾符, 它在WIN32 API中的文檔約定是指被修飾的參數可以傳一個NULL指標進去而不會任何問題, 最多也就是你不知道實際填充到TokenInformation緩衝區的令牌資訊佔用了多少位元組, 不過有趣的是API的實現似乎是遵照了在MSDN官網文檔中定義的形式, 也就是ReturnLength這個值必須指向一個有效DWORD類型的變數, 所以如果你在調用GetTokenInformation時傳遞給ReturnLength是一個NULL值, 那麼GetTokenInformation會返回失敗, 並且調用GetLastError()會返回錯誤碼87(ERROR_INVALID_PARAMETER), 同樣的問題可能不只是出現在GetTokenInformation函數中, 其它一些少數API可能也存在此類問題, 所以使用的時候還需要多加留意才行.
在MSDN的文檔中ReturnLength這個參數被定義為"必選"參數, 這裡所謂的"必選"一詞是指它不是一個NULL指標值, 也就是不允許這樣的調用行為GetTokenInformation(...., NULL);, 但如果細心的朋友在Microsoft Visual Stdio 2005中查看這個WinBase.h中這個函數的原型聲明時會發現它的聲明形式如下:
WINDOWS下調用GetTokenInformation的奇怪之處--兩次調用