Вот такая ситуация: у меня есть служба Windows C# .NET (запускается как локальная система), которая запускает исполняемый файл C# .NET (без окон WinForms) под текущей учетной записью пользователя, используя CreateProcessAsUser.exe запущен с CreateProcessAsUser случайным образом сбой при запуске
Иногда это работает, иногда ... это не так. Я вижу, что exe появляется в диспетчере задач всего на секунду и исчезает. Основной метод exe не попадает, поэтому я думаю, что проблема исходит от CreateProcessAsUser.
Средство просмотра событий показывает ошибку приложения с кодом 0xc06d007e, который не помогает. Существует также отчет об ошибках Windows, в котором говорится, что нужно посмотреть файлы дампа, но они отсутствуют в указанном пути.
Я понятия не имею, как отладить это. Если бы я мог увидеть реальную ошибку.
Это абсолютно случайный.
EDIT:
Вот код, как просили.
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;
}
.NET-программисты рано или поздно всегда обнаруживают, что запись обработчика событий для события AppDomain.CurrentDomain.UnhandledException никогда не является обязательным. Без отладчика и Trace Stack, вы слепы, как летучая мышь, чтобы обнаружить основную проблему. И никогда не просите помощи на сайте, например, SO. –
Без улучшения. Я пытался прослушивать события UnhandledExceptions как для службы Windows, так и для exe, но безрезультатно. Думаю, мне нужно разместить его в главном экзе (я сделал), но, как я уже сказал, он никогда не срабатывает. Кажется, что exe будет убит ОС сразу после его запуска. – user1174017
Не могли бы вы показать свой код? Сделали ли вы все «волшебство», которое описано здесь [http://blogs.msdn.com/b/winsdk/archive/2009/07/14/launching-an-interactive-process-from-windows-service-in -windows-перспектива-и-later.aspx)? Может быть, это может быть полезно. [Вот мой код] (http://pastebin.com/xhajdxrk), как я запускаю некоторый EXE под SessionId для некоторого пользователя. Он написан на C++, но его можно вызвать из C# через PInvoke. Вы можете перечислить весь сеанс [WTSEnumerateSessions] (https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa383833%28v=vs.85%29.aspx). –