任何人都知道为什么在调用EnumDesktopWindows
时返回183此过程是在System LocalService
中运行的服务我试图将窗口置于顶部,因为过程开始最小化。
感谢帮助
我的代码:
BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam )
{
DWORD dwPID;
GetWindowThreadProcessId( hwnd, &dwPID );
if( dwPID == lParam ) {
SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE );
SwitchToThisWindow(hwnd, true);
SetFocus( hwnd );
return FALSE;
}
return TRUE;
}
BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam) {
HDESK hDesk = OpenDesktop(lpszDesktop, NULL, FALSE, GENERIC_ALL);
if(hDesk != NULL) {
if(!EnumDesktopWindows(hDesk,&EnumWindowsProc, lParam)) {
//This call returns (183) Cannot create a file when that file already exists
}
CloseDesktop(hDesk);
}
return TRUE;
}
BOOL CALLBACK EnumWindowStationProc(LPTSTR lpszWindowStation, LPARAM lParam)
{
HWINSTA hWinStat = OpenWindowStation(lpszWindowStation,FALSE,WINSTA_ENUMDESKTOPS|WINSTA_ENUMERATE);
if(hWinStat) {
SetProcessWindowStation(hWinStat);
EnumDesktops(hWinStat,&EnumDesktopProc,lParam);
CloseWindowStation(hWinStat);
}
return TRUE;
}
bool Utils::execIntoDifferentSession(const std::wstring &aPath, const std::wstring &aParams, const std::wstring &aMode)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL bResult = FALSE;
DWORD dwSessionId,winlogonPid;
HANDLE hUserToken,hUserTokenDup,hPToken,hProcess;
DWORD dwCreationFlags;
// Log the client on to the local computer.
dwSessionId = WTSGetActiveConsoleSessionId();
//////////////////////////////////////////
// Find the winlogon process
////////////////////////////////////////
PROCESSENTRY32 procEntry;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
return false;
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &procEntry))
return false;
do {
if (_wcsicmp(procEntry.szExeFile, L"winlogon.exe") == 0) {
// We found a winlogon process...make sure it's running in the console session
DWORD winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId) {
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry));
WTSQueryUserToken(dwSessionId,&hUserToken);
dwCreationFlags = NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb= sizeof(STARTUPINFO);
si.lpDesktop = L"winsta0\\default";
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL|SW_RESTORE;
ZeroMemory(&pi, sizeof(pi));
TOKEN_PRIVILEGES tp;
LUID luid;
hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);
if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
|TOKEN_READ|TOKEN_WRITE,&hPToken))
{
return false;
}
if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
return false;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
//Adjust Token privilege
SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD));
if (!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL))
return false;
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
return false;
LPVOID pEnv = NULL;
if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
else
pEnv = NULL;
// Launch the process in the client's logon session.
std::wstring params = aParams;
std::wstring path = aPath;
if(aMode == L"select") {
TCHAR infoBuffer[MAX_PATH];
GetSystemWindowsDirectory(infoBuffer, MAX_PATH);
std::wstring windowsDir(infoBuffer);
path = windowsDir+L"\\explorer.exe";
params = L" /n, /select,"+replaceString(aPath, L"\\\\", L"\\");
}
bResult = CreateProcessAsUser(
hUserTokenDup, // client's access token
path.c_str(), // file to execute
params.length() > 0 ? stringToLPWSTR(wideToUtf8(params)) : NULL, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
EnumWindowStations(&EnumWindowStationProc, (LPARAM)(pi.dwProcessId));
// End impersonation of client.
//GetLastError Shud be 0
int rv = GetLastError();
//Perform All the Close Handles task
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hUserTokenDup);
CloseHandle(hPToken);
return !rv;
}
答案 0 :(得分:1)
错误183是ERROR_ALREADY_EXISTS
。 EnumDesktopWindows()
未设置该错误,因此它必须是早期API调用的结转。如果您阅读文档说明:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682615.aspx
如果失败,您必须确保回调函数设置SetLastError。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682614.aspx
如果回调函数失败,则返回值为零。回调函数可以调用SetLastError来设置错误代码,以便调用者通过调用GetLastError来检索。
所以尝试更像这样的东西:
struct WndInfo
{
DWORD dwProcessID;
HWND hWnd;
};
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
WndInfo *pInfo = (WndInfo*) lParam;
DWORD dwPID;
GetWindowThreadProcessId(hwnd, &dwPID);
if (dwPID == pInfo->dwProcessID)
{
pInfo->hWnd = hwnd;
SetLastError(0);
return FALSE;
}
return TRUE;
}
BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam)
{
HDESK hDesk = OpenDesktop(lpszDesktop, NULL, FALSE, GENERIC_ALL);
if (hDesk != NULL)
{
if (!EnumDesktopWindows(hDesk, &EnumWindowsProc, lParam))
{
if (GetLastError() != 0)
{
// handle error as needed...
}
}
CloseDesktop(hDesk);
WndInfo *pInfo = (WndInfo*) lParam;
if (pInfo->hWnd != NULL)
{
SetLastError(0);
return FALSE;
}
}
return TRUE;
}
BOOL CALLBACK EnumWindowStationProc(LPTSTR lpszWindowStation, LPARAM lParam)
{
HWINSTA hWinStat = OpenWindowStation(lpszWindowStation, FALSE, WINSTA_ENUMDESKTOPS|WINSTA_ENUMERATE);
if (hWinStat != NULL)
{
SetProcessWindowStation(hWinStat);
if (!EnumDesktops(hWinStat, &EnumDesktopProc, lParam))
{
if (GetLastError() != 0)
{
// handle error as needed...
}
}
CloseWindowStation(hWinStat);
WndInfo *pInfo = (WndInfo*) lParam;
if (pInfo->hWnd != NULL)
{
SetLastError(0);
return FALSE;
}
}
return TRUE;
}
HWND findWindowForProcess(DWORD PID)
{
WndInfo info;
info.dwProcessID = PID;
info.hWnd = NULL;
if (!EnumWindowStations(&EnumWindowStationProc, (LPARAM)&info))
{
if (GetLastError() != 0)
{
// handle error as needed...
}
}
return info.hWnd;
}
bool Utils::execIntoDifferentSession(const std::wstring &aPath, const std::wstring &aParams, const std::wstring &aMode)
{
...
bResult = CreateProcessAsUser(...);
if (bResult)
{
HWND hWnd = findWindowForProcess(pi.dwProcessId);
if (hWnd != NULL)
{
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
SwitchToThisWindow(hWnd, TRUE);
SetFocus(hWnd);
}
}
...
}
话虽如此,因为你真正想要做的就是在特定的用户会话中执行一个新的过程,你不需要为所有的枚举逻辑而烦恼。您根本不需要找到WinLogon进程,您已经拥有来自WTSQueryUserToken()
的用户令牌,因此只需复制+根据需要调整该令牌。并且你没有在窗口枚举中做任何有用的事情,新进程在启动时默认不会这样做,所以也要摆脱那个逻辑。
然后最后修复你的错误处理(或缺少),这样你就可以关闭任何打开的句柄而不会泄漏它们。