首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Vista/Win7/Win10 VC 程序以管理員權限運行:Manifest 嵌入法與啟動器法完整指南

     編輯:關於VC++

方法一:嵌入 Manifest(推薦,無需代碼修改)

步驟 1:創建 Manifest 文件

在專案目錄新建 MyApp.manifest:




  
  我的應用程序描述
  
    
      
        
      
    
  
  
    
      
       
       
       
       
       
    
  
  
  
    
      True/PM
      PerMonitorV2
    
  

步驟 2:嵌入 Manifest

VS2010+ (推薦):專案屬性 → 配置屬性 → Manifest Tool → Input and Output → Embed Manifest = Yes

VS2008/手動:

  1. 專案屬性 → Linker → Manifest File → Generate Manifest = No
  2. Linker → Command Line → Additional Options 添加:
    /MANIFEST:EMBED,ID=1 (EXE) 或 /MANIFEST:EMBED,ID=2 (DLL)
  3. 或使用 mt.exe 後處理:
    mt.exe -manifest MyApp.manifest -outputresource:MyApp.exe;1

效果

  • 程序圖標自帶 UAC 盾牌圖標
  • 雙擊運行彈出 UAC 確認對話框
  • 進程 Token 直接包含管理員權限,無需代碼判斷

方法二:啟動器進程法(適用於插件/子進程需提權)


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

常見問題 FAQ

  1. Manifest 不生效? 檢查:Embed Manifest=Yes、ID=1 (EXE)、清單文件編碼 UTF-8、重新建置而非僅編譯
  2. 調試時不想彈 UAC? Debug 配置禁用 Manifest 嵌入,或臨時修改 level="asInvoker"
  3. 子進程繼承權限? 父進程提權後創建的子進程默認繼承管理員 Token
  4. UIAccess="true" 危險? 允許繞過 UIPI 訪問高完整性窗口,極少數場景(如螢幕鍵盤)需用,普通程序必須 false
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved