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