[英]c# start a exe until it is completely started and then append the arguments
[英]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.