CreateProcessAsUserW 函式 (processthreadsapi.h)
建立新的進程及其主要線程。 新的進程會在指定令牌所代表之使用者的安全性內容中執行。
一般而言,呼叫 CreateProcessAsUser 函式的程式必須具有 SE_INCREASE_QUOTA_NAME 許可權,而且如果令牌無法指派,可能需要 SE_ASSIGNPRIMARYTOKEN_NAME 許可權。 如果此函式失敗 ,ERROR_PRIVILEGE_NOT_HELD ( 1314) ,請改用 CreateProcessWithLogonW 函式。 CreateProcessWithLogonW 不需要特殊許可權,但必須允許指定的用戶帳戶以互動方式登入。 一般而言,最好使用 CreateProcessWithLogonW 來建立具有替代認證的程式。
語法
BOOL CreateProcessAsUserW(
[in, optional] HANDLE hToken,
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
參數
[in, optional] hToken
代表使用者的主要令牌句柄。 句柄必須具有 TOKEN_QUERY、 TOKEN_DUPLICATE和 TOKEN_ASSIGN_PRIMARY 訪問許可權。 如需詳細資訊,請參閱 Access-Token 對象的訪問許可權。 令牌所代表的用戶必須具有 lpApplicationName 或 lpCommandLine 參數所指定之應用程式的讀取和執行存取權。
若要取得代表指定使用者的主要令牌,請呼叫 LogonUser 函式。 或者,您也可以呼叫 DuplicateTokenEx 函式,將模擬令牌轉換成主要令牌。 這可讓模擬用戶端的伺服器應用程式建立具有用戶端安全性內容的進程。
如果 hToken 是呼叫端主要令牌的限制版本,則不需要 SE_ASSIGNPRIMARYTOKEN_NAME 許可權。 如果尚未啟用必要的許可權, CreateProcessAsUser 會在呼叫期間啟用這些許可權。 如需詳細資訊,請參閱 使用特殊許可權執行。
終端機服務: 進程會在令牌中指定的工作階段中執行。 根據預設,這是呼叫 LogonUser 的相同會話。 若要變更會話,請使用 SetTokenInformation 函式 。
[in, optional] lpApplicationName
要執行的模組名稱。 此課程模組可以是以 Windows 為基礎的應用程式。 例如,如果本機電腦上有適當的子系統可用,可能是某些其他類型的模組 (MS-DOS 或 OS/2) 。
字串可以指定要執行之模組的完整路徑和檔名,也可以指定部分名稱。 在部分名稱的情況下,函式會使用目前的磁碟驅動器和目前目錄來完成規格。 函式不會使用搜尋路徑。 此參數必須包含擴展名;未假設預設延伸模組。
lpApplicationName 參數可以是 NULL。 在此情況下,模組名稱必須是 lpCommandLine 字串中的第一個空格符分隔標記。 如果您使用包含空格的長檔名,請使用引號字串來指出檔名結尾和自變數的開頭;否則,檔名模棱兩可。 例如,請考慮字串 「c:\program files\sub dir\program name」。。 此字串可以透過數種方式解譯。 系統會嘗試以下列順序解譯可能性:
c:\program.exec:\program files\sub.exec:\program files\sub dir\program.exec:\program files\sub dir\program name.exe 如果可執行檔模組是 16 位應用程式, lpApplicationName 應該是 NULL, 而 lpCommandLine 指向的字元串應該指定可執行檔模組及其自變數。 根據預設,CreateProcessAsUser 建立的所有 16 位 Windows 應用程式都會在不同的 VDM (中執行,相當於 CreateProcess) 中的CREATE_SEPARATE_WOW_VDM。
[in, out, optional] lpCommandLine
要執行的命令行。 此字串的最大長度為 32K 個字元。 如果 lpApplicationName 為 NULL,lpCommandLine 的模組名稱部分限制為MAX_PATH個字元。
這個函式的 Unicode 版本 CreateProcessAsUserW 可以修改此字串的內容。 因此,此參數不能是唯讀記憶體 (的指標,例如 const 變數或常值字串) 。 如果此參數是常數位符串,函式可能會造成存取違規。
lpCommandLine 參數可以是 NULL。 在此情況下,函式會使用 lpApplicationName 所指向的字串作為命令行。
如果 lpApplicationName 和 lpCommandLine 都是非 NULL,*lpApplicationName 會指定要執行的模組,而 *lpCommandLine 會指定命令行。 新的程式可以使用 GetCommandLine 來擷取整個命令行。 以 C 撰寫的控制台程式可以使用 argc 和 argv 自變數來剖析命令行。 因為 argv[0] 是模組名稱,C 程式設計人員通常會在命令行中重複模組名稱作為第一個令牌。
如果 lpApplicationName 為 NULL,命令行的第一個空格符分隔標記會指定模組名稱。 如果您使用包含空格的長檔名,請使用引號字串來指出檔名結尾的位置,而自變數會開始 (請參閱 lpApplicationName 參數的說明) 。 如果檔名不包含擴展名,則會附加 .exe。 因此,如果擴展名.com,此參數必須包含.com擴展名。 如果檔名以不含擴展名的句號結尾 (.) ,或檔名包含路徑,則不會附加 .exe。 如果檔案名不包含目錄路徑,系統會以下列順序搜尋可執行檔:
- 應用程式從中載入的目錄。
- 父進程的目前目錄。
- 32 位 Windows 系統目錄。 使用 GetSystemDirectory 函式 來取得此目錄的路徑。
- 16 位 Windows 系統目錄。 沒有函式可取得此目錄的路徑,但已搜尋。
- Windows 目錄。 使用 GetWindowsDirectory 函式 來取得此目錄的路徑。
- PATH 環境變數中列出的目錄。 請注意,此函式不會搜尋 應用程式路徑 登錄機碼所指定的個別應用程式路徑。 若要在搜尋順序中包含此個別應用程式路徑,請使用 ShellExecute 函式。
[in, optional] lpProcessAttributes
SECURITY_ATTRIBUTES 結構的指標,指定新進程對象的安全性描述元,並判斷子進程是否可以繼承傳回的進程句柄。 如果 lpProcessAttributes 為 NULL 或 lpSecurityDescriptor 為 NULL,則進程會取得預設的安全性描述元,而且無法繼承句柄。 默認的安全性描述元是 hToken 參數中所參考的使用者。 此安全性描述元可能不允許存取呼叫端,在此情況下,在執行進程之後可能不會再次開啟。 進程句柄有效,而且會繼續擁有完整的訪問許可權。
[in, optional] lpThreadAttributes
SECURITY_ATTRIBUTES 結構的指標,指定新線程對象的安全性描述元,並判斷子進程是否可以繼承傳回的句柄給線程。 如果 lpThreadAttributes 為 NULL 或 lpSecurityDescriptor 為 NULL,則線程會取得預設的安全性描述元,而且無法繼承句柄。 默認的安全性描述元是 hToken 參數中所參考的使用者。 此安全性描述元可能不允許呼叫端的存取。
[in] bInheritHandles
如果此參數為 TRUE,則呼叫進程中的每個可繼承句柄都會由新進程繼承。 如果 參數為 FALSE,則不會繼承句柄。 請注意,繼承的句柄的值和訪問許可權與原始句柄相同。 如需可繼承句柄的其他討論,請參閱。
終端機服務: 您無法跨工作階段繼承句柄。 此外,如果此參數為 TRUE,您必須在與呼叫端相同的會話中建立進程。
受保護的行程光線 (PPL) 行程: 當PPL進程建立非PPL進程時,會封鎖泛型句柄繼承,因為不允許從非PPL進程到PPL進程PROCESS_DUP_HANDLE。 請參閱 處理安全性和訪問許可權
[in] dwCreationFlags
控制優先順序類別和建立進程的旗標。 如需值清單,請參閱 進程建立旗標。
此參數也會控制新進程的優先順序類別,用來判斷進程線程的排程優先順序。 如需值清單,請參閱 GetPriorityClass。 如果未指定任何優先順序類別旗標,則除非建立程式的優先順序類別是IDLE_PRIORITY_CLASS或BELOW_NORMAL_PRIORITY_CLASS,否則優先順序類別預設為 NORMAL_PRIORITY_CLASS。 在此情況下,子進程會收到呼叫進程的預設優先順序類別。
如果 dwCreationFlags 參數的值為 0:
- 進程會同時繼承呼叫端和父代控制台的錯誤模式。
- 假設新進程的環境區塊包含 ANSI 字元 (請參閱 lpEnvironment 參數以取得) 的其他資訊。
- 16 位 Windows 應用程式會在共用的 Virtual DOS 計算機中執行, (VDM) 。
[in, optional] lpEnvironment
新進程的環境區塊指標。 如果此參數為 NULL,新進程會使用呼叫進程的環境。
環境區塊是由 Null 終止字串的 Null 終止區塊所組成。 每個字串的格式如下:
名字=value\0
因為等號是當做分隔符使用,所以不能用在環境變數的名稱中。
環境區塊可以包含 Unicode 或 ANSI 字元。 如果 lpEnvironment 所指向的環境區塊包含 Unicode 字元,請確定 dwCreationFlags 包含 CREATE_UNICODE_ENVIRONMENT。
如果進程的環境區塊大小總計超過 32,767 個字元, 則 CreateProcessAsUserA 此函式的 ANSI 版本會失敗。
請注意,ANSI 環境區塊會以兩個零位元節終止:一個用於最後一個字串,再一個以終止區塊。 Unicode 環境區塊會以四個零個字節終止:兩個用於最後一個字元串,兩個會再終止區塊。
Windows Server 2003 和 Windows XP: 如果合併的使用者和系統環境變數大小超過8192個字節, CreateProcessAsUser 所建立的進程就不會再執行,且由父進程傳遞至函式的環境區塊。 相反地,子進程會以 CreateEnvironmentBlock 函式傳回的環境區塊執行。
若要擷取指定用戶的環境區塊複本,請使用 CreateEnvironmentBlock 函式。
[in, optional] lpCurrentDirectory
進程目前目錄的完整路徑。 字串也可以指定 UNC 路徑。
如果此參數為 Null,新處理序會有與呼叫處理序相同的目前磁碟機和目錄。 (這項功能主要是針對需要啟動應用程式的殼層,並指定其初始磁碟驅動器和工作目錄。)
[in] lpStartupInfo
STARTUPINFO 或 STARTUPINFOEX 結構的指標。
用戶必須擁有指定視窗月臺和桌面的完整存取權。 如果您想要讓進程成為互動式程式,請指定 winsta0\default。 如果 lpDesktop 成員為 NULL,新進程會繼承其父進程的桌面和視窗月臺。 如果這個成員是空字串 “”,則新進程會使用與 視窗站的處理連接中所述的規則連接到視窗月臺。
若要設定擴充屬性,請使用 STARTUPINFOEX 結構,並在 dwCreationFlags 參數中指定EXTENDED_STARTUPINFO_PRESENT。
當不再需要 STARTUPINFO 或 STARTUPINFOEX 中的句柄時,必須使用 CloseHandle 關閉。
[out] lpProcessInformation
PROCESS_INFORMATION 結構的指標 ,可接收新進程的識別資訊。
PROCESS_INFORMATION 中的句 柄在不再需要時,必須使用 CloseHandle 關閉。
傳回值
如果函式成功,則傳回非零的值。
如果此函式失敗,則傳回值為零。 若要取得擴充的錯誤資訊,請呼叫 GetLastError。
請注意,函式會在進程完成初始化之前傳回。 如果找不到必要的 DLL 或無法初始化,進程就會終止。 若要取得進程的終止狀態,請呼叫 GetExitCodeProcess。
備註
CreateProcessAsUser 必須能夠使用 TOKEN_DUPLICATE 和 TOKEN_IMPERSONATE 訪問許可權開啟呼叫程式的主要令牌。
根據預設, CreateProcessAsUser 會在非互動式視窗站臺上建立新進程,且桌面無法看見且無法接收使用者輸入。 若要啟用使用者與新程式的互動,您必須在 STARTUPINFO 結構的 lpDesktop 成員中指定預設互動式視窗月臺和桌面 「winsta0\default」 的名稱。 此外,在呼叫 CreateProcessAsUser 之前,您必須變更預設互動式視窗月臺和預設桌面的 DACL (DACL) 的任意存取控制清單。 視窗月臺和桌面的 DACL 必須授與 使用者或 hToken 參數所代表之登入會話的存取權。
CreateProcessAsUser 不會將指定的使用者配置檔載入 HKEY_USERS 登錄機碼。 因此,若要存取HKEY_CURRENT_USER登錄機碼中的資訊,您必須先使用LoadUserProfile函式將使用者配置檔資訊載入HKEY_USERS,才能呼叫 CreateProcessAsUser。 在新的進程結束之後,請務必呼叫 UnloadUserProfile 。
如果 lpEnvironment 參數為 NULL,新進程會繼承呼叫進程的環境。 CreateProcessAsUser 不會自動修改環境區塊,以包含 hToken 所代表使用者特定的環境變數。 例如,如果 lpEnvironment 為 NULL,則 USERNAME 和 USERDOMAIN 變數會繼承自呼叫進程。 您必須負責準備新進程的環境區塊,並在 lpEnvironment 中加以指定。
CreateProcessWithLogonW 和 CreateProcessWithTokenW 函式類似於 CreateProcessAsUser,不同之處在於呼叫端不需要呼叫 LogonUser 函式來驗證使用者並取得令牌。
CreateProcessAsUser 可讓您在呼叫端或目標使用者的安全性內容中存取指定的目錄和可執行映像。 根據預設, CreateProcessAsUser 會存取呼叫端安全性內容中的目錄和可執行映像。 在此情況下,如果呼叫端沒有目錄和可執行映像的存取權,函式就會失敗。 若要使用目標使用者的安全性內容存取目錄和可執行檔映像,請在呼叫 ImpersonateLoggedOnUser 函式之前,先指定 hToken,再呼叫 CreateProcessAsUser。
進程會指派進程標識碼。 標識元有效,直到進程終止為止。 它可以用來識別進程,或在 OpenProcess 函式中指定,以開啟進程的句柄。 進程中的初始線程也會指派線程標識碼。 您可以在 OpenThread 函式中指定它,以開啟線程的句柄。 標識元有效,直到線程終止為止,而且可用來唯一識別系統中的線程。 這些標識碼會在 PROCESS_INFORMATION 結構中傳回。
呼叫線程可以使用 WaitForInputIdle 函式等候,直到新進程完成初始化,並正在等候沒有輸入擱置的使用者輸入。 這很適合用於父進程和子進程之間的同步處理,因為 CreateProcessAsUser 會傳回,而不需要等待新進程完成初始化。 例如,建立程式會先使用 WaitForInputIdle ,再嘗試尋找與新進程相關聯的視窗。
關閉行程的慣用方式是使用 ExitProcess 函式,因為此函式會將接近終止的通知傳送給附加至進程的所有 DLL。 關閉進程的其他方式不會通知附加的 DLL。 請注意,當線程呼叫 ExitProcess 時,進程的其他線程會終止,而不會有機會執行任何其他程式碼 (包括附加 DLL 的線程終止程式代碼) 。 如需詳細資訊,請參閱 終止進程。
根據預設,傳遞 TRUE 作為 bInheritHandles 參數的值會導致新進程繼承所有可繼承的句柄。 這可能會對同時從多個線程建立進程但希望每個進程繼承不同句柄的應用程式造成問題。 應用程式可以使用 UpdateProcThreadAttributeList 函式搭配 PROC_THREAD_ATTRIBUTE_HANDLE_LIST 參數,以提供特定進程所繼承的句柄清單。
安全性備註
lpApplicationName 參數可以是 NULL,在此情況下,可執行檔名稱必須是 lpCommandLine 中的第一個空格符分隔字串。 如果可執行檔或路徑名稱有空格,則因為函式剖析空格的方式,可能會執行不同的可執行檔。 下列範例很危險,因為函式會在存在時嘗試執行 「Program.exe」,而不是 「MyApp.exe」。 LPTSTR szCmdline[] = _tcsdup(TEXT("C:\\Program Files\\MyApp"));
CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/ );
如果惡意使用者要在系統上建立名為 「Program.exe」 的應用程式,則使用 Program Files 目錄不正確地呼叫 CreateProcessAsUser 的任何程式都會執行此應用程式,而不是預期的應用程式。
若要避免這個問題,請勿針對 lpApplicationName 傳遞 NULL。 如果您為 lpApplicationName 傳遞 NULL,請在 lpCommandLine 中的可執行文件路徑周圍使用引號,如下列範例所示。
LPTSTR szCmdline[] = _tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/);
PowerShell: 當 CreateProcessAsUser 函式用來在 PowerShell 2.0 版中實作 Cmdlet 時,Cmdlet 會針對風扇和展開遠端會話正確運作。 不過,由於某些安全性案例,使用 CreateProcessAsUser 所實作的 Cmdlet 只會在 PowerShell 3.0 版中正確運作,以進行傳送到遠端會話;展開遠端會話將會失敗,因為用戶端安全性許可權不足。 若要實作適用於 PowerShell 3.0 版中風扇和展開遠端會話的 Cmdlet,請使用 CreateProcess 函式。
範例
如需範例,請參閱 啟動互動式客戶端進程。
注意
processthreadsapi.h 標頭會將 CreateProcessAsUser 定義為別名,根據 UNICODE 預處理器常數的定義,自動選取此函式的 ANSI 或 Unicode 版本。 混合使用編碼中性別名與非編碼中性的程序代碼,可能會導致編譯或運行時間錯誤不符。 如需詳細資訊,請參閱 函式原型的慣例。
規格需求
需求 | 值 |
---|---|
最低支援的用戶端 | Windows XP [僅限傳統型應用程式] |
最低支援的伺服器 | Windows Server 2003 [僅限傳統型應用程式] |
目標平台 | Windows |
標頭 | processthreadsapi.h (包含 Windows.h) |
程式庫 | Advapi32.lib |
Dll | Advapi32.dll |