我有一个 C# 应用程序,它是使用 CreateProcessAsUserW api 从 C++ DLL 启动的。该进程成功启动,但立即终止。它在 Windows 10 [32 位和 64 位] 和 Windows 7 上的 32 位上正常工作。我找到了以下链接,
但是,SysInternals 的进程监视器没有发现丢失的 dll。[我可以从 ProcMon 附加保存的日志] 我还尝试在 API 的 lpCurrentDirectory 参数中按照其他地方的建议将路径传递到应用程序文件夹,但这也不起作用。
我遵循了如何在多个用户在 Windows 中登录时获取活动用户中的指导?编写启动进程的代码,并从 Windows 服务调用启动进程的方法。为了从命令行模拟它,我使用了以下 如何在本地系统帐户下运行 CMD.exe?[psexec64 -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 屏幕截图附在下面请帮助。谢谢,萨加尔
[![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 位启动器进程有什么区别?