1. 程式人生 > >VC程式獲取管理員許可權

VC程式獲取管理員許可權

一:

編譯程式的時候設定一下
在專案屬性–聯結器–清單檔案–UAC執行級別改為requireAdministrator

二:

void GainAdminPrivileges(CString strApp, UINT idd)
{
    CString         strCmd;
    strCmd.Format (_T("/adminoption %d"), idd);

    SHELLEXECUTEINFO execinfo;
    memset(&execinfo, 0, sizeof(execinfo));
    execinfo.lpFile         = strApp;
    execinfo.cbSize         = sizeof(execinfo);
    execinfo.lpVerb         = _T("runas");
    execinfo.fMask          = SEE_MASK_NO_CONSOLE;
    execinfo.nShow          = SW_SHOWDEFAULT;
    execinfo.lpParameters   = strCmd;

    ShellExecuteEx(&execinfo);
}  

strApp是應用程式的路徑idd我傳的是1,但好像傳幾都沒問題

BOOL ElevateCurrentProcess(CString sCmdLine)
{
    TCHAR szPath[MAX_PATH] = {0};

    if (::GetModuleFileName(NULL, szPath, MAX_PATH))
    {
        // Launch itself as administrator.
        SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
        sei.lpVerb = _T("runas");
        sei.lpFile = szPath;
        sei.lpParameters = (LPCTSTR)sCmdLine;
        //     sei.hwnd = hWnd;
        sei.nShow = SW_SHOWNORMAL;

        if (!ShellExecuteEx(&sei))
        {
            DWORD dwStatus = GetLastError();
            if (dwStatus == ERROR_CANCELLED)
            {
                // The user refused to allow privileges elevation.
                return FALSE;
            }
            else if (dwStatus == ERROR_FILE_NOT_FOUND)
            {
                // The file defined by lpFile was not found and
                // an error message popped up.
                return FALSE;
            }
            return FALSE;
        }
        return TRUE;
    }
    return FALSE;
}

如何獲取正確的檔案路徑

當我們那些在Windows 7之前設計的應用程式遇到UAC Virtualization問題的時候,我們需要從新設計我們的程式碼,將檔案寫入到合適的位置。在改善既有程式碼,使之可以與Windows 7相容的時候,我們應該確保以下幾點:

  ——在執行的時候,應用程式只會將資料儲存到每個使用者預先定義的位置或者是%alluserprofile% 中定義的普通使用者擁有訪問許可權的位置。

  ——確定你要寫入資料的“已知資料夾”(Knownfolders)。通常,所有使用者共用的公共資料檔案應該寫入到一個全域性的公共的位置,這樣所有使用者都可以訪問到。而其它資料則應該寫入每個使用者自己的資料夾。

  1 公共資料檔案包括日誌檔案,配置檔案(通常是INI或者XML檔案),應用程式狀態檔案,比如儲存的遊戲程序等等。

  2 而屬於每個使用者的文件,則應該保持在文件目錄下,或者是使用者自己指定的目錄。

  ——當你確定合適的檔案儲存位置後,不要在程式碼中明文寫出(Hard-code)你選擇的路徑。為了更好地保持相容性,我們應該採用下面這些API來獲得作業系統“已知資料夾(Knownfolders)”的正確路徑。

  1 C/C++非託管程式碼: 使用SHGetKnownFolderPath函式,通過指定“已知資料夾”的KNOWNFOLDERID作為引數來獲得正確的資料夾路徑。

  FOLDERID_ProgramData –所有使用者都可以訪問的應用程式資料適合放置在這個目錄下。
  FOLDERID_LocalAppData – 每個使用者單獨訪問的應用程式資料適合放置在這個目錄下。
  FOLDERID_RoamingAppData – 每個使用者單獨訪問的應用程式資料適合放置在這個目錄下。 與上面一個目錄不同的是,放置在這個目錄下的檔案會隨著使用者遷移,當一個使用者在同一個域中的其他計算機登入的時候,這些檔案會被複制到當前登入的機器上,就像使用者隨身攜帶的公文包一樣。

下面這段程式碼演示了在非託管程式碼中如何呼叫shell函式,SHGetKnownFolderPath函式獲得正確的檔案儲存路徑(SHGetFolderLocation, SHGetFolderPath, SHGetSpecialFolderLocation, SHGetSpecialFolderPath):

#include "shlobj.h"
#include "shlwapi.h"
//…

#define AppFolderName _T("YourApp")
#define DataFileName _T("SomeFile.txt")

// 構造一個數據檔案路徑
// dataFilePath指向一個長度為MAX_PATH,型別為TCHAR的字串數值
// hwndDlg是訊息對話方塊的父視窗控制代碼
// 當有錯誤發生的時候用於顯示錯誤提示
// includeFileName用於表示是否在路徑後面擴充套件檔名
BOOL MakeDataFilePath(TCHAR *dataFilePath, 
                      HWND hwndDlg, BOOL includeFileName)
{
    // 初始化工作
    memset(dataFilePath, 0, MAX_PATH * sizeof(TCHAR));
    PWSTR pszPath = NULL;

    // SHGetKnownFolderPath函式可以返回一個已知檔案見的路徑,
    // 例如我的文件(My Documents),桌面(Desktop),
       // 應用程式資料夾(Program Files)等等。 
    // 對於資料檔案來說,FOLDERID_ProgramFiles並不是一個合適的位置
    // 使用FOLDERID_ProgramFiles儲存所有使用者共享的資料檔案
    // 使用FOLDERID_LocalAppData儲存屬於每個使用者自己的檔案(non-roaming).
    // 使用FOLDERID_RoamingAppData儲存屬於每個使用者自己的檔案(roaming).
// 對於“隨身檔案”(Roaming files),
// 當一個使用者在一個域中的其他計算機登陸的時候,
    // 這些檔案會被複制到當前登入的機器上,就像使用者隨身攜帶的公文包一樣    

    // 獲取資料夾路徑
    if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramData,
               0, NULL, &pszPath)))
    // 錯誤的做法: if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFiles,
       // 0, NULL, &pszPath)))
    {
        // 提示錯誤
        MessageBox(hwndDlg, _T("SHGetKnownFolderPath無法獲取檔案路徑"),
            _T("Error"), MB_OK | MB_ICONERROR);
        return FALSE;
    }

    // 複製路徑到目標變數
    _tcscpy_s(dataFilePath, MAX_PATH, pszPath);
    ::CoTaskMemFree(pszPath);

    //錯誤的做法: _tcscpy_s(dataFilePath, MAX_PATH, _T("C:\\"));

    // 在路徑後面擴充套件應用程式所在資料夾
    if (!::PathAppend(dataFilePath, AppFolderName))
    {
        // 提示錯誤
        MessageBox(hwndDlg, _T("PathAppend無法擴充套件路徑"),
            _T("Error"), MB_OK | MB_ICONERROR);
        return FALSE;
    }

    // 是否新增檔名
    if (includeFileName)
    {
        // 在路徑後擴充套件檔名
        if (!::PathAppend(dataFilePath, DataFileName))
        {
            // 提示錯誤
            MessageBox(hwndDlg, _T("PathAppend無法擴充套件檔名"),
                _T("Error"), MB_OK | MB_ICONERROR);
            return FALSE;
        }
    }

    return TRUE;
}

2 託管程式碼: 使用System.Environment.GetFolderPath函式,通過指定我們想要獲取的“已知資料夾”為引數,從而獲取相應的資料夾的正確路徑。

  Environment.SpecialFolder.CommonApplicationData – 所有使用者都可以訪問的應用程式資料適合放置在這個目錄下。
  Environment.SpecialFolder.LocalApplicationData – 每個使用者單獨訪問的應用程式資料適合放置在這個目錄下。
  Environment.SpecialFolder.ApplicationData – 每個使用者單獨訪問的應用程式資料適合放置在這個目錄下。這是“隨身資料夾”。

下面這段程式碼展示瞭如何在託管程式碼中獲取正確的檔案路徑:

internal class FileIO
    {
        private const string AppFolderName = "YourApp";
        private const string DataFileName = "SomeFile.txt";
        private static string _dataFilePath;

        /// <summary>
        /// 構建路徑
        /// </summary>
        static FileIO()
        {
            // Environment.GetFolderPath返回一個“已知資料夾”的路徑
            // Path.Combine可以合併兩個路徑成一個合法的路徑

            // …

            _dataFilePath = Path.Combine(Environment.GetFolderPath(
                  Environment.SpecialFolder.ProgramFiles), AppFolderName);
            //錯誤的做法:
            //_dataFilePath = Path.Combine(Environment.GetFolderPath(
             Environment.SpecialFolder.CommonApplicationData), AppFolderName);

            // 擴充套件檔名
            _dataFilePath = Path.Combine(_dataFilePath, DataFileName);
        }

         public static void Save(string text)
        {
            // 檢查要儲存的字串是否為空
            if (String.IsNullOrEmpty(text))
            {
                MessageBox.Show("字串為空,無法保持.", "空字串",
                     MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                // 獲取檔案儲存的路徑
                string dirPath = Path.GetDirectoryName(_dataFilePath);
                // 檢查資料夾是否存在
                if (!Directory.Exists(dirPath))
                    Directory.CreateDirectory(dirPath); // 建立資料夾
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "資料夾建立失敗",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                // 儲存字串到檔案
                StreamWriter sw = new StreamWriter(_dataFilePath);
                try
                {
                    sw.Write(text);
                }
                finally
                {
                    // 關閉檔案
                    sw.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "檔案寫入失敗",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        // …
   }
}

如果上面的方法都不適合你,你還可以使用環境變數,使用getenv()或GetEnvironmentVariable()獲取相應的資料夾路徑:

  %ALLUSERSPROFILE% – 所有使用者都可以訪問的應用程式資料適合放置在這個目錄下。
  %LOCALAPPDATA% – 每個使用者單獨訪問的應用程式資料適合放置在這個目錄下。 - (Windows Vista 或者Windows 7)
  %APPDATA% – 每個使用者單獨訪問的應用程式資料適合放置在這個目錄下。這是“隨身資料夾”。- (Windows Vista 或者Windows 7)

參考: