CreateProcessWithLogonW 函式 (winbase.h)

建立新的進程及其主要線程。 然後,新的進程會在指定認證的安全性內容中執行指定的可執行檔, (用戶、網域和密碼) 。 它可以選擇性地載入指定使用者的使用者配置檔。

此函式類似於 CreateProcessAsUserCreateProcessWithTokenW 函式,不同之處在於呼叫端不需要呼叫 LogonUser 函式來驗證使用者並取得令牌。

語法

BOOL CreateProcessWithLogonW(
  [in]                LPCWSTR               lpUsername,
  [in, optional]      LPCWSTR               lpDomain,
  [in]                LPCWSTR               lpPassword,
  [in]                DWORD                 dwLogonFlags,
  [in, optional]      LPCWSTR               lpApplicationName,
  [in, out, optional] LPWSTR                lpCommandLine,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCWSTR               lpCurrentDirectory,
  [in]                LPSTARTUPINFOW        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

參數

[in] lpUsername

使用者的名稱。 這是要登入的用戶帳戶名稱。 如果您使用UPN格式,使用者@DNS_domain_name,lpDomain 參數必須是NULL。

用戶帳戶必須在本機計算機上具有 [本機登入] 許可權。 此許可權會授與工作站和伺服器上的所有使用者,但只授與域控制器上的系統管理員。

[in, optional] lpDomain

帳戶資料庫包含 lpUsername 帳戶的網域或伺服器名稱。 如果此參數為 NULL,則必須以 UPN 格式指定使用者名稱。

[in] lpPassword

lpUsername 帳戶的純文本密碼。

[in] dwLogonFlags

登入選項。 此參數可以是 0 (零) 或下列其中一個值。

意義
LOGON_WITH_PROFILE
0x00000001
登入,然後在 HKEY_USERS 登錄機碼中載入使用者配置檔。 函式會在載入配置檔之後傳回。 載入配置檔可能相當耗時,因此只有在您必須存取 HKEY_CURRENT_USER 登錄機碼中的資訊時,才最好使用此值。

Windows Server 2003: 配置檔會在新的進程終止之後卸除,不論它是否已經建立子進程。

Windowsxp: 配置檔會在新的進程和它建立的所有子進程終止之後卸除。

LOGON_NETCREDENTIALS_ONLY
0x00000002
登入,但只在網路上使用指定的認證。 新進程會使用與呼叫端相同的令牌,但系統會在 LSA 中建立新的登入會話,而進程會使用指定的認證作為默認認證。

這個值可用來建立一個程式,此進程會使用與遠端不同的認證集。 這在網域間案例中很有用,其中沒有任何信任關係。

系統不會驗證指定的認證。 因此,進程可以啟動,但可能無法存取網路資源。

[in, optional] lpApplicationName

要執行的模組名稱。 此課程模組可以是以 Windows 為基礎的應用程式。 例如,如果本機電腦上有適當的子系統可用,可能是某些其他類型的模組 (MS-DOS 或 OS/2) 。

字串可以指定要執行之模組的完整路徑和檔名,也可以指定部分名稱。 如果是部分名稱,函式會使用目前的磁碟驅動器和目前的目錄來完成規格。 函式不會使用搜尋路徑。 此參數必須包含擴展名;未假設預設延伸模組。

lpApplicationName 參數可以是 NULL,而模組名稱必須是 lpCommandLine 字串中的第一個空格符分隔標記。 如果您使用包含空格的長檔名,請使用引號字串來指出檔名結尾和自變數的開頭;否則,檔名模棱兩可。

例如,下列字串可以不同方式解譯:

“c:\program files\sub dir\program name”

系統會嘗試以下列順序解譯可能性:

  1. c:\program.exe files\sub dir\program name
  2. c:\program files\sub.exe dir\program name
  3. c:\program files\sub dir\program.exe name
  4. c:\program files\sub dir\program name.exe

如果可執行模組是16位應用程式, lpApplicationName 應該是NULL, 而 lpCommandLine 所指向的字串應該指定可執行模組及其自變數。

[in, out, optional] lpCommandLine

要執行的命令行。 此字串的最大長度為1024個字元。 如果 lpApplicationName 為 NULL,lpCommandLine 的模組名稱部分限制為MAX_PATH個字元。

函式可以修改此字串的內容。 因此,此參數不能是唯讀記憶體 (的指標,例如 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] dwCreationFlags

用來控制進程建立方式的旗標。 默認會啟用 CREATE_DEFAULT_ERROR_MODECREATE_NEW_CONSOLECREATE_NEW_PROCESS_GROUP 旗標。 如需值清單,請參閱 進程建立旗標

此參數也會控制新進程的優先順序類別,用來判斷進程線程的排程優先順序。 如需值清單,請參閱 GetPriorityClass。 如果未指定任何優先順序類別旗標,則除非建立程式的優先順序類別是IDLE_PRIORITY_CLASSBELOW_NORMAL_PRIORITY_CLASS,否則優先順序類別預設為 NORMAL_PRIORITY_CLASS。 在此情況下,子進程會收到呼叫進程的預設優先順序類別。

如果 dwCreationFlags 參數的值為 0:

  • 進程會取得預設的錯誤模式、建立新的控制台,並建立新的進程群組。
  • 假設新進程的環境區塊包含 ANSI 字元 (請參閱 lpEnvironment 參數以取得) 的其他資訊。
  • 16 位 Windows 應用程式會在共用的 Virtual DOS 計算機中執行, (VDM) 。

[in, optional] lpEnvironment

新進程的環境區塊指標。 如果此參數為 NULL,新進程會使用從 lpUsername 所指定使用者的設定檔建立的環境。

環境區塊是由 Null 終止字串的 Null 終止區塊所組成。 每個字串的格式如下:

名字=價值

因為等號 (=) 做為分隔符,所以不能在環境變數的名稱中使用。

環境區塊可以包含 Unicode 或 ANSI 字元。 如果 lpEnvironment 指向的環境區塊包含 Unicode 字元,請確定 dwCreationFlags 包含 CREATE_UNICODE_ENVIRONMENT

ANSI 環境區塊會由兩個 0 () 零個字節終止:一個用於最後一個字串,另一個則是終止區塊。 Unicode 環境區塊會以四個零個字節終止:兩個用於最後一個字元串,再兩個以終止區塊。

若要擷取特定用戶的環境區塊複本,請使用 CreateEnvironmentBlock 函式。

[in, optional] lpCurrentDirectory

進程目前目錄的完整路徑。 字串也可以指定 UNC 路徑。

如果此參數為 NULL,則新進程具有與呼叫進程相同的目前磁碟驅動器和目錄。 這項功能主要是針對需要啟動應用程式的殼層,並指定其初始磁碟驅動器和工作目錄。

[in] lpStartupInfo

STARTUPINFO 結構的指標。

即使 WinSta0\Default,應用程式也必須將指定使用者帳戶的許可權新增至指定的視窗月臺和桌面。

如果 lpDesktop 成員是 NULL 或空字串,新進程會繼承其父進程的桌面和視窗月臺。 應用程式必須將指定用戶帳戶的許可權新增至繼承的視窗月臺和桌面。

Windows XP: CreateProcessWithLogonW 會將指定使用者帳戶的許可權新增至繼承的視窗月臺和桌面。

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

重要如果 STARTUPINFO 結構的 dwFlags 成員指定STARTF_USESTDHANDLES,則標準句柄欄位不會變更複製到子進程,而不需驗證。 呼叫端負責確保這些欄位包含有效的句柄值。 不正確的值可能會導致子進程錯誤或當機。 使用 應用程式驗證器 運行時間驗證工具來偵測無效的句柄。
 

[out] lpProcessInformation

接收新進程的識別資訊 之PROCESS_INFORMATION 結構的指標,包括處理程式的句柄。

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

傳回值

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

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

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

備註

根據預設, CreateProcessWithLogonW 不會將指定的使用者配置檔載入 HKEY_USERS 登錄機碼。 這表示存取 HKEY_CURRENT_USER 登錄機碼中的資訊,可能不會產生與一般互動式登錄一致的結果。 您必須先將使用者登錄區載入 HKEY_USERS ,再呼叫 CreateProcessWithLogonW、使用 LOGON_WITH_PROFILE,或呼叫 LoadUserProfile 函式

如果 lpEnvironment 參數為 NULL,新進程會使用從 lpUserName 所指定使用者的配置檔建立的環境區塊。 如果未設定 HOMEDRIVE 和 HOMEPATH 變數, CreateProcessWithLogonW 會修改環境區塊,以使用使用者工作目錄的磁碟驅動器和路徑。

建立時,新的進程和線程句柄會收到 (PROCESS_ALL_ACCESSTHREAD_ALL_ACCESS) 的完整訪問許可權。 針對任一個句柄,如果未提供安全性描述元,句柄就可用於任何需要該類型之物件句柄的函式中。 提供安全性描述元時,會在授與存取權之前,對句柄的所有後續使用執行存取檢查。 如果拒絕存取,要求進程就無法使用句柄來存取進程或線程。

若要擷取安全性令牌,請將 PROCESS_INFORMATION 結構中的進程句柄傳遞至 OpenProcessToken 函式。

進程會指派進程標識碼。 標識元有效,直到進程終止為止。 它可以用來識別進程,也可以在 OpenProcess 函式中指定,以開啟進程的句柄。 進程中的初始線程也會指派線程標識碼。 您可以在 OpenThread 函式中指定它,以開啟線程的句柄。 標識元有效,直到線程終止為止,而且可用來唯一識別系統中的線程。 這些標識碼會在 PROCESS_INFORMATION中傳回。

呼叫線程可以使用 WaitForInputIdle 函式等候,直到新進程完成初始化,並正在等候使用者輸入,而沒有擱置的輸入。 這很適合用於父進程和子進程之間的同步處理,因為 CreateProcessWithLogonW 會傳回,而不需要等待新進程完成初始化。 例如,建立程式會先使用 WaitForInputIdle ,再嘗試尋找與新進程相關聯的視窗。

關閉行程的慣用方式是使用 ExitProcess 函式,因為此函式會將接近終止的通知傳送給附加至進程的所有 DLL。 關閉進程的其他方式不會通知附加的 DLL。 請注意,當線程呼叫 ExitProcess 時,進程的其他線程會終止,而不會有機會執行任何其他程式碼 (包括附加 DLL 的線程終止程式代碼) 。 如需詳細資訊,請參閱 終止進程

CreateProcessWithLogonW 會在目標使用者的安全性內容中存取指定的目錄和可執行映射。 如果可執行檔映像位於網路上,且路徑中指定了網路驅動器號,則目標用戶無法使用網路驅動器號,因為可以為每個登入指派網路驅動器號。 如果指定網路驅動器號,此函式會失敗。 如果可執行檔映像位於網路上,請使用 UNC 路徑。

此函式可以建立並同時執行的子進程數目有限制。 例如,在 Windows XP 上,此限制 是MAXIMUM_WAIT_OBJECTS*4。 不過,您可能因為全系統配額限制而無法建立此許多進程。

Windows XP 搭配 SP2、Windows Server 2003 或更新版本: 您無法從在 「LocalSystem」 帳戶下執行的行程呼叫 CreateProcessWithLogonW ,因為函式會使用呼叫端令牌中的登入 SID,而 「LocalSystem」 帳戶的令牌不包含此 SID。 或者,請使用 CreateProcessAsUserLogonUser 函式。

若要編譯使用此函式的應用程式,請將 _WIN32_WINNT 定義為0x0500或更新版本。 如需詳細資訊,請參閱 使用 Windows 標頭

安全性備註

lpApplicationName 參數可以是 NULL,可執行檔名稱必須是 lpCommandLine 中的第一個空格符分隔字串。 如果可執行檔或路徑名稱有空格,則因為函式剖析空格的方式,可能會執行不同的可執行檔。 請避免下列範例,因為函式嘗試在存在時執行 「Program.exe」,而不是 「MyApp.exe」。
LPTSTR szCmdline[]=_tcsdup(TEXT("C:\\Program Files\\MyApp"));
CreateProcessWithLogonW(..., szCmdline, ...)

如果惡意使用者在系統上建立名為 「Program.exe」 的應用程式,則使用 Program Files 目錄不正確地呼叫 CreateProcessWithLogonW 的任何程式都會執行惡意使用者應用程式,而不是預期的應用程式。

若要避免此問題,請勿傳遞 lpApplicationNameNULL。 如果您為 lpApplicationName 傳遞 NULL,請使用 lpCommandLine 中可執行文件路徑的引號,如下列範例所示:

LPTSTR szCmdline[]=_tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
CreateProcessWithLogonW(..., szCmdline, ...)

範例

下列範例示範如何呼叫此函式。


#include <windows.h>
#include <stdio.h>
#include <userenv.h>

void DisplayError(LPWSTR pszAPI)
{
    LPVOID lpvMessageBuffer;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, GetLastError(), 
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
        (LPWSTR)&lpvMessageBuffer, 0, NULL);

    //
    //... now display this string
    //
    wprintf(L"ERROR: API        = %s.\n", pszAPI);
    wprintf(L"       error code = %d.\n", GetLastError());
    wprintf(L"       message    = %s.\n", (LPWSTR)lpvMessageBuffer);

    //
    // Free the buffer allocated by the system
    //
    LocalFree(lpvMessageBuffer);

    ExitProcess(GetLastError());
}

void wmain(int argc, WCHAR *argv[])
{
    DWORD     dwSize;
    HANDLE    hToken;
    LPVOID    lpvEnv;
    PROCESS_INFORMATION pi = {0};
    STARTUPINFO         si = {0};
    WCHAR               szUserProfile[256] = L"";

    si.cb = sizeof(STARTUPINFO);
    
    if (argc != 4)
    {
        wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
        wprintf(L"\n\n");
        return;
    }

    //
    // TO DO: change NULL to '.' to use local account database
    //
    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE, 
            LOGON32_PROVIDER_DEFAULT, &hToken))
        DisplayError(L"LogonUser");

    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
        DisplayError(L"CreateEnvironmentBlock");

    dwSize = sizeof(szUserProfile)/sizeof(WCHAR);

    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
        DisplayError(L"GetUserProfileDirectory");

    //
    // TO DO: change NULL to '.' to use local account database
    //
    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2], 
            LOGON_WITH_PROFILE, NULL, argv[3], 
            CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, 
            &si, &pi))
        DisplayError(L"CreateProcessWithLogonW");

    if (!DestroyEnvironmentBlock(lpvEnv))
        DisplayError(L"DestroyEnvironmentBlock");

    CloseHandle(hToken);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

規格需求

需求
最低支援的用戶端 Windows XP [僅限傳統型應用程式]
最低支援的伺服器 Windows Server 2003 [僅限傳統型應用程式]
目標平台 Windows
標頭 winbase.h (包含 Windows.h)
程式庫 Advapi32.lib
Dll Advapi32.dll

另請參閱

CloseHandle

CreateEnvironmentBlock

CreateProcessAsUser

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

OpenProcess

PROCESS_INFORMATION

處理序和執行緒函式

程序

STARTUPINFO

SetErrorMode

WaitForInputIdle