As @NicholasWilson said, SetThreadDesktop()
is the correct way to switch a process between default desktop and winlogon desktop.
The error 170, "The requested resource is in use", occurred because I called MessageBox()
before SetThreadDesktop()
called. Also calling CreateWindow()
can cause the error.
I think any function associated with GUI creation called before SetThreadDesktop()
called can cause the error. So if you want to invoke SetThreadDesktop()
successfully, you must be sure not to call any GUI creation function before you invoke SetThreadDesktop()
.
Code
Code here is how to switch the process to the specified desktop.
Usage: SetWinSta0Desktop(TEXT("winlogon"))
, SetWinSta0Desktop(TEXT("default"))
SetWinSta0Desktop()
function:
BOOL SetWinSta0Desktop(TCHAR *szDesktopName)
{
BOOL bSuccess = FALSE;
HWINSTA hWinSta0 = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED);
if (NULL == hWinSta0) { ShowLastErrorMessage(GetLastError(), TEXT("OpenWindowStation")); }
bSuccess = SetProcessWindowStation(hWinSta0);
if (!bSuccess) { ShowLastErrorMessage(GetLastError(), TEXT("SetProcessWindowStation")); }
HDESK hDesk = OpenDesktop(szDesktopName, 0, FALSE, MAXIMUM_ALLOWED);
if (NULL == hDesk) { ShowLastErrorMessage(GetLastError(), TEXT("OpenDesktop")); }
bSuccess = SetThreadDesktop(hDesk);
if (!bSuccess) { ShowLastErrorMessage(GetLastError(), TEXT("SetThreadDesktop")); }
if (hDesk != NULL) { CloseDesktop(hDesk); }
if (hWinSta0 != NULL) { CloseWindowStation(hWinSta0); }
return bSuccess;
}
ShowLastErrorMessage()
function:
void ShowLastErrorMessage(DWORD errCode, LPTSTR errTitle)
{
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText,
0,
NULL);
if ( NULL != errorText )
{
WCHAR msg[512] = {0};
wsprintf(msg, TEXT("%s:\nError Code: %u\n%s\n"), errTitle, errCode, errorText);
LocalFree(errorText);
errorText = NULL;
OutputDebugString(msg);
}
}