static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp) { HWINSTA hwinsta; trace("open_window_station_callbackA called with argument %s\n", winsta); hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE); ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta); if (hwinsta) CloseWindowStation(hwinsta); return lp; }
static void test_handles(void) { HWINSTA w1, w2, w3; HDESK d1, d2, d3; HANDLE hthread; DWORD id, flags, le; ATOM atom; char buffer[20]; /* win stations */ w1 = GetProcessWindowStation(); ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" ); ok( !CloseWindowStation(w1), "closing process win station succeeded\n" ); SetLastError( 0xdeadbeef ); ok( !CloseHandle(w1), "closing process win station handle succeeded\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); print_object( w1 ); flags = 0; ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" ); ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) || broken(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), /* set on nt4 */ "handle %p PROTECT_FROM_CLOSE set\n", w1 ); ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0, TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); ok( CloseWindowStation(w2), "closing dup win station failed\n" ); ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0, TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); ok( CloseHandle(w2), "closing dup win station handle failed\n" ); w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL ); le = GetLastError(); ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", le ); if (w2 != 0) { ok( w2 != w1, "CreateWindowStation returned default handle\n" ); SetLastError( 0xdeadbeef ); ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */ "bad last error %d\n", GetLastError() ); ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL ); ok( CloseHandle( w2 ), "CloseHandle failed\n" ); } else if (le == ERROR_ACCESS_DENIED) win_skip( "Not enough privileges for CreateWindowStation\n" ); w2 = OpenWindowStationA("winsta0", TRUE, WINSTA_ALL_ACCESS ); ok( w2 != 0, "OpenWindowStation failed\n" ); ok( w2 != w1, "OpenWindowStation returned default handle\n" ); ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); w2 = OpenWindowStationA("dummy name", TRUE, WINSTA_ALL_ACCESS ); ok( !w2, "open dummy win station succeeded\n" ); CreateMutexA( NULL, 0, "foobar" ); w2 = CreateWindowStationA("foobar", 0, WINSTA_ALL_ACCESS, NULL ); le = GetLastError(); ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "create foobar station failed (%u)\n", le ); if (w2 != 0) { w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS ); ok( w3 != 0, "open foobar station failed\n" ); ok( w3 != w2, "open foobar station returned same handle\n" ); ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" ); w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS ); ok( !w3, "open foobar station succeeded\n" ); w2 = CreateWindowStationA("foobar1", 0, WINSTA_ALL_ACCESS, NULL ); ok( w2 != 0, "create foobar station failed\n" ); w3 = CreateWindowStationA("foobar2", 0, WINSTA_ALL_ACCESS, NULL ); ok( w3 != 0, "create foobar station failed\n" ); ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" ); ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" ); SetProcessWindowStation( w2 ); atom = GlobalAddAtomA("foo"); ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" ); ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer ); ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" ); ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" ); SetProcessWindowStation( w3 ); ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" ); ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" ); ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer ); } else if (le == ERROR_ACCESS_DENIED) win_skip( "Not enough privileges for CreateWindowStation\n" ); /* desktops */ d1 = GetThreadDesktop(GetCurrentThreadId()); initial_desktop = d1; ok( GetThreadDesktop(GetCurrentThreadId()) == d1, "GetThreadDesktop returned different handles\n" ); flags = 0; ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" ); ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 ); SetLastError( 0xdeadbeef ); ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" ); ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ "bad last error %d\n", GetLastError() ); SetLastError( 0xdeadbeef ); if (CloseHandle( d1 )) /* succeeds on nt4 */ { win_skip( "NT4 desktop handle management is completely different\n" ); return; } ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0, TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); ok( CloseDesktop(d2), "closing dup desktop failed\n" ); ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0, TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); ok( CloseHandle(d2), "closing dup desktop handle failed\n" ); d2 = OpenDesktopA( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS ); ok( !d2, "open dummy desktop succeeded\n" ); d2 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); ok( d2 != 0, "create foobar desktop failed\n" ); SetLastError( 0xdeadbeef ); ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */ "bad last error %d\n", GetLastError() ); SetLastError( 0xdeadbeef ); d3 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); ok( d3 != 0, "create foobar desktop again failed\n" ); ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() ); ok( CloseDesktop( d3 ), "CloseDesktop failed\n" ); d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS ); ok( d3 != 0, "open foobar desktop failed\n" ); ok( d3 != d2, "open foobar desktop returned same handle\n" ); ok( CloseDesktop( d2 ), "CloseDesktop failed\n" ); ok( CloseDesktop( d3 ), "CloseDesktop failed\n" ); d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS ); ok( !d3, "open foobar desktop succeeded\n" ); ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" ); d2 = GetThreadDesktop(GetCurrentThreadId()); ok( d1 == d2, "got different handles after close\n" ); register_class(); trace( "thread 1 desktop: %p\n", d1 ); print_object( d1 ); hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id ); Sleep(1000); trace( "get other thread desktop: %p\n", GetThreadDesktop(id) ); WaitForSingleObject( hthread, INFINITE ); CloseHandle( hthread ); /* clean side effect */ SetProcessWindowStation( w1 ); }
/* * Take a screenshot of this sessions default input desktop on WinSta0 * and send it as a JPEG image to a named pipe. */ DWORD screenshot( int quality, DWORD dwPipeName ) { DWORD dwResult = ERROR_ACCESS_DENIED; HWINSTA hWindowStation = NULL; HWINSTA hOrigWindowStation = NULL; HDESK hInputDesktop = NULL; HDESK hOrigDesktop = NULL; HWND hDesktopWnd = NULL; HDC hdc = NULL; HDC hmemdc = NULL; HBITMAP hbmp = NULL; BYTE * pJpegBuffer = NULL; OSVERSIONINFO os = {0}; char cNamedPipe[MAX_PATH] = {0}; // If we use SM_C[X|Y]VIRTUALSCREEN we can screenshot the whole desktop of a multi monitor display. int xmetric = SM_CXVIRTUALSCREEN; int ymetric = SM_CYVIRTUALSCREEN; DWORD dwJpegSize = 0; int sx = 0; int sy = 0; do { _snprintf_s( cNamedPipe, sizeof(cNamedPipe), MAX_PATH, "\\\\.\\pipe\\%08X", dwPipeName ); os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); if( !GetVersionEx( &os ) ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot: GetVersionEx failed" ) // On NT we cant use SM_CXVIRTUALSCREEN/SM_CYVIRTUALSCREEN. if( os.dwMajorVersion <= 4 ) { xmetric = SM_CXSCREEN; ymetric = SM_CYSCREEN; } // open the WinSta0 as some services are attached to a different window station. hWindowStation = OpenWindowStationA( "WinSta0", FALSE, WINSTA_ALL_ACCESS ); if( !hWindowStation ) { if( RevertToSelf() ) hWindowStation = OpenWindowStationA( "WinSta0", FALSE, WINSTA_ALL_ACCESS ); } // if we cant open the defaut input station we wont be able to take a screenshot if( !hWindowStation ) BREAK_WITH_ERROR( "[SCREENSHOT] screenshot: Couldnt get the WinSta0 Window Station", ERROR_INVALID_HANDLE ); // get the current process's window station so we can restore it later on. hOrigWindowStation = GetProcessWindowStation(); // set the host process's window station to this sessions default input station we opened if( !SetProcessWindowStation( hWindowStation ) ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot: SetProcessWindowStation failed" ); // grab a handle to the default input desktop (e.g. Default or WinLogon) hInputDesktop = OpenInputDesktop( 0, FALSE, MAXIMUM_ALLOWED ); if( !hInputDesktop ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot: OpenInputDesktop failed" ); // get the threads current desktop so we can restore it later on hOrigDesktop = GetThreadDesktop( GetCurrentThreadId() ); // set this threads desktop to that of this sessions default input desktop on WinSta0 SetThreadDesktop( hInputDesktop ); // and now we can grab a handle to this input desktop hDesktopWnd = GetDesktopWindow(); // and get a DC from it so we can read its pixels! hdc = GetDC( hDesktopWnd ); if( !hdc ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot. GetDC failed" ); // back up this DC with a memory DC hmemdc = CreateCompatibleDC( hdc ); if( !hmemdc ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot. CreateCompatibleDC failed" ); // calculate the width and height sx = GetSystemMetrics( xmetric ); sy = GetSystemMetrics( ymetric ); // and create a bitmap hbmp = CreateCompatibleBitmap( hdc, sx, sy ); if( !hbmp ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot. CreateCompatibleBitmap failed" ); // this bitmap is backed by the memory DC if( !SelectObject( hmemdc, hbmp ) ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot. SelectObject failed" ); // BitBlt the screenshot of this sessions default input desktop on WinSta0 onto the memory DC we created if( !BitBlt( hmemdc, 0, 0, sx, sy, hdc, 0, 0, SRCCOPY ) ) BREAK_ON_ERROR( "[SCREENSHOT] screenshot. BitBlt failed" ); // finally convert the BMP we just made into a JPEG... if( bmp2jpeg( hbmp, hmemdc, quality, &pJpegBuffer, &dwJpegSize ) != 1 ) BREAK_WITH_ERROR( "[SCREENSHOT] screenshot. bmp2jpeg failed", ERROR_INVALID_HANDLE ); // we have succeded dwResult = ERROR_SUCCESS; } while( 0 ); // if we have successfully taken a screenshot we send it back via the named pipe // but if we have failed we send back a zero byte result to indicate this failure. if( dwResult == ERROR_SUCCESS ) screenshot_send( cNamedPipe, pJpegBuffer, dwJpegSize ); else screenshot_send( cNamedPipe, NULL, 0 ); if( hdc ) ReleaseDC( hDesktopWnd, hdc ); if( hmemdc ) DeleteDC( hmemdc ); if( hbmp ) DeleteObject( hbmp ); // free the jpeg images buffer if( pJpegBuffer ) free( pJpegBuffer ); // restore the origional process's window station if( hOrigWindowStation ) SetProcessWindowStation( hOrigWindowStation ); // restore the threads origional desktop if( hOrigDesktop ) SetThreadDesktop( hOrigDesktop ); // close the WinSta0 window station handle we opened if( hWindowStation ) CloseWindowStation( hWindowStation ); // close this last to avoid a handle leak... if( hInputDesktop ) CloseDesktop( hInputDesktop ); return dwResult; }