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_QUERYTOKEN_DUPLICATETOKEN_ASSIGN_PRIMARY 存取權限。 如需詳細資訊,請參閱 Access-Token 物件的存取權限。 權杖所代表的使用者必須具有 lpApplicationNamelpCommandLine 參數所指定之應用程式的讀取和執行存取權。

若要取得代表指定使用者的主要權杖,請呼叫 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 個字元。 如果 lpApplicationNameNull則 lpCommandLine 的模組名稱部分限制為 MAX_PATH 個字元。

這個函式的 Unicode 版本 CreateProcessAsUserW可以修改此字串的內容。 因此,此參數不能是唯讀記憶體 (指標,例如 const 變數或常值字串) 。 如果此參數是常數位符串,函式可能會造成存取違規。

lpCommandLine參數可以是Null。 在此情況下,函式會使用 lpApplicationName 指向的字串作為命令列。

如果 lpApplicationNamelpCommandLine 都是非Null,*lpApplicationName 會指定要執行的模組,而 *lpCommandLine 會指定命令列。 新的進程可以使用 GetCommandLine 來擷取整個命令列。 以 C 撰寫的主控台進程可以使用 argcargv 引數來剖析命令列。 因為 argv[0] 是模組名稱,C 程式設計人員通常會重複模組名稱作為命令列中的第一個權杖。

如果 lpApplicationNameNull,命令列的第一個空白字元分隔標記會指定模組名稱。 如果您使用包含空格的長檔名,請使用引號字串來指出檔案名結束的位置,而引數會開始 (請參閱 lpApplicationName 參數的說明) 。 如果檔案名不包含副檔名,則會附加.exe。 因此,如果副檔名為 .com,此參數必須包含 .com 副檔名。 如果檔案名結尾為句號 (.) 沒有副檔名,或檔案名包含路徑,則不會附加.exe。 如果檔案名不包含目錄路徑,系統會依下列順序搜尋可執行檔:

  1. 應用程式從中載入的目錄。
  2. 父進程的目前目錄。
  3. 32 位 Windows 系統目錄。 使用 GetSystemDirectory 函式來取得此目錄的路徑。
  4. 16 位 Windows 系統目錄。 沒有可取得此目錄路徑的函式,但會加以搜尋。
  5. Windows 目錄。 使用 GetWindowsDirectory 函 式來取得此目錄的路徑。
  6. PATH 環境變數中所列的目錄。 請注意,此函式不會搜尋 應用程式路徑 登錄機碼所指定的個別應用程式路徑。 若要在搜尋順序中包含此個別應用程式路徑,請使用 ShellExecute 函式。
系統會將 Null 字元新增至命令列字串,以分隔檔案名與引數。 這會將原始字串分割成兩個字串以供內部處理。

[in, optional] lpProcessAttributes

SECURITY_ATTRIBUTES結構的指標,指定新進程物件的安全性描述項,並判斷子進程是否可以繼承傳回的控制碼給進程。 如果 lpProcessAttributesNulllpSecurityDescriptorNull,則進程會取得預設的安全性描述元,而且無法繼承控制碼。 預設的安全性描述元是 hToken 參數中所參考的使用者。 此安全性描述項不一定允許呼叫端存取,在此情況下,在執行進程之後可能無法再次開啟。 進程控制碼有效,而且會繼續擁有完整的存取權限。

[in, optional] lpThreadAttributes

SECURITY_ATTRIBUTES結構的指標,指定新執行緒物件的安全性描述項,並判斷子進程是否可以繼承傳回的控制碼給執行緒。 如果 lpThreadAttributesNulllpSecurityDescriptorNull,執行緒會取得預設的安全性描述元,而且無法繼承控制碼。 預設的安全性描述元是 hToken 參數中所參考的使用者。 此安全性描述元可能不允許呼叫端的存取。

[in] bInheritHandles

如果此參數為 TRUE,則呼叫進程中的每個可繼承控制碼都會由新進程繼承。 如果參數為 FALSE,則不會繼承控制碼。 請注意,繼承的控制碼的值和存取權限與原始控制碼相同。 如需可繼承控制碼的其他討論,請參閱。

終端機服務: 您無法跨會話繼承控制碼。 此外,如果此參數為 TRUE,您必須在與呼叫端相同的會話中建立進程。

受保護的進程淺色 (PPL) 程式: 當 PPL 進程建立非 PPL 進程時,會封鎖泛型控制碼繼承,因為不允許從非 PPL 進程到 PPL 進程PROCESS_DUP_HANDLE。 請參閱 程式安全性和存取權限

[in] dwCreationFlags

控制優先順序類別和建立進程的旗標。 如需值清單,請參閱 進程建立旗標

此參數也會控制新進程的優先順序類別,用來判斷進程執行緒的排程優先順序。 如需值清單,請參閱 GetPriorityClass。 如果未指定任何優先順序類別旗標,除非建立程式的優先順序類別IDLE_PRIORITY_CLASSBELOW_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

STARTUPINFOSTARTUPINFOEX結構的指標。

使用者必須擁有指定視窗月臺和桌面的完整存取權。 如果您想要讓進程成為互動式程式,請指定 winsta0\default。 如果 lpDesktop 成員為 Null,新進程會繼承其父進程的桌面和視窗月臺。 如果這個成員是空字串 「」,則新進程會使用與 視窗站的處理連接中所述的規則連接到視窗月臺。

若要設定擴充屬性,請使用STARTUPINFOEX結構,並在dwCreationFlags參數中指定EXTENDED_STARTUPINFO_PRESENT

當不再需要 STARTUPINFOSTARTUPINFOEX 中的控制碼時,必須使用 CloseHandle 關閉。

重要 呼叫端負責確保 STARTUPINFO 中的標準控制碼欄位包含有效的控制碼值。 即使 dwFlags 成員指定 STARTF_USESTDHANDLES,這些欄位也不會複製到子進程而不進行驗證。 不正確的值可能會導致子進程錯誤或當機。 使用 應用程式驗證器 執行時間驗證工具來偵測不正確控制碼。
 

[out] lpProcessInformation

PROCESS_INFORMATION 結構的指標 ,可接收新進程的識別資訊。

PROCESS_INFORMATION 中的句 柄在不再需要時,必須使用 CloseHandle 關閉。

傳回值

如果函式成功,則傳回非零的值。

如果此函式失敗,則傳回值為零。 若要取得擴充的錯誤資訊,請呼叫 GetLastError

請注意,函式會在進程完成初始化之前傳回。 如果找不到必要的 DLL 或無法初始化,進程就會終止。 若要取得進程的終止狀態,請呼叫 GetExitCodeProcess

備註

CreateProcessAsUser 必須能夠使用 TOKEN_DUPLICATETOKEN_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中加以指定。

CreateProcessWithLogonWCreateProcessWithTokenW函式類似于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

另請參閱

CloseHandle

CreateEnvironmentBlock

CreateProcess

CreateProcessWithLogonW

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

GetStartupInfo

ImpersonateLoggedOnUser

LoadUserProfile

PROCESS_INFORMATION

處理序和執行緒函式

程序

SECURITY_ATTRIBUTES

SHCreateProcessAsUserW

STARTUPINFO

STARTUPINFOEX

SetErrorMode

WaitForInputIdle