我有一个C#应用程序,它是使用CreateProcessAsUserW api从C++DLL启动的。进程已成功启动,但会立即终止。它在Windows 10上正常工作[包括32位和64位],在Windows 7上正常工作32位。我发现了以下链接,
为什么这个进程一启动就崩溃了?
但是,来自SysInternal的进程监视器没有发现丢失的dll。[我可以从ProcMon附加保存的日志]我还尝试将路径传递到API的lpCurrentDirectory参数中的应用程序文件夹,如其他地方所建议的,但这也不起作用。
我遵循了"当多个用户登录Windows时如何获得活动用户?"中的指导?为了编写启动进程的代码,并且从windows服务调用启动该进程的方法。为了从命令行中进行模拟,我使用了以下内容如何在本地系统帐户下运行CMD.exe?[pexec64-i-s cmd.exe,然后从cmd.exe启动进程]方法如下//当多个用户登录Windows时,如何获取活动用户?
STDMETHODIMP CProcessManager::LaunchProcessAsActiveUser(BSTR processName, LONG* dwProcessId)
{
//char *lpszPath = _com_util::ConvertBSTRToString(processName);
wchar_t* path = (wchar_t*)processName;//CharToWideChar(lpszPath);
DWORD session_id = -1;
DWORD session_count = 0;
WTS_SESSION_INFOA *pSession = NULL;
if (WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count))
{
//log success
}
else
{
//log error
return S_OK;
}
logger->Log(L"Session Count", session_count);
logger->Log(L"Begin Enumerating Sesions");
for (int i = 0; i < session_count; i++)
{
session_id = pSession[i].SessionId;
logger->Log(L"SessionId", session_id);
WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
DWORD bytes_returned = 0;
if (::WTSQuerySessionInformation(
WTS_CURRENT_SERVER_HANDLE,
session_id,
WTSConnectState,
reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
&bytes_returned))
{
wts_connect_state = *ptr_wts_connect_state;
::WTSFreeMemory(ptr_wts_connect_state);
if (wts_connect_state != WTSActive) continue;
}
else
{
//log error
continue;
}
logger->Log(L"End Enumerating Sesions");
logger->Log(L"Selected Session Id", session_id);
HANDLE hImpersonationToken;
if (!WTSQueryUserToken(session_id, &hImpersonationToken))
{
//log error
logger->Log(L"Exception in WTSQueryUserToken", GetLastError());
continue;
}
//Get real token from impersonation token
DWORD neededSize1 = 0;
HANDLE *realToken = new HANDLE;
if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1))
{
CloseHandle(hImpersonationToken);
hImpersonationToken = *realToken;
}
else
{
//log error
logger->Log(L"Exception in GetTokenInformation", GetLastError());
continue;
}
HANDLE hUserToken;
if (!DuplicateTokenEx(hImpersonationToken,
//0,
//MAXIMUM_ALLOWED,
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED,
NULL,
SecurityImpersonation,
TokenPrimary,
&hUserToken))
{
//log error
logger->Log(L"Exception in DuplicateTokenEx", GetLastError());
continue;
}
// Get user name of this process
//LPTSTR pUserName = NULL;
WCHAR* pUserName;
DWORD user_name_len = 0;
if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len))
{
//log username contained in pUserName WCHAR string
// char * lpszUserName = WideCharToChar(pUserName);
logger->Log(pUserName);
//LocalFree(lpszUserName);
}
else
{
logger->Log(L"Exception in WTSQuerySessionInformation", GetLastError());
}
//Free memory
if (pUserName) WTSFreeMemory(pUserName);
ImpersonateLoggedOnUser(hUserToken);
STARTUPINFOW StartupInfo;
StartupInfo.cb = sizeof(STARTUPINFOW);
//GetStartupInfoW(&StartupInfo);
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
//Uncommented by Sagar 20th January 20118 1612
StartupInfo.lpDesktop = CharToWideChar("winsta0\default");
//to Hide Console Process 03-10-2018
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow = SW_SHOW;//SW_HIDE;
PROCESS_INFORMATION processInfo;
SECURITY_ATTRIBUTES Security1;
ZeroMemory(&Security1, sizeof(Security1));
Security1.nLength = sizeof SECURITY_ATTRIBUTES;
SECURITY_ATTRIBUTES Security2;
ZeroMemory(&Security2, sizeof(Security2));
Security2.nLength = sizeof SECURITY_ATTRIBUTES;
void* lpEnvironment = NULL;
// Get all necessary environment variables of logged in user
// to pass them to the new process
BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE);
if (!resultEnv)
{
//log error
DWORD err = GetLastError();
logger->Log(L"Exception in CreateEnvironmentBlock", err);
continue;
}
WCHAR PP[1024]; //path and parameters
ZeroMemory(PP, 1024 * sizeof WCHAR);
wcscpy_s(PP, path);
wcscat_s(PP, L" ");
//wcscat(PP, args);
// Start the process on behalf of the current user
BOOL result = CreateProcessAsUserW(hUserToken,
PP,
NULL,
&Security1,
&Security2,
FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE/*| CREATE_NO_WINDOW*/,//CREATE_NO_WINDOW to Hide Console Process 03-10-2018
/*lpEnvironment*/NULL,
//"C:\ProgramData\some_dir",
NULL,
/*NULL,*/
&StartupInfo,
&processInfo);
if (!result)
{
//log error
//char * lpszPath = WideCharToChar(PP);
logger->Log(L"Failed to create process", PP);
//LocalFree(lpszPath);
DWORD err = GetLastError();
logger->Log(L"GetLastError returned", err);
}
else
{
*dwProcessId = processInfo.dwProcessId;
logger->Log(L"Created Process", *dwProcessId);
//log success
}
DestroyEnvironmentBlock(lpEnvironment);
CloseHandle(hImpersonationToken);
CloseHandle(hUserToken);
CloseHandle(realToken);
RevertToSelf();
}
WTSFreeMemory(pSession);
return S_OK;
}
下面附有Procmon屏幕截图请帮忙。谢谢Sagar
[![Pg 1](https://i.stack.imgur.com/CJCrG.png)
[![Pg 2](https://i.stack.imgur.com/uo8Uw.png)
[![Pg 3](https://i.stack.imgur.com/G7g12.png)
[![Pg 4](https://i.stack.imgur.com/6e5w4.png)
[![Pg 5](https://i.stack.imgur.com/8k2b0.png)
我尝试了以下排列
Target Process : ATL DLL : Launcher:Result
64 bit 64 bit 64 bit Crashes
64 bit 32 bit 64 bit Crashes
32 bit 32 bit 64 bit Crashes
32 bit 64 bit 64 bit Crashes
32 bit 32 bit 32 bit OK
64 bit 32 bit 32 bit OK
64 bit 64 bit 32 bit OK
32 bit 64 bit 32 bit OK
因此,如果启动器进程是64位的,那么它总是崩溃,如果是32位的,它总是成功。64位和32位启动器进程之间的区别是什么?
我在上得到了答案https://social.msdn.microsoft.com/Forums/vstudio/en-US/fb9d15fb-dc9f-488e-92c4-e0bb438442e1/64-bit-dot-net-process-created-with-createprocessasuserw-exits-immediately-with-exception-code?forum=vcgeneral[RLWA32回答了它]启动该进程的方式存在问题。他启动流程的代码如下,并且运行良好。
UINT __stdcall RunProgram(LPVOID pv)
{
WCHAR szTarg32[MAX_PATH] = TARGET32_PATH, szTarg64[MAX_PATH] = TARGET64_PATH;
LPWSTR pszProcess = nullptr;
PWTS_SESSION_INFOW pwsi = NULL;
DWORD dwSession = -1, dwCount = 0;
HANDLE hToken = NULL;
LPVOID lpEnvironment = nullptr;
LPWSTR pszPath = nullptr;
UINT ret = 1;
DWORD dwOpcode = reinterpret_cast<DWORD>(pv);
if (dwOpcode == LAUNCH_X86PROCESS)
pszProcess = szTarg32;
else
pszProcess = szTarg64;
if (!WTSEnumerateSessionsW(WTS_CURRENT_SERVER, 0, 1, &pwsi, &dwCount))
{
Report(L"WTSEnumerateSessions failed with %dn", GetLastError());
return ret;
}
for (DWORD i = 0; i < dwCount; i++)
{
if (pwsi[i].State == WTSActive)
{
dwSession = pwsi[i].SessionId;
break;
}
}
if (dwSession != -1)
{
if (WTSQueryUserToken(dwSession, &hToken))
{
if (CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE))
{
HRESULT hr;
if (SUCCEEDED((hr = SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, hToken, &pszPath))))
{
if (ImpersonateLoggedOnUser(hToken))
{
STARTUPINFOW si = { sizeof si };
PROCESS_INFORMATION pi = {};
if (CreateProcessAsUserW(hToken, pszProcess, nullptr, nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT, lpEnvironment, pszPath, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
Report(L"CreateProcessAsUser started %s, pid is %dn", pszProcess, pi.dwProcessId);
ret = 0;
}
else
Report(L"CreateProcessAsUser failed with %dn", GetLastError());
RevertToSelf();
}
else
Report(L"ImpersonateLoggedOnUser failed with %dn", GetLastError());
}
else
Report(L"SHGetKnownFolderPath failed with 0x%Xn", hr);
}
else
Report(L"CreateEnvironmentBlock failed with %dn", GetLastError());
}
else
Report(L"WTSQueryUserToken failed with %dn", GetLastError());
}
else
Report(L"WTSEnumerateSessions reported no active sessionn");
if (pwsi)
WTSFreeMemory(pwsi);
if (hToken)
CloseHandle(hToken);
if (lpEnvironment)
DestroyEnvironmentBlock(lpEnvironment);
if (pszPath)
CoTaskMemFree(pszPath);
return ret;
}