1 /* 2 * Unit tests for window stations and desktops 3 * 4 * Copyright 2002 Alexandre Julliard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "wine/test.h" 22 #include "winbase.h" 23 #include "wingdi.h" 24 #include "winuser.h" 25 #include "winnls.h" 26 #include "wine/winternl.h" 27 28 static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG); 29 30 #define DESKTOP_ALL_ACCESS 0x01ff 31 32 static void print_object( HANDLE obj ) 33 { 34 char buffer[100]; 35 DWORD size; 36 37 strcpy( buffer, "foobar" ); 38 if (!GetUserObjectInformationA( obj, UOI_NAME, buffer, sizeof(buffer), &size )) 39 trace( "could not get info for %p\n", obj ); 40 else 41 trace( "obj %p name '%s'\n", obj, buffer ); 42 strcpy( buffer, "foobar" ); 43 if (!GetUserObjectInformationA( obj, UOI_TYPE, buffer, sizeof(buffer), &size )) 44 trace( "could not get type for %p\n", obj ); 45 else 46 trace( "obj %p type '%s'\n", obj, buffer ); 47 } 48 49 static void register_class(void) 50 { 51 WNDCLASSA cls; 52 53 cls.style = CS_DBLCLKS; 54 cls.lpfnWndProc = DefWindowProcA; 55 cls.cbClsExtra = 0; 56 cls.cbWndExtra = 0; 57 cls.hInstance = GetModuleHandleA(0); 58 cls.hIcon = 0; 59 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 60 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 61 cls.lpszMenuName = NULL; 62 cls.lpszClassName = "WinStationClass"; 63 RegisterClassA(&cls); 64 } 65 66 static HDESK initial_desktop; 67 68 static DWORD CALLBACK thread( LPVOID arg ) 69 { 70 HDESK d1, d2; 71 HWND hwnd = CreateWindowExA(0,"WinStationClass","test",WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0); 72 ok( hwnd != 0, "CreateWindow failed\n" ); 73 d1 = GetThreadDesktop(GetCurrentThreadId()); 74 trace( "thread %p desktop: %p\n", arg, d1 ); 75 ok( d1 == initial_desktop, "thread %p doesn't use initial desktop\n", arg ); 76 77 SetLastError( 0xdeadbeef ); 78 ok( !CloseHandle( d1 ), "CloseHandle succeeded\n" ); 79 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); 80 SetLastError( 0xdeadbeef ); 81 ok( !CloseDesktop( d1 ), "CloseDesktop succeeded\n" ); 82 ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ 83 "bad last error %d\n", GetLastError() ); 84 print_object( d1 ); 85 d2 = CreateDesktopA( "foobar2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); 86 trace( "created desktop %p\n", d2 ); 87 ok( d2 != 0, "CreateDesktop failed\n" ); 88 89 SetLastError( 0xdeadbeef ); 90 ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" ); 91 ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ 92 "bad last error %d\n", GetLastError() ); 93 94 DestroyWindow( hwnd ); 95 ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" ); 96 d1 = GetThreadDesktop(GetCurrentThreadId()); 97 ok( d1 == d2, "GetThreadDesktop did not return set desktop %p/%p\n", d1, d2 ); 98 print_object( d2 ); 99 if (arg < (LPVOID)5) 100 { 101 HANDLE hthread = CreateThread( NULL, 0, thread, (char *)arg + 1, 0, NULL ); 102 Sleep(1000); 103 WaitForSingleObject( hthread, INFINITE ); 104 CloseHandle( hthread ); 105 } 106 return 0; 107 } 108 109 static void test_handles(void) 110 { 111 HWINSTA w1, w2, w3; 112 HDESK d1, d2, d3; 113 HANDLE hthread; 114 DWORD id, flags, le; 115 ATOM atom; 116 char buffer[20]; 117 DWORD size; 118 BOOL ret; 119 120 /* win stations */ 121 122 w1 = GetProcessWindowStation(); 123 ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" ); 124 ok( !CloseWindowStation(w1), "closing process win station succeeded\n" ); 125 SetLastError( 0xdeadbeef ); 126 ok( !CloseHandle(w1), "closing process win station handle succeeded\n" ); 127 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); 128 print_object( w1 ); 129 130 flags = 0; 131 ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" ); 132 ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) || 133 broken(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), /* set on nt4 */ 134 "handle %p PROTECT_FROM_CLOSE set\n", w1 ); 135 136 ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0, 137 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); 138 ok( CloseWindowStation(w2), "closing dup win station failed\n" ); 139 140 ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0, 141 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); 142 ok( CloseHandle(w2), "closing dup win station handle failed\n" ); 143 144 w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL ); 145 le = GetLastError(); 146 ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", le ); 147 if (w2 != 0) 148 { 149 ok( w2 != w1, "CreateWindowStation returned default handle\n" ); 150 SetLastError( 0xdeadbeef ); 151 ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" ); 152 ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */ 153 "bad last error %d\n", GetLastError() ); 154 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); 155 156 w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL ); 157 ok( CloseHandle( w2 ), "CloseHandle failed\n" ); 158 } 159 else if (le == ERROR_ACCESS_DENIED) 160 win_skip( "Not enough privileges for CreateWindowStation\n" ); 161 162 w2 = OpenWindowStationA("winsta0", TRUE, WINSTA_ALL_ACCESS ); 163 ok( w2 != 0, "OpenWindowStation failed\n" ); 164 ok( w2 != w1, "OpenWindowStation returned default handle\n" ); 165 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); 166 167 w2 = OpenWindowStationA("dummy name", TRUE, WINSTA_ALL_ACCESS ); 168 ok( !w2, "open dummy win station succeeded\n" ); 169 170 CreateMutexA( NULL, 0, "foobar" ); 171 w2 = CreateWindowStationA("foobar", 0, WINSTA_ALL_ACCESS, NULL ); 172 le = GetLastError(); 173 ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "create foobar station failed (%u)\n", le ); 174 175 if (w2 != 0) 176 { 177 w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS ); 178 ok( w3 != 0, "open foobar station failed\n" ); 179 ok( w3 != w2, "open foobar station returned same handle\n" ); 180 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); 181 ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" ); 182 183 w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS ); 184 ok( !w3, "open foobar station succeeded\n" ); 185 186 w2 = CreateWindowStationA("foobar1", 0, WINSTA_ALL_ACCESS, NULL ); 187 ok( w2 != 0, "create foobar station failed\n" ); 188 w3 = CreateWindowStationA("foobar2", 0, WINSTA_ALL_ACCESS, NULL ); 189 ok( w3 != 0, "create foobar station failed\n" ); 190 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" ); 191 ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" ); 192 193 SetProcessWindowStation( w2 ); 194 atom = GlobalAddAtomA("foo"); 195 ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" ); 196 ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer ); 197 198 ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" ); 199 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" ); 200 201 SetProcessWindowStation( w3 ); 202 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" ); 203 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); 204 ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" ); 205 ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer ); 206 } 207 else if (le == ERROR_ACCESS_DENIED) 208 win_skip( "Not enough privileges for CreateWindowStation\n" ); 209 210 SetLastError( 0xdeadbeef ); 211 w2 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS ); 212 ok( !w2, "open station succeeded\n" ); 213 todo_wine 214 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError() ); 215 216 SetLastError( 0xdeadbeef ); 217 w2 = CreateWindowStationA( "", 0, WINSTA_ALL_ACCESS, NULL ); 218 ok( w2 != 0, "create station failed err %u\n", GetLastError() ); 219 220 memset( buffer, 0, sizeof(buffer) ); 221 ret = GetUserObjectInformationA( w2, UOI_NAME, buffer, sizeof(buffer), &size ); 222 ok( ret, "GetUserObjectInformationA failed with error %u\n", GetLastError() ); 223 ok( !memcmp(buffer, "Service-0x0-", 12), "unexpected window station name '%s'\n", buffer ); 224 ok( buffer[strlen(buffer) - 1] == '$', "unexpected window station name '%s'\n", buffer ); 225 226 SetLastError( 0xdeadbeef ); 227 w3 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS ); 228 todo_wine 229 ok( w3 != 0, "open station failed err %u\n", GetLastError() ); 230 CloseWindowStation( w3 ); 231 CloseWindowStation( w2 ); 232 233 SetLastError( 0xdeadbeef ); 234 w2 = CreateWindowStationA( "foo\\bar", 0, WINSTA_ALL_ACCESS, NULL ); 235 ok( !w2, "create station succeeded\n" ); 236 ok( GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED, 237 "wrong error %u\n", GetLastError() ); 238 239 SetLastError( 0xdeadbeef ); 240 w2 = OpenWindowStationA( "foo\\bar", TRUE, WINSTA_ALL_ACCESS ); 241 ok( !w2, "create station succeeded\n" ); 242 ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %u\n", GetLastError() ); 243 244 /* desktops */ 245 d1 = GetThreadDesktop(GetCurrentThreadId()); 246 initial_desktop = d1; 247 ok( GetThreadDesktop(GetCurrentThreadId()) == d1, 248 "GetThreadDesktop returned different handles\n" ); 249 250 flags = 0; 251 ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" ); 252 ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 ); 253 254 SetLastError( 0xdeadbeef ); 255 ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" ); 256 ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ 257 "bad last error %d\n", GetLastError() ); 258 259 SetLastError( 0xdeadbeef ); 260 if (CloseHandle( d1 )) /* succeeds on nt4 */ 261 { 262 win_skip( "NT4 desktop handle management is completely different\n" ); 263 return; 264 } 265 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); 266 267 ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0, 268 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); 269 ok( CloseDesktop(d2), "closing dup desktop failed\n" ); 270 271 ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0, 272 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); 273 ok( CloseHandle(d2), "closing dup desktop handle failed\n" ); 274 275 d2 = OpenDesktopA( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS ); 276 ok( !d2, "open dummy desktop succeeded\n" ); 277 278 SetLastError( 0xdeadbeef ); 279 d2 = CreateDesktopA( "", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); 280 todo_wine 281 ok( !d2, "create empty desktop succeeded\n" ); 282 todo_wine 283 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); 284 285 SetLastError( 0xdeadbeef ); 286 d2 = OpenDesktopA( "", 0, TRUE, DESKTOP_ALL_ACCESS ); 287 ok( !d2, "open empty desktop succeeded\n" ); 288 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); 289 290 SetLastError( 0xdeadbeef ); 291 d2 = CreateDesktopA( "foo\\bar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); 292 ok( !d2, "create desktop succeeded\n" ); 293 ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() ); 294 295 SetLastError( 0xdeadbeef ); 296 d2 = OpenDesktopA( "foo\\bar", 0, TRUE, DESKTOP_ALL_ACCESS ); 297 ok( !d2, "open desktop succeeded\n" ); 298 ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() ); 299 300 d2 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); 301 ok( d2 != 0, "create foobar desktop failed\n" ); 302 SetLastError( 0xdeadbeef ); 303 ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" ); 304 ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */ 305 "bad last error %d\n", GetLastError() ); 306 307 SetLastError( 0xdeadbeef ); 308 d3 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); 309 ok( d3 != 0, "create foobar desktop again failed\n" ); 310 ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() ); 311 ok( CloseDesktop( d3 ), "CloseDesktop failed\n" ); 312 313 d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS ); 314 ok( d3 != 0, "open foobar desktop failed\n" ); 315 ok( d3 != d2, "open foobar desktop returned same handle\n" ); 316 ok( CloseDesktop( d2 ), "CloseDesktop failed\n" ); 317 ok( CloseDesktop( d3 ), "CloseDesktop failed\n" ); 318 319 d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS ); 320 ok( !d3, "open foobar desktop succeeded\n" ); 321 322 ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" ); 323 d2 = GetThreadDesktop(GetCurrentThreadId()); 324 ok( d1 == d2, "got different handles after close\n" ); 325 326 register_class(); 327 trace( "thread 1 desktop: %p\n", d1 ); 328 print_object( d1 ); 329 hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id ); 330 Sleep(1000); 331 trace( "get other thread desktop: %p\n", GetThreadDesktop(id) ); 332 WaitForSingleObject( hthread, INFINITE ); 333 CloseHandle( hthread ); 334 335 /* clean side effect */ 336 SetProcessWindowStation( w1 ); 337 } 338 339 /* Enumeration tests */ 340 341 static BOOL CALLBACK window_station_callbackA(LPSTR winsta, LPARAM lp) 342 { 343 trace("window_station_callbackA called with argument %s\n", winsta); 344 return lp; 345 } 346 347 static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp) 348 { 349 HWINSTA hwinsta; 350 351 trace("open_window_station_callbackA called with argument %s\n", winsta); 352 hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE); 353 ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta); 354 if (hwinsta) 355 CloseWindowStation(hwinsta); 356 return lp; 357 } 358 359 static void test_enumstations(void) 360 { 361 DWORD ret; 362 HWINSTA hwinsta; 363 364 if (0) /* Crashes instead */ 365 { 366 SetLastError(0xbabefeed); 367 ret = EnumWindowStationsA(NULL, 0); 368 ok(!ret, "EnumWindowStationsA returned successfully!\n"); 369 ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError()); 370 } 371 372 hwinsta = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL); 373 ret = GetLastError(); 374 ok(hwinsta != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret); 375 if (!hwinsta) 376 { 377 win_skip("Not enough privileges for CreateWindowStation\n"); 378 return; 379 } 380 381 SetLastError(0xdeadbeef); 382 ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345); 383 ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret); 384 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 385 386 SetLastError(0xdeadbeef); 387 ret = EnumWindowStationsA(window_station_callbackA, 0); 388 ok(!ret, "EnumWindowStationsA returned %x\n", ret); 389 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 390 } 391 392 static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp) 393 { 394 trace("desktop_callbackA called with argument %s\n", desktop); 395 return lp; 396 } 397 398 static BOOL CALLBACK open_desktop_callbackA(LPSTR desktop, LPARAM lp) 399 { 400 HDESK hdesk; 401 static int once; 402 403 trace("open_desktop_callbackA called with argument %s\n", desktop); 404 /* Only try to open one desktop */ 405 if (once++) 406 return lp; 407 408 hdesk = OpenDesktopA(desktop, 0, FALSE, DESKTOP_ENUMERATE); 409 ok(hdesk != NULL, "Could not open desktop %s!\n", desktop); 410 if (hdesk) 411 CloseDesktop(hdesk); 412 return lp; 413 } 414 415 static void test_enumdesktops(void) 416 { 417 BOOL ret; 418 419 if (0) /* Crashes instead */ 420 { 421 SetLastError(0xbabefeed); 422 ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0); 423 ok(!ret, "EnumDesktopsA returned successfully!\n"); 424 ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError()); 425 } 426 427 SetLastError(0xdeadbeef); 428 ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345); 429 ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret); 430 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 431 432 SetLastError(0xdeadbeef); 433 ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345); 434 ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret); 435 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 436 437 SetLastError(0xdeadbeef); 438 ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345); 439 ok(!ret, "EnumDesktopsA returned %x\n", ret); 440 ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError()); 441 442 SetLastError(0xdeadbeef); 443 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0); 444 ok(!ret, "EnumDesktopsA returned %x\n", ret); 445 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 446 } 447 448 /* Miscellaneous tests */ 449 450 static void test_getuserobjectinformation(void) 451 { 452 WCHAR foobarTestW[] = {'\\','f','o','o','b','a','r','T','e','s','t',0}; 453 WCHAR DesktopW[] = {'D','e','s','k','t','o','p',0}; 454 OBJECT_NAME_INFORMATION *name_info; 455 WCHAR bufferW[20]; 456 char buffer[64]; 457 NTSTATUS status; 458 DWORD size; 459 HDESK desk; 460 BOOL ret; 461 462 desk = CreateDesktopA("foobarTest", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL); 463 ok(desk != 0, "open foobarTest desktop failed\n"); 464 465 strcpy(buffer, "blahblah"); 466 467 /** Tests for UOI_NAME **/ 468 469 /* Get size, test size and return value/error code */ 470 SetLastError(0xdeadbeef); 471 size = 0xdeadbeef; 472 ret = GetUserObjectInformationA(desk, UOI_NAME, NULL, 0, &size); 473 474 ok(!ret, "GetUserObjectInformationA returned %x\n", ret); 475 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); 476 ok(size == 22, "size is set to %d\n", size); /* Windows returns Unicode length (11*2) */ 477 478 /* Get string */ 479 SetLastError(0xdeadbeef); 480 size = 0xdeadbeef; 481 ret = GetUserObjectInformationA(desk, UOI_NAME, buffer, sizeof(buffer), &size); 482 483 ok(ret, "GetUserObjectInformationA returned %x\n", ret); 484 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 485 486 ok(strcmp(buffer, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer); 487 ok(size == 11, "size is set to %d\n", size); /* 11 bytes in 'foobarTest\0' */ 488 489 /* Get size, test size and return value/error code (Unicode) */ 490 SetLastError(0xdeadbeef); 491 size = 0xdeadbeef; 492 ret = GetUserObjectInformationW(desk, UOI_NAME, NULL, 0, &size); 493 494 ok(!ret, "GetUserObjectInformationW returned %x\n", ret); 495 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); 496 ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */ 497 498 /* Get string (Unicode) */ 499 SetLastError(0xdeadbeef); 500 size = 0xdeadbeef; 501 ret = GetUserObjectInformationW(desk, UOI_NAME, bufferW, sizeof(bufferW), &size); 502 503 ok(ret, "GetUserObjectInformationW returned %x\n", ret); 504 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 505 506 ok(lstrcmpW(bufferW, foobarTestW + 1) == 0, "Buffer is not set to 'foobarTest'\n"); 507 ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */ 508 509 /* ObjectNameInformation does not return the full desktop name */ 510 name_info = (OBJECT_NAME_INFORMATION *)buffer; 511 status = pNtQueryObject(desk, ObjectNameInformation, name_info, sizeof(buffer), NULL); 512 ok(!status, "expected STATUS_SUCCESS, got %08x\n", status); 513 ok(lstrcmpW(name_info->Name.Buffer, foobarTestW) == 0, 514 "expected '\\foobarTest', got %s\n", wine_dbgstr_w(name_info->Name.Buffer)); 515 516 /** Tests for UOI_TYPE **/ 517 518 /* Get size, test size and return value/error code */ 519 SetLastError(0xdeadbeef); 520 size = 0xdeadbeef; 521 ret = GetUserObjectInformationA(desk, UOI_TYPE, NULL, 0, &size); 522 523 ok(!ret, "GetUserObjectInformationA returned %x\n", ret); 524 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); 525 ok(size == 16, "size is set to %d\n", size); /* Windows returns Unicode length (8*2) */ 526 527 /* Get string */ 528 SetLastError(0xdeadbeef); 529 size = 0xdeadbeef; 530 ret = GetUserObjectInformationA(desk, UOI_TYPE, buffer, sizeof(buffer), &size); 531 532 ok(ret, "GetUserObjectInformationA returned %x\n", ret); 533 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 534 535 ok(strcmp(buffer, "Desktop") == 0, "Buffer is set to '%s'\n", buffer); 536 ok(size == 8, "size is set to %d\n", size); /* 8 bytes in 'Desktop\0' */ 537 538 /* Get size, test size and return value/error code (Unicode) */ 539 size = 0xdeadbeef; 540 SetLastError(0xdeadbeef); 541 ret = GetUserObjectInformationW(desk, UOI_TYPE, NULL, 0, &size); 542 543 ok(!ret, "GetUserObjectInformationW returned %x\n", ret); 544 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); 545 ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */ 546 547 /* Get string (Unicode) */ 548 SetLastError(0xdeadbeef); 549 size = 0xdeadbeef; 550 ret = GetUserObjectInformationW(desk, UOI_TYPE, bufferW, sizeof(bufferW), &size); 551 552 ok(ret, "GetUserObjectInformationW returned %x\n", ret); 553 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); 554 555 ok(lstrcmpW(bufferW, DesktopW) == 0, "Buffer is not set to 'Desktop'\n"); 556 ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */ 557 558 ok(CloseDesktop(desk), "CloseDesktop failed\n"); 559 } 560 561 static void test_inputdesktop(void) 562 { 563 HDESK input_desk, old_input_desk, thread_desk, old_thread_desk, new_desk; 564 DWORD ret; 565 CHAR name[1024]; 566 INPUT inputs[1]; 567 568 inputs[0].type = INPUT_KEYBOARD; 569 U(inputs[0]).ki.wVk = 0; 570 U(inputs[0]).ki.wScan = 0x3c0; 571 U(inputs[0]).ki.dwFlags = KEYEVENTF_UNICODE; 572 573 /* OpenInputDesktop creates new handles for each calls */ 574 old_input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); 575 ok(old_input_desk != NULL, "OpenInputDesktop failed!\n"); 576 memset(name, 0, sizeof(name)); 577 ret = GetUserObjectInformationA(old_input_desk, UOI_NAME, name, 1024, NULL); 578 ok(ret, "GetUserObjectInformation failed!\n"); 579 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); 580 581 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); 582 ok(input_desk != NULL, "OpenInputDesktop failed!\n"); 583 memset(name, 0, sizeof(name)); 584 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL); 585 ok(ret, "GetUserObjectInformation failed!\n"); 586 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); 587 588 ok(old_input_desk != input_desk, "returned the same handle!\n"); 589 ret = CloseDesktop(input_desk); 590 ok(ret, "CloseDesktop failed!\n"); 591 592 /* by default, GetThreadDesktop is the input desktop, SendInput should succeed. */ 593 old_thread_desk = GetThreadDesktop(GetCurrentThreadId()); 594 ok(old_thread_desk != NULL, "GetThreadDesktop faile!\n"); 595 memset(name, 0, sizeof(name)); 596 ret = GetUserObjectInformationA(old_thread_desk, UOI_NAME, name, 1024, NULL); 597 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); 598 599 SetLastError(0xdeadbeef); 600 ret = SendInput(1, inputs, sizeof(INPUT)); 601 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); 602 ok(ret == 1, "unexpected return count %d\n", ret); 603 604 /* Set thread desktop to the new desktop, SendInput should fail. */ 605 new_desk = CreateDesktopA("new_desk", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL); 606 ok(new_desk != NULL, "CreateDesktop failed!\n"); 607 ret = SetThreadDesktop(new_desk); 608 ok(ret, "SetThreadDesktop failed!\n"); 609 thread_desk = GetThreadDesktop(GetCurrentThreadId()); 610 ok(thread_desk == new_desk, "thread desktop doesn't match!\n"); 611 memset(name, 0, sizeof(name)); 612 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL); 613 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name); 614 615 SetLastError(0xdeadbeef); 616 ret = SendInput(1, inputs, sizeof(INPUT)); 617 if(broken(GetLastError() == 0xdeadbeef)) 618 { 619 SetThreadDesktop(old_thread_desk); 620 CloseDesktop(old_input_desk); 621 CloseDesktop(input_desk); 622 CloseDesktop(new_desk); 623 win_skip("Skip tests on NT4\n"); 624 return; 625 } 626 todo_wine 627 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError()); 628 ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret); 629 630 /* Set thread desktop back to the old thread desktop, SendInput should success. */ 631 ret = SetThreadDesktop(old_thread_desk); 632 ok(ret, "SetThreadDesktop failed!\n"); 633 thread_desk = GetThreadDesktop(GetCurrentThreadId()); 634 ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n"); 635 memset(name, 0, sizeof(name)); 636 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL); 637 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); 638 639 SetLastError(0xdeadbeef); 640 ret = SendInput(1, inputs, sizeof(INPUT)); 641 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); 642 ok(ret == 1, "unexpected return count %d\n", ret); 643 644 /* Set thread desktop to the input desktop, SendInput should success. */ 645 ret = SetThreadDesktop(old_input_desk); 646 ok(ret, "SetThreadDesktop failed!\n"); 647 thread_desk = GetThreadDesktop(GetCurrentThreadId()); 648 ok(thread_desk == old_input_desk, "thread desktop doesn't match!\n"); 649 memset(name, 0, sizeof(name)); 650 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL); 651 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); 652 653 SetLastError(0xdeadbeef); 654 ret = SendInput(1, inputs, sizeof(INPUT)); 655 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); 656 ok(ret == 1, "unexpected return count %d\n", ret); 657 658 /* Switch input desktop to the new desktop, SendInput should fail. */ 659 ret = SwitchDesktop(new_desk); 660 ok(ret, "SwitchDesktop failed!\n"); 661 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); 662 ok(input_desk != NULL, "OpenInputDesktop failed!\n"); 663 ok(input_desk != new_desk, "returned the same handle!\n"); 664 memset(name, 0, sizeof(name)); 665 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL); 666 ok(ret, "GetUserObjectInformation failed!\n"); 667 todo_wine 668 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name); 669 ret = CloseDesktop(input_desk); 670 ok(ret, "CloseDesktop failed!\n"); 671 672 SetLastError(0xdeadbeef); 673 ret = SendInput(1, inputs, sizeof(INPUT)); 674 todo_wine 675 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError()); 676 ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret); 677 678 /* Set thread desktop to the new desktop, SendInput should success. */ 679 ret = SetThreadDesktop(new_desk); 680 ok(ret, "SetThreadDesktop failed!\n"); 681 thread_desk = GetThreadDesktop(GetCurrentThreadId()); 682 ok(thread_desk == new_desk, "thread desktop doesn't match!\n"); 683 memset(name, 0, sizeof(name)); 684 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL); 685 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name); 686 687 SetLastError(0xdeadbeef); 688 ret = SendInput(1, inputs, sizeof(INPUT)); 689 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); 690 ok(ret == 1, "unexpected return count %d\n", ret); 691 692 /* Switch input desktop to the old input desktop, set thread desktop to the old 693 * thread desktop, clean side effects. SendInput should success. */ 694 ret = SwitchDesktop(old_input_desk); 695 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); 696 ok(input_desk != NULL, "OpenInputDesktop failed!\n"); 697 ok(input_desk != old_input_desk, "returned the same handle!\n"); 698 memset(name, 0, sizeof(name)); 699 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL); 700 ok(ret, "GetUserObjectInformation failed!\n"); 701 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); 702 703 ret = SetThreadDesktop(old_thread_desk); 704 ok(ret, "SetThreadDesktop failed!\n"); 705 thread_desk = GetThreadDesktop(GetCurrentThreadId()); 706 ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n"); 707 memset(name, 0, sizeof(name)); 708 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL); 709 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); 710 711 SetLastError(0xdeadbeef); 712 ret = SendInput(1, inputs, sizeof(INPUT)); 713 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); 714 ok(ret == 1, "unexpected return count %d\n", ret); 715 716 /* free resources */ 717 ret = CloseDesktop(input_desk); 718 ok(ret, "CloseDesktop failed!\n"); 719 ret = CloseDesktop(old_input_desk); 720 ok(ret, "CloseDesktop failed!\n"); 721 ret = CloseDesktop(new_desk); 722 ok(ret, "CloseDesktop failed!\n"); 723 } 724 725 static void test_inputdesktop2(void) 726 { 727 HWINSTA w1, w2; 728 HDESK thread_desk, new_desk, input_desk, hdesk; 729 DWORD ret; 730 731 thread_desk = GetThreadDesktop(GetCurrentThreadId()); 732 ok(thread_desk != NULL, "GetThreadDesktop failed!\n"); 733 w1 = GetProcessWindowStation(); 734 ok(w1 != NULL, "GetProcessWindowStation failed!\n"); 735 SetLastError(0xdeadbeef); 736 w2 = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL); 737 ret = GetLastError(); 738 ok(w2 != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret); 739 if (!w2) 740 { 741 win_skip("Not enough privileges for CreateWindowStation\n"); 742 return; 743 } 744 745 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0); 746 ok(!ret, "EnumDesktopsA failed!\n"); 747 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); 748 ok(input_desk != NULL, "OpenInputDesktop failed!\n"); 749 ret = CloseDesktop(input_desk); 750 ok(ret, "CloseDesktop failed!\n"); 751 752 ret = SetProcessWindowStation(w2); 753 ok(ret, "SetProcessWindowStation failed!\n"); 754 hdesk = GetThreadDesktop(GetCurrentThreadId()); 755 ok(hdesk != NULL, "GetThreadDesktop failed!\n"); 756 ok(hdesk == thread_desk, "thread desktop should not change after winstation changed!\n"); 757 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0); 758 759 new_desk = CreateDesktopA("desk_test", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL); 760 ok(new_desk != NULL, "CreateDesktop failed!\n"); 761 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0); 762 ok(!ret, "EnumDesktopsA failed!\n"); 763 SetLastError(0xdeadbeef); 764 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); 765 ok(input_desk == NULL, "OpenInputDesktop should fail on non default winstation!\n"); 766 ok(GetLastError() == ERROR_INVALID_FUNCTION || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError()); 767 768 hdesk = OpenDesktopA("desk_test", 0, TRUE, DESKTOP_ALL_ACCESS); 769 ok(hdesk != NULL, "OpenDesktop failed!\n"); 770 SetLastError(0xdeadbeef); 771 ret = SwitchDesktop(hdesk); 772 todo_wine 773 ok(!ret, "Switch to desktop belong to non default winstation should fail!\n"); 774 todo_wine 775 ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError()); 776 ret = SetThreadDesktop(hdesk); 777 ok(ret, "SetThreadDesktop failed!\n"); 778 779 /* clean side effect */ 780 ret = SetThreadDesktop(thread_desk); 781 todo_wine 782 ok(ret, "SetThreadDesktop should success even desktop is not belong to process winstation!\n"); 783 ret = SetProcessWindowStation(w1); 784 ok(ret, "SetProcessWindowStation failed!\n"); 785 ret = SetThreadDesktop(thread_desk); 786 ok(ret, "SetThreadDesktop failed!\n"); 787 ret = CloseWindowStation(w2); 788 ok(ret, "CloseWindowStation failed!\n"); 789 ret = CloseDesktop(new_desk); 790 ok(ret, "CloseDesktop failed!\n"); 791 ret = CloseDesktop(hdesk); 792 ok(ret, "CloseDesktop failed!\n"); 793 } 794 795 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 796 { 797 if (msg == WM_DESTROY) 798 { 799 trace("destroying hwnd %p\n", hWnd); 800 PostQuitMessage(0); 801 return 0; 802 } 803 return DefWindowProcA( hWnd, msg, wParam, lParam ); 804 } 805 806 typedef struct tag_wnd_param 807 { 808 const char *wnd_name; 809 HWND hwnd; 810 HDESK hdesk; 811 HANDLE hevent; 812 } wnd_param; 813 814 static DWORD WINAPI create_window(LPVOID param) 815 { 816 wnd_param *param1 = param; 817 DWORD ret; 818 MSG msg; 819 820 ret = SetThreadDesktop(param1->hdesk); 821 ok(ret, "SetThreadDesktop failed!\n"); 822 param1->hwnd = CreateWindowA("test_class", param1->wnd_name, WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL); 823 ok(param1->hwnd != 0, "CreateWindowA failed!\n"); 824 ret = SetEvent(param1->hevent); 825 ok(ret, "SetEvent failed!\n"); 826 827 while (GetMessageA(&msg, 0, 0, 0)) 828 { 829 TranslateMessage(&msg); 830 DispatchMessageA(&msg); 831 } 832 833 return 0; 834 } 835 836 static DWORD set_foreground(HWND hwnd) 837 { 838 HWND hwnd_fore; 839 DWORD set_id, fore_id, ret; 840 char win_text[1024]; 841 842 hwnd_fore = GetForegroundWindow(); 843 GetWindowTextA(hwnd_fore, win_text, 1024); 844 set_id = GetWindowThreadProcessId(hwnd, NULL); 845 fore_id = GetWindowThreadProcessId(hwnd_fore, NULL); 846 trace("\"%s\" %p %08x hwnd %p %08x\n", win_text, hwnd_fore, fore_id, hwnd, set_id); 847 ret = AttachThreadInput(set_id, fore_id, TRUE); 848 trace("AttachThreadInput returned %08x\n", ret); 849 ret = ShowWindow(hwnd, SW_SHOWNORMAL); 850 trace("ShowWindow returned %08x\n", ret); 851 ret = SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE); 852 trace("set topmost returned %08x\n", ret); 853 ret = SetWindowPos(hwnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE); 854 trace("set notopmost returned %08x\n", ret); 855 ret = SetForegroundWindow(hwnd); 856 trace("SetForegroundWindow returned %08x\n", ret); 857 Sleep(250); 858 AttachThreadInput(set_id, fore_id, FALSE); 859 return ret; 860 } 861 862 static void test_foregroundwindow(void) 863 { 864 HWND hwnd, hwnd_test, partners[2], hwnds[2]; 865 HDESK hdesks[2]; 866 int thread_desk_id, input_desk_id, hwnd_id; 867 WNDCLASSA wclass; 868 wnd_param param; 869 DWORD ret, timeout, timeout_old; 870 char win_text[1024]; 871 872 #define DESKTOPS 2 873 874 memset( &wclass, 0, sizeof(wclass) ); 875 wclass.lpszClassName = "test_class"; 876 wclass.lpfnWndProc = WndProc; 877 RegisterClassA(&wclass); 878 param.wnd_name = "win_name"; 879 880 hdesks[0] = GetThreadDesktop(GetCurrentThreadId()); 881 ok(hdesks[0] != NULL, "OpenDesktop failed!\n"); 882 SetLastError(0xdeadbeef); 883 hdesks[1] = CreateDesktopA("desk2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL); 884 ret = GetLastError(); 885 ok(hdesks[1] != NULL || ret == ERROR_ACCESS_DENIED, "CreateDesktop failed (%u)\n", ret); 886 if(!hdesks[1]) 887 { 888 win_skip("Not enough privileges for CreateDesktop\n"); 889 return; 890 } 891 892 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout_old, 0); 893 if(!ret) 894 { 895 win_skip("Skip tests on NT4\n"); 896 CloseDesktop(hdesks[1]); 897 return; 898 } 899 trace("old timeout %d\n", timeout_old); 900 timeout = 0; 901 ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE); 902 ok(ret, "set foreground lock timeout failed!\n"); 903 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0); 904 ok(ret, "get foreground lock timeout failed!\n"); 905 ok(timeout == 0, "unexpected timeout %d\n", timeout); 906 907 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++) 908 { 909 param.hdesk = hdesks[thread_desk_id]; 910 param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL); 911 CreateThread(NULL, 0, create_window, ¶m, 0, NULL); 912 ret = WaitForSingleObject(param.hevent, INFINITE); 913 ok(ret == WAIT_OBJECT_0, "wait failed!\n"); 914 hwnds[thread_desk_id] = param.hwnd; 915 } 916 917 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++) 918 { 919 param.hdesk = hdesks[thread_desk_id]; 920 param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL); 921 CreateThread(NULL, 0, create_window, ¶m, 0, NULL); 922 ret = WaitForSingleObject(param.hevent, INFINITE); 923 ok(ret == WAIT_OBJECT_0, "wait failed!\n"); 924 partners[thread_desk_id] = param.hwnd; 925 } 926 927 trace("hwnd0 %p hwnd1 %p partner0 %p partner1 %p\n", hwnds[0], hwnds[1], partners[0], partners[1]); 928 929 for (hwnd_id = 0; hwnd_id < DESKTOPS; hwnd_id++) 930 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++) 931 for (input_desk_id = 0; input_desk_id < DESKTOPS; input_desk_id++) 932 { 933 trace("testing thread_desk %d input_desk %d hwnd %d\n", 934 thread_desk_id, input_desk_id, hwnd_id); 935 hwnd_test = hwnds[hwnd_id]; 936 ret = SetThreadDesktop(hdesks[thread_desk_id]); 937 ok(ret, "set thread desktop failed!\n"); 938 ret = SwitchDesktop(hdesks[input_desk_id]); 939 ok(ret, "switch desktop failed!\n"); 940 set_foreground(partners[0]); 941 set_foreground(partners[1]); 942 hwnd = GetForegroundWindow(); 943 ok(hwnd != hwnd_test, "unexpected foreground window %p\n", hwnd); 944 ret = set_foreground(hwnd_test); 945 hwnd = GetForegroundWindow(); 946 GetWindowTextA(hwnd, win_text, 1024); 947 trace("hwnd %p name %s\n", hwnd, win_text); 948 if (input_desk_id == hwnd_id) 949 { 950 if (input_desk_id == thread_desk_id) 951 { 952 ok(ret, "SetForegroundWindow failed!\n"); 953 todo_wine_if (!hwnd) 954 ok(hwnd == hwnd_test , "unexpected foreground window %p\n", hwnd); 955 } 956 else 957 { 958 todo_wine ok(ret, "SetForegroundWindow failed!\n"); 959 todo_wine ok(hwnd == 0, "unexpected foreground window %p\n", hwnd); 960 } 961 } 962 else 963 { 964 if (input_desk_id == thread_desk_id) 965 { 966 ok(!ret, "SetForegroundWindow should fail!\n"); 967 todo_wine_if (!hwnd) 968 ok(hwnd == partners[input_desk_id] , "unexpected foreground window %p\n", hwnd); 969 } 970 else 971 { 972 todo_wine ok(!ret, "SetForegroundWindow should fail!\n"); 973 todo_wine_if (hwnd) 974 ok(hwnd == 0, "unexpected foreground window %p\n", hwnd); 975 } 976 } 977 } 978 979 /* Clean up */ 980 981 for (thread_desk_id = DESKTOPS - 1; thread_desk_id >= 0; thread_desk_id--) 982 { 983 ret = SetThreadDesktop(hdesks[thread_desk_id]); 984 ok(ret, "set thread desktop failed!\n"); 985 SendMessageA(hwnds[thread_desk_id], WM_DESTROY, 0, 0); 986 SendMessageA(partners[thread_desk_id], WM_DESTROY, 0, 0); 987 } 988 989 ret = SwitchDesktop(hdesks[0]); 990 ok(ret, "switch desktop failed!\n"); 991 CloseDesktop(hdesks[1]); 992 993 ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UlongToPtr(timeout_old), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE); 994 ok(ret, "set foreground lock timeout failed!\n"); 995 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0); 996 ok(ret, "get foreground lock timeout failed!\n"); 997 ok(timeout == timeout_old, "unexpected timeout %d\n", timeout); 998 } 999 1000 START_TEST(winstation) 1001 { 1002 HMODULE hntdll = GetModuleHandleA("ntdll.dll"); 1003 pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject"); 1004 1005 /* Check whether this platform supports WindowStation calls */ 1006 1007 SetLastError( 0xdeadbeef ); 1008 GetProcessWindowStation(); 1009 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 1010 { 1011 win_skip("WindowStation calls not supported on this platform\n"); 1012 return; 1013 } 1014 1015 test_inputdesktop(); 1016 test_inputdesktop2(); 1017 test_enumstations(); 1018 test_enumdesktops(); 1019 test_handles(); 1020 test_getuserobjectinformation(); 1021 test_foregroundwindow(); 1022 } 1023