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