在專案目錄新建 MyApp.manifest:
我的應用程序描述
True/PM
PerMonitorV2
VS2010+ (推薦):專案屬性 → 配置屬性 → Manifest Tool → Input and Output → Embed Manifest = Yes
VS2008/手動:
/MANIFEST:EMBED,ID=1 (EXE) 或 /MANIFEST:EMBED,ID=2 (DLL)mt.exe 後處理:mt.exe -manifest MyApp.manifest -outputresource:MyApp.exe;1
BOOL RunAsAdmin(LPCTSTR lpszExePath, LPCTSTR lpszParams = _T(""), LPCTSTR lpszDir = NULL)
{
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = _T("runas"); // 關鍵:請求提權
sei.lpFile = lpszExePath;
sei.lpParameters = lpszParams;
sei.lpDirectory = lpszDir;
sei.nShow = SW_SHOWNORMAL;
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
if (!ShellExecuteEx(&sei))
{
DWORD err = GetLastError();
if (err == ERROR_CANCELLED)
{
// 用戶在 UAC 提示中點擊「否」
return FALSE;
}
return FALSE;
}
// 可選:等待子進程結束
if (sei.hProcess)
{
WaitForSingleObject(sei.hProcess, INFINITE);
CloseHandle(sei.hProcess);
}
return TRUE;
}
BOOL EnsureRunAsAdmin()
{
// 1. 檢查當前是否已有管理員權限
BOOL bIsAdmin = FALSE;
PSID pAdministratorsGroup = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&NtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0,0,0,0,0,0, &pAdministratorsGroup))
{
CheckTokenMembership(NULL, pAdministratorsGroup, &bIsAdmin);
FreeSid(pAdministratorsGroup);
}
if (bIsAdmin) return TRUE; // 已是管理員
// 2. 非管理員:以 runas 動詞重啟自身
TCHAR szExePath[MAX_PATH];
GetModuleFileName(NULL, szExePath, MAX_PATH);
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = _T("runas");
sei.lpFile = szExePath;
sei.nShow = SW_SHOWNORMAL;
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
if (ShellExecuteEx(&sei))
{
// 3. 退出當前非提權實例
ExitProcess(0);
}
return FALSE; // 用戶拒絕或失敗
}
// 在 WinMain / _tWinMain / CWinApp::InitInstance 最開頭調用
int APIENTRY _tWinMain(...)
{
if (!EnsureRunAsAdmin()) return 0; // 用戶拒絕提權,直接退出
// 後續代碼均在管理員權限下運行
...
}
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| Manifest 嵌入 | 標準、無代碼侵入、圖標自帶盾牌、系統級提權 | 進程啟動即提權,無法延遲/條件提權 | 主程序、安裝程序、系統工具 |
| 啟動器法 | 靈活控制何時提權、可傳參數、主程序無需提權 | 需維護兩個 EXE、進程間通信較複雜 | 插件加載、偶爾需要提權的功能模塊 |
| 代碼自重啟 | 單 EXE 部署、邏輯自包含、可條件判斷 | 進程重啟有閃爍、命令行參數需手動傳遞 | 綠色軟件、單文件工具、不想嵌入 Manifest |