簡體   English   中英

以CreateProcessAsUser啟動的exe在啟動時隨機崩潰

[英]exe started with CreateProcessAsUser randomly crashes on start

這是一種情況:我有一個C#.NET Windows服務(以本地系統運行),該服務使用CreateProcessAsUser在當前登錄的用戶帳戶下啟動衛星C#.NET可執行文件(無窗口WinForms)。

有時它起作用,有時...它不起作用。 我可以看到該exe在任務管理器中顯示了僅一秒鍾,然后消失了。 exe的主要方法沒有被執行,因此我認為問題來自CreateProcessAsUser。

事件查看器顯示代碼為0xc06d007e的應用程序錯誤,這沒有幫助。 還有一個Windows錯誤報告,說要查看轉儲文件,但是給出的路徑中缺少這些文件。

我不知道該如何調試。 如果至少我可以看到一個真正的錯誤。

這是完全隨機的。

編輯:

這是一些要求的代碼。

public static uint? LaunchAsCurrentUser(string cmdLine)
{
    IntPtr token = GetCurrentUserToken();

    if (token == IntPtr.Zero)
        return null;

    IntPtr envBlock = GetEnvironmentBlock(token);
    uint? processId = LaunchProcessAsUser(cmdLine, token, envBlock);
    if (envBlock != IntPtr.Zero)
        DestroyEnvironmentBlock(envBlock);

    CloseHandle(token);
    return processId;
}

private static uint LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock)
{
    PROCESS_INFORMATION processInformation = new PROCESS_INFORMATION();
    SECURITY_ATTRIBUTES saProcess = new SECURITY_ATTRIBUTES();
    SECURITY_ATTRIBUTES saThread = new SECURITY_ATTRIBUTES();
    saProcess.nLength = (uint)Marshal.SizeOf(saProcess);
    saThread.nLength = (uint)Marshal.SizeOf(saThread);

    STARTUPINFO si = new STARTUPINFO();
    si.cb = (uint)Marshal.SizeOf(si);

    //if this member is NULL, the new process inherits the desktop
    //and window station of its parent process. If this member is
    //an empty string, the process does not inherit the desktop and
    //window station of its parent process; instead, the system
    //determines if a new desktop and window station need to be created.
    //If the impersonated user already has a desktop, the system uses the
    //existing desktop.

    si.lpDesktop = string.Empty; //Modify as needed
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
    si.wShowWindow = SW_SHOW;
    //Set other si properties as required.

    bool result = CreateProcessAsUser(
        token,
        null,
        cmdLine,
        ref saProcess,
        ref saThread,
        false,
        CREATE_UNICODE_ENVIRONMENT,
        envBlock,
        null,
        ref si,
        out processInformation);

    if (!result)
    {
        int error = Marshal.GetLastWin32Error();
        string message = String.Format("CreateProcessAsUser Error: {0}", error);
        throw new ApplicationException(message);
    }

    return processInformation.dwProcessId;
}

private static IntPtr GetEnvironmentBlock(IntPtr token)
{
    IntPtr envBlock = IntPtr.Zero;
    bool retVal = CreateEnvironmentBlock(ref envBlock, token, false);
    if (retVal == false)
    {
        // Environment Block, things like common paths to My Documents etc.
        // Will not be created if "false"
        // It should not adversley affect CreateProcessAsUser.

        string message = String.Format("CreateEnvironmentBlock Error: {0}", Marshal.GetLastWin32Error());
        throw new ApplicationException(message);

    }

    return envBlock;
}

private static IntPtr GetCurrentUserToken()
{
    IntPtr currentToken = IntPtr.Zero;
    IntPtr primaryToken = IntPtr.Zero;
    IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

    int dwSessionId = 0;
    IntPtr hUserToken = IntPtr.Zero;
    IntPtr hTokenDup = IntPtr.Zero;

    IntPtr pSessionInfo = IntPtr.Zero;
    int dwCount = 0;

    WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref dwCount);

    Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));

    Int64 current = (long)pSessionInfo;
    for (int i = 0; i < dwCount; i++)
    {
        WTS_SESSION_INFO si =
            (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
        if (WTS_CONNECTSTATE_CLASS.WTSActive == si.State)
        {
            dwSessionId = si.SessionID;
            break;
        }

        current += dataSize;
    }

    WTSFreeMemory(pSessionInfo);

    bool bRet = WTSQueryUserToken(dwSessionId, out currentToken);
    if (bRet == false)
        return IntPtr.Zero;

    bRet = DuplicateTokenEx(currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
    if (bRet == false)
        return IntPtr.Zero;

    return primaryToken;
}

只需更改以下內容:

si.lpDesktop = string.Empty;

對此:

si.lpDesktop = null;

...因此新進程繼承了其父進程桌面。 現在,它可以完美地工作了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM