blob: 4f664dd5476480161268ddc3cc3fb13baa00ed2a [file] [log] [blame]
/*
* Unit tests for window stations and desktops
*
* Copyright 2002 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "wine/test.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#define DESKTOP_ALL_ACCESS 0x01ff
static void print_object( HANDLE obj )
{
char buffer[100];
DWORD size;
strcpy( buffer, "foobar" );
if (!GetUserObjectInformationA( obj, UOI_NAME, buffer, sizeof(buffer), &size ))
trace( "could not get info for %p\n", obj );
else
trace( "obj %p name '%s'\n", obj, buffer );
strcpy( buffer, "foobar" );
if (!GetUserObjectInformationA( obj, UOI_TYPE, buffer, sizeof(buffer), &size ))
trace( "could not get type for %p\n", obj );
else
trace( "obj %p type '%s'\n", obj, buffer );
}
static void register_class(void)
{
WNDCLASSA cls;
cls.style = CS_DBLCLKS;
cls.lpfnWndProc = DefWindowProcA;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = GetModuleHandleA(0);
cls.hIcon = 0;
cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
cls.hbrBackground = GetStockObject(WHITE_BRUSH);
cls.lpszMenuName = NULL;
cls.lpszClassName = "WinStationClass";
RegisterClassA(&cls);
}
static HDESK initial_desktop;
static DWORD CALLBACK thread( LPVOID arg )
{
HDESK d1, d2;
HWND hwnd = CreateWindowExA(0,"WinStationClass","test",WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0);
ok( hwnd != 0, "CreateWindow failed\n" );
d1 = GetThreadDesktop(GetCurrentThreadId());
trace( "thread %p desktop: %p\n", arg, d1 );
ok( d1 == initial_desktop, "thread %p doesn't use initial desktop\n", arg );
SetLastError( 0xdeadbeef );
ok( !CloseHandle( d1 ), "CloseHandle succeeded\n" );
ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
SetLastError( 0xdeadbeef );
ok( !CloseDesktop( d1 ), "CloseDesktop succeeded\n" );
ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */
"bad last error %d\n", GetLastError() );
print_object( d1 );
d2 = CreateDesktopA( "foobar2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
trace( "created desktop %p\n", d2 );
ok( d2 != 0, "CreateDesktop failed\n" );
SetLastError( 0xdeadbeef );
ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" );
ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */
"bad last error %d\n", GetLastError() );
DestroyWindow( hwnd );
ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" );
d1 = GetThreadDesktop(GetCurrentThreadId());
ok( d1 == d2, "GetThreadDesktop did not return set desktop %p/%p\n", d1, d2 );
print_object( d2 );
if (arg < (LPVOID)5)
{
HANDLE hthread = CreateThread( NULL, 0, thread, (char *)arg + 1, 0, NULL );
Sleep(1000);
WaitForSingleObject( hthread, INFINITE );
CloseHandle( hthread );
}
return 0;
}
static void test_handles(void)
{
HWINSTA w1, w2, w3;
HDESK d1, d2, d3;
HANDLE hthread;
DWORD id, flags, le;
ATOM atom;
char buffer[20];
/* win stations */
w1 = GetProcessWindowStation();
ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" );
ok( !CloseWindowStation(w1), "closing process win station succeeded\n" );
SetLastError( 0xdeadbeef );
ok( !CloseHandle(w1), "closing process win station handle succeeded\n" );
ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
print_object( w1 );
flags = 0;
ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" );
ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) ||
broken(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), /* set on nt4 */
"handle %p PROTECT_FROM_CLOSE set\n", w1 );
ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
ok( CloseWindowStation(w2), "closing dup win station failed\n" );
ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
ok( CloseHandle(w2), "closing dup win station handle failed\n" );
w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
le = GetLastError();
ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", le );
if (w2 != 0)
{
ok( w2 != w1, "CreateWindowStation returned default handle\n" );
SetLastError( 0xdeadbeef );
ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" );
ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */
"bad last error %d\n", GetLastError() );
ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
ok( CloseHandle( w2 ), "CloseHandle failed\n" );
}
else if (le == ERROR_ACCESS_DENIED)
win_skip( "Not enough privileges for CreateWindowStation\n" );
w2 = OpenWindowStationA("winsta0", TRUE, WINSTA_ALL_ACCESS );
ok( w2 != 0, "OpenWindowStation failed\n" );
ok( w2 != w1, "OpenWindowStation returned default handle\n" );
ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
w2 = OpenWindowStationA("dummy name", TRUE, WINSTA_ALL_ACCESS );
ok( !w2, "open dummy win station succeeded\n" );
CreateMutexA( NULL, 0, "foobar" );
w2 = CreateWindowStationA("foobar", 0, WINSTA_ALL_ACCESS, NULL );
le = GetLastError();
ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "create foobar station failed (%u)\n", le );
if (w2 != 0)
{
w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS );
ok( w3 != 0, "open foobar station failed\n" );
ok( w3 != w2, "open foobar station returned same handle\n" );
ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" );
w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS );
ok( !w3, "open foobar station succeeded\n" );
w2 = CreateWindowStationA("foobar1", 0, WINSTA_ALL_ACCESS, NULL );
ok( w2 != 0, "create foobar station failed\n" );
w3 = CreateWindowStationA("foobar2", 0, WINSTA_ALL_ACCESS, NULL );
ok( w3 != 0, "create foobar station failed\n" );
ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" );
SetProcessWindowStation( w2 );
atom = GlobalAddAtomA("foo");
ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" );
ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
SetProcessWindowStation( w3 );
ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
}
else if (le == ERROR_ACCESS_DENIED)
win_skip( "Not enough privileges for CreateWindowStation\n" );
/* desktops */
d1 = GetThreadDesktop(GetCurrentThreadId());
initial_desktop = d1;
ok( GetThreadDesktop(GetCurrentThreadId()) == d1,
"GetThreadDesktop returned different handles\n" );
flags = 0;
ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" );
ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 );
SetLastError( 0xdeadbeef );
ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" );
ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */
"bad last error %d\n", GetLastError() );
SetLastError( 0xdeadbeef );
if (CloseHandle( d1 )) /* succeeds on nt4 */
{
win_skip( "NT4 desktop handle management is completely different\n" );
return;
}
ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
ok( CloseDesktop(d2), "closing dup desktop failed\n" );
ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
ok( CloseHandle(d2), "closing dup desktop handle failed\n" );
d2 = OpenDesktopA( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
ok( !d2, "open dummy desktop succeeded\n" );
d2 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
ok( d2 != 0, "create foobar desktop failed\n" );
SetLastError( 0xdeadbeef );
ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" );
ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */
"bad last error %d\n", GetLastError() );
SetLastError( 0xdeadbeef );
d3 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
ok( d3 != 0, "create foobar desktop again failed\n" );
ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() );
ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
ok( d3 != 0, "open foobar desktop failed\n" );
ok( d3 != d2, "open foobar desktop returned same handle\n" );
ok( CloseDesktop( d2 ), "CloseDesktop failed\n" );
ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
ok( !d3, "open foobar desktop succeeded\n" );
ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" );
d2 = GetThreadDesktop(GetCurrentThreadId());
ok( d1 == d2, "got different handles after close\n" );
register_class();
trace( "thread 1 desktop: %p\n", d1 );
print_object( d1 );
hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id );
Sleep(1000);
trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
WaitForSingleObject( hthread, INFINITE );
CloseHandle( hthread );
/* clean side effect */
SetProcessWindowStation( w1 );
}
/* Enumeration tests */
static BOOL CALLBACK window_station_callbackA(LPSTR winsta, LPARAM lp)
{
trace("window_station_callbackA called with argument %s\n", winsta);
return lp;
}
static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp)
{
HWINSTA hwinsta;
trace("open_window_station_callbackA called with argument %s\n", winsta);
hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE);
ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta);
if (hwinsta)
CloseWindowStation(hwinsta);
return lp;
}
static void test_enumstations(void)
{
BOOL ret;
if (0) /* Crashes instead */
{
SetLastError(0xbabefeed);
ret = EnumWindowStationsA(NULL, 0);
ok(!ret, "EnumWindowStationsA returned successfully!\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
}
SetLastError(0xdeadbeef);
ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345);
ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = EnumWindowStationsA(window_station_callbackA, 0);
ok(!ret, "EnumWindowStationsA returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
}
static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp)
{
trace("desktop_callbackA called with argument %s\n", desktop);
return lp;
}
static BOOL CALLBACK open_desktop_callbackA(LPSTR desktop, LPARAM lp)
{
HDESK hdesk;
static int once;
trace("open_desktop_callbackA called with argument %s\n", desktop);
/* Only try to open one desktop */
if (once++)
return lp;
hdesk = OpenDesktopA(desktop, 0, FALSE, DESKTOP_ENUMERATE);
ok(hdesk != NULL, "Could not open desktop %s!\n", desktop);
if (hdesk)
CloseDesktop(hdesk);
return lp;
}
static void test_enumdesktops(void)
{
BOOL ret;
if (0) /* Crashes instead */
{
SetLastError(0xbabefeed);
ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0);
ok(!ret, "EnumDesktopsA returned successfully!\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
}
SetLastError(0xdeadbeef);
ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345);
ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345);
ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345);
ok(!ret, "EnumDesktopsA returned %x\n", ret);
ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
ok(!ret, "EnumDesktopsA returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
}
/* Miscellaneous tests */
static void test_getuserobjectinformation(void)
{
HDESK desk;
WCHAR bufferW[20];
char buffer[20];
WCHAR foobarTestW[] = {'f','o','o','b','a','r','T','e','s','t',0};
WCHAR DesktopW[] = {'D','e','s','k','t','o','p',0};
DWORD size;
BOOL ret;
desk = CreateDesktopA("foobarTest", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
ok(desk != 0, "open foobarTest desktop failed\n");
strcpy(buffer, "blahblah");
/** Tests for UOI_NAME **/
/* Get size, test size and return value/error code */
SetLastError(0xdeadbeef);
size = 0xdeadbeef;
ret = GetUserObjectInformationA(desk, UOI_NAME, NULL, 0, &size);
ok(!ret, "GetUserObjectInformationA returned %x\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
ok(size == 22, "size is set to %d\n", size); /* Windows returns Unicode length (11*2) */
/* Get string */
SetLastError(0xdeadbeef);
size = 0xdeadbeef;
ret = GetUserObjectInformationA(desk, UOI_NAME, buffer, sizeof(buffer), &size);
ok(ret, "GetUserObjectInformationA returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
ok(strcmp(buffer, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer);
ok(size == 11, "size is set to %d\n", size); /* 11 bytes in 'foobarTest\0' */
/* Get size, test size and return value/error code (Unicode) */
SetLastError(0xdeadbeef);
size = 0xdeadbeef;
ret = GetUserObjectInformationW(desk, UOI_NAME, NULL, 0, &size);
ok(!ret, "GetUserObjectInformationW returned %x\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */
/* Get string (Unicode) */
SetLastError(0xdeadbeef);
size = 0xdeadbeef;
ret = GetUserObjectInformationW(desk, UOI_NAME, bufferW, sizeof(bufferW), &size);
ok(ret, "GetUserObjectInformationW returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
ok(lstrcmpW(bufferW, foobarTestW) == 0, "Buffer is not set to 'foobarTest'\n");
ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */
/** Tests for UOI_TYPE **/
/* Get size, test size and return value/error code */
SetLastError(0xdeadbeef);
size = 0xdeadbeef;
ret = GetUserObjectInformationA(desk, UOI_TYPE, NULL, 0, &size);
ok(!ret, "GetUserObjectInformationA returned %x\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
ok(size == 16, "size is set to %d\n", size); /* Windows returns Unicode length (8*2) */
/* Get string */
SetLastError(0xdeadbeef);
size = 0xdeadbeef;
ret = GetUserObjectInformationA(desk, UOI_TYPE, buffer, sizeof(buffer), &size);
ok(ret, "GetUserObjectInformationA returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
ok(strcmp(buffer, "Desktop") == 0, "Buffer is set to '%s'\n", buffer);
ok(size == 8, "size is set to %d\n", size); /* 8 bytes in 'Desktop\0' */
/* Get size, test size and return value/error code (Unicode) */
size = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = GetUserObjectInformationW(desk, UOI_TYPE, NULL, 0, &size);
ok(!ret, "GetUserObjectInformationW returned %x\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */
/* Get string (Unicode) */
SetLastError(0xdeadbeef);
size = 0xdeadbeef;
ret = GetUserObjectInformationW(desk, UOI_TYPE, bufferW, sizeof(bufferW), &size);
ok(ret, "GetUserObjectInformationW returned %x\n", ret);
ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
ok(lstrcmpW(bufferW, DesktopW) == 0, "Buffer is not set to 'Desktop'\n");
ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */
ok(CloseDesktop(desk), "CloseDesktop failed\n");
}
static void test_inputdesktop(void)
{
HDESK input_desk, old_input_desk, thread_desk, old_thread_desk, new_desk;
DWORD ret;
CHAR name[1024];
INPUT inputs[1];
inputs[0].type = INPUT_KEYBOARD;
U(inputs[0]).ki.wVk = 0;
U(inputs[0]).ki.wScan = 0x3c0;
U(inputs[0]).ki.dwFlags = KEYEVENTF_UNICODE;
/* OpenInputDesktop creates new handles for each calls */
old_input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
ok(old_input_desk != NULL, "OpenInputDesktop failed!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(old_input_desk, UOI_NAME, name, 1024, NULL);
ok(ret, "GetUserObjectInformation failed!\n");
ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
ok(input_desk != NULL, "OpenInputDesktop failed!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
ok(ret, "GetUserObjectInformation failed!\n");
ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
ok(old_input_desk != input_desk, "returned the same handle!\n");
ret = CloseDesktop(input_desk);
ok(ret, "CloseDesktop failed!\n");
/* by default, GetThreadDesktop is the input desktop, SendInput should success. */
old_thread_desk = GetThreadDesktop(GetCurrentThreadId());
ok(old_thread_desk != NULL, "GetThreadDesktop faile!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(old_thread_desk, UOI_NAME, name, 1024, NULL);
ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
SetLastError(0xdeadbeef);
ret = SendInput(1, inputs, sizeof(INPUT));
ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
ok(ret == 1, "unexpected return count %d\n", ret);
/* Set thread desktop to the new desktop, SendInput should fail. */
new_desk = CreateDesktopA("new_desk", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
ok(new_desk != NULL, "CreateDesktop failed!\n");
ret = SetThreadDesktop(new_desk);
ok(ret, "SetThreadDesktop failed!\n");
thread_desk = GetThreadDesktop(GetCurrentThreadId());
ok(thread_desk == new_desk, "thread desktop doesn't match!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
SetLastError(0xdeadbeef);
ret = SendInput(1, inputs, sizeof(INPUT));
if(broken(GetLastError() == 0xdeadbeef))
{
SetThreadDesktop(old_thread_desk);
CloseDesktop(old_input_desk);
CloseDesktop(input_desk);
CloseDesktop(new_desk);
win_skip("Skip tests on NT4\n");
return;
}
todo_wine
ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError());
ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret);
/* Set thread desktop back to the old thread desktop, SendInput should success. */
ret = SetThreadDesktop(old_thread_desk);
ok(ret, "SetThreadDesktop failed!\n");
thread_desk = GetThreadDesktop(GetCurrentThreadId());
ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
SetLastError(0xdeadbeef);
ret = SendInput(1, inputs, sizeof(INPUT));
ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
ok(ret == 1, "unexpected return count %d\n", ret);
/* Set thread desktop to the input desktop, SendInput should success. */
ret = SetThreadDesktop(old_input_desk);
ok(ret, "SetThreadDesktop failed!\n");
thread_desk = GetThreadDesktop(GetCurrentThreadId());
ok(thread_desk == old_input_desk, "thread desktop doesn't match!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
SetLastError(0xdeadbeef);
ret = SendInput(1, inputs, sizeof(INPUT));
ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
ok(ret == 1, "unexpected return count %d\n", ret);
/* Switch input desktop to the new desktop, SendInput should fail. */
ret = SwitchDesktop(new_desk);
ok(ret, "SwitchDesktop failed!\n");
input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
ok(input_desk != NULL, "OpenInputDesktop failed!\n");
ok(input_desk != new_desk, "returned the same handle!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
ok(ret, "GetUserObjectInformation failed!\n");
todo_wine
ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
ret = CloseDesktop(input_desk);
ok(ret, "CloseDesktop failed!\n");
SetLastError(0xdeadbeef);
ret = SendInput(1, inputs, sizeof(INPUT));
todo_wine
ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError());
ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret);
/* Set thread desktop to the new desktop, SendInput should success. */
ret = SetThreadDesktop(new_desk);
ok(ret, "SetThreadDesktop failed!\n");
thread_desk = GetThreadDesktop(GetCurrentThreadId());
ok(thread_desk == new_desk, "thread desktop doesn't match!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
SetLastError(0xdeadbeef);
ret = SendInput(1, inputs, sizeof(INPUT));
ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
ok(ret == 1, "unexpected return count %d\n", ret);
/* Switch input desktop to the old input desktop, set thread desktop to the old
* thread desktop, clean side effects. SendInput should success. */
ret = SwitchDesktop(old_input_desk);
input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
ok(input_desk != NULL, "OpenInputDesktop failed!\n");
ok(input_desk != old_input_desk, "returned the same handle!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
ok(ret, "GetUserObjectInformation failed!\n");
ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
ret = SetThreadDesktop(old_thread_desk);
ok(ret, "SetThreadDesktop failed!\n");
thread_desk = GetThreadDesktop(GetCurrentThreadId());
ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n");
memset(name, 0, sizeof(name));
ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
SetLastError(0xdeadbeef);
ret = SendInput(1, inputs, sizeof(INPUT));
ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
ok(ret == 1, "unexpected return count %d\n", ret);
/* free resources */
ret = CloseDesktop(input_desk);
ok(ret, "CloseDesktop failed!\n");
ret = CloseDesktop(old_input_desk);
ok(ret, "CloseDesktop failed!\n");
ret = CloseDesktop(new_desk);
ok(ret, "CloseDesktop failed!\n");
}
static void test_inputdesktop2(void)
{
HWINSTA w1, w2;
HDESK thread_desk, new_desk, input_desk, hdesk;
DWORD ret;
thread_desk = GetThreadDesktop(GetCurrentThreadId());
ok(thread_desk != NULL, "GetThreadDesktop failed!\n");
w1 = GetProcessWindowStation();
ok(w1 != NULL, "GetProcessWindowStation failed!\n");
SetLastError(0xdeadbeef);
w2 = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL);
ret = GetLastError();
ok(w2 != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret);
if (!w2)
{
win_skip("Not enough privileges for CreateWindowStation\n");
return;
}
ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
ok(!ret, "EnumDesktopsA failed!\n");
input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
ok(input_desk != NULL, "OpenInputDesktop failed!\n");
ret = CloseDesktop(input_desk);
ok(ret, "CloseDesktop failed!\n");
ret = SetProcessWindowStation(w2);
ok(ret, "SetProcessWindowStation failed!\n");
hdesk = GetThreadDesktop(GetCurrentThreadId());
ok(hdesk != NULL, "GetThreadDesktop failed!\n");
ok(hdesk == thread_desk, "thread desktop should not change after winstation changed!\n");
ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
new_desk = CreateDesktopA("desk_test", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
ok(new_desk != NULL, "CreateDesktop failed!\n");
ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
ok(!ret, "EnumDesktopsA failed!\n");
SetLastError(0xdeadbeef);
input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
ok(input_desk == NULL, "OpenInputDesktop should fail on non default winstation!\n");
ok(GetLastError() == ERROR_INVALID_FUNCTION || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
hdesk = OpenDesktopA("desk_test", 0, TRUE, DESKTOP_ALL_ACCESS);
ok(hdesk != NULL, "OpenDesktop failed!\n");
SetLastError(0xdeadbeef);
ret = SwitchDesktop(hdesk);
todo_wine
ok(!ret, "Switch to desktop belong to non default winstation should fail!\n");
todo_wine
ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
ret = SetThreadDesktop(hdesk);
ok(ret, "SetThreadDesktop failed!\n");
/* clean side effect */
ret = SetThreadDesktop(thread_desk);
todo_wine
ok(ret, "SetThreadDesktop should success even desktop is not belong to process winstation!\n");
ret = SetProcessWindowStation(w1);
ok(ret, "SetProcessWindowStation failed!\n");
ret = SetThreadDesktop(thread_desk);
ok(ret, "SetThreadDesktop failed!\n");
ret = CloseWindowStation(w2);
ok(ret, "CloseWindowStation failed!\n");
ret = CloseDesktop(new_desk);
ok(ret, "CloseDesktop failed!\n");
ret = CloseDesktop(hdesk);
ok(ret, "CloseDesktop failed!\n");
}
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_DESTROY)
{
trace("destroying hwnd %p\n", hWnd);
PostQuitMessage(0);
return 0;
}
return DefWindowProcA( hWnd, msg, wParam, lParam );
}
typedef struct tag_wnd_param
{
const char *wnd_name;
HWND hwnd;
HDESK hdesk;
HANDLE hevent;
} wnd_param;
static DWORD WINAPI create_window(LPVOID param)
{
wnd_param *param1 = param;
DWORD ret;
MSG msg;
ret = SetThreadDesktop(param1->hdesk);
ok(ret, "SetThreadDesktop failed!\n");
param1->hwnd = CreateWindowA("test_class", param1->wnd_name, WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
ok(param1->hwnd != 0, "CreateWindowA failed!\n");
ret = SetEvent(param1->hevent);
ok(ret, "SetEvent failed!\n");
while (GetMessageA(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
return 0;
}
static DWORD set_foreground(HWND hwnd)
{
HWND hwnd_fore;
DWORD set_id, fore_id, ret;
char win_text[1024];
hwnd_fore = GetForegroundWindow();
GetWindowTextA(hwnd_fore, win_text, 1024);
set_id = GetWindowThreadProcessId(hwnd, NULL);
fore_id = GetWindowThreadProcessId(hwnd_fore, NULL);
trace("\"%s\" %p %08x hwnd %p %08x\n", win_text, hwnd_fore, fore_id, hwnd, set_id);
ret = AttachThreadInput(set_id, fore_id, TRUE);
trace("AttachThreadInput returned %08x\n", ret);
ret = ShowWindow(hwnd, SW_SHOWNORMAL);
trace("ShowWindow returned %08x\n", ret);
ret = SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE);
trace("set topmost returned %08x\n", ret);
ret = SetWindowPos(hwnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE);
trace("set notopmost returned %08x\n", ret);
ret = SetForegroundWindow(hwnd);
trace("SetForegroundWindow returned %08x\n", ret);
Sleep(250);
AttachThreadInput(set_id, fore_id, FALSE);
return ret;
}
static void test_foregroundwindow(void)
{
HWND hwnd, hwnd_test, partners[2], hwnds[2];
HDESK hdesks[2];
int thread_desk_id, input_desk_id, hwnd_id;
WNDCLASSA wclass;
wnd_param param;
DWORD ret, timeout, timeout_old;
char win_text[1024];
#define DESKTOPS 2
memset( &wclass, 0, sizeof(wclass) );
wclass.lpszClassName = "test_class";
wclass.lpfnWndProc = WndProc;
RegisterClassA(&wclass);
param.wnd_name = "win_name";
hdesks[0] = GetThreadDesktop(GetCurrentThreadId());
ok(hdesks[0] != NULL, "OpenDesktop failed!\n");
SetLastError(0xdeadbeef);
hdesks[1] = CreateDesktopA("desk2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
ret = GetLastError();
ok(hdesks[1] != NULL || ret == ERROR_ACCESS_DENIED, "CreateDesktop failed (%u)\n", ret);
if(!hdesks[1])
{
win_skip("Not enough privileges for CreateDesktop\n");
return;
}
ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout_old, 0);
if(!ret)
{
win_skip("Skip tests on NT4\n");
CloseDesktop(hdesks[1]);
return;
}
trace("old timeout %d\n", timeout_old);
timeout = 0;
ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
ok(ret, "set foreground lock timeout failed!\n");
ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0);
ok(ret, "get foreground lock timeout failed!\n");
ok(timeout == 0, "unexpected timeout %d\n", timeout);
for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
{
param.hdesk = hdesks[thread_desk_id];
param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL);
CreateThread(NULL, 0, create_window, &param, 0, NULL);
ret = WaitForSingleObject(param.hevent, INFINITE);
ok(ret == WAIT_OBJECT_0, "wait failed!\n");
hwnds[thread_desk_id] = param.hwnd;
}
for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
{
param.hdesk = hdesks[thread_desk_id];
param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL);
CreateThread(NULL, 0, create_window, &param, 0, NULL);
ret = WaitForSingleObject(param.hevent, INFINITE);
ok(ret == WAIT_OBJECT_0, "wait failed!\n");
partners[thread_desk_id] = param.hwnd;
}
trace("hwnd0 %p hwnd1 %p partner0 %p partner1 %p\n", hwnds[0], hwnds[1], partners[0], partners[1]);
for (hwnd_id = 0; hwnd_id < DESKTOPS; hwnd_id++)
for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
for (input_desk_id = 0; input_desk_id < DESKTOPS; input_desk_id++)
{
trace("testing thread_desk %d input_desk %d hwnd %d\n",
thread_desk_id, input_desk_id, hwnd_id);
hwnd_test = hwnds[hwnd_id];
ret = SetThreadDesktop(hdesks[thread_desk_id]);
ok(ret, "set thread desktop failed!\n");
ret = SwitchDesktop(hdesks[input_desk_id]);
ok(ret, "switch desktop failed!\n");
set_foreground(partners[0]);
set_foreground(partners[1]);
hwnd = GetForegroundWindow();
ok(hwnd != hwnd_test, "unexpected foreground window %p\n", hwnd);
ret = set_foreground(hwnd_test);
hwnd = GetForegroundWindow();
GetWindowTextA(hwnd, win_text, 1024);
trace("hwnd %p name %s\n", hwnd, win_text);
if (input_desk_id == hwnd_id)
{
if (input_desk_id == thread_desk_id)
{
ok(ret, "SetForegroundWindow failed!\n");
ok(hwnd == hwnd_test , "unexpected foreground window %p\n", hwnd);
}
else
{
todo_wine ok(ret, "SetForegroundWindow failed!\n");
todo_wine ok(hwnd == 0, "unexpected foreground window %p\n", hwnd);
}
}
else
{
if (input_desk_id == thread_desk_id)
{
ok(!ret, "SetForegroundWindow should fail!\n");
ok(hwnd == partners[input_desk_id] , "unexpected foreground window %p\n", hwnd);
}
else
{
todo_wine ok(!ret, "SetForegroundWindow should fail!\n");
todo_wine ok(hwnd == 0, "unexpected foreground window %p\n", hwnd);
}
}
}
/* Clean up */
for (thread_desk_id = DESKTOPS - 1; thread_desk_id >= 0; thread_desk_id--)
{
ret = SetThreadDesktop(hdesks[thread_desk_id]);
ok(ret, "set thread desktop failed!\n");
SendMessageA(hwnds[thread_desk_id], WM_DESTROY, 0, 0);
SendMessageA(partners[thread_desk_id], WM_DESTROY, 0, 0);
}
ret = SwitchDesktop(hdesks[0]);
ok(ret, "switch desktop failed!\n");
CloseDesktop(hdesks[1]);
ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UlongToPtr(timeout_old), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
ok(ret, "set foreground lock timeout failed!\n");
ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0);
ok(ret, "get foreground lock timeout failed!\n");
ok(timeout == timeout_old, "unexpected timeout %d\n", timeout);
}
START_TEST(winstation)
{
/* Check whether this platform supports WindowStation calls */
SetLastError( 0xdeadbeef );
GetProcessWindowStation();
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
skip("WindowStation calls not supported on this platform\n");
return;
}
test_inputdesktop();
test_inputdesktop2();
test_enumstations();
test_enumdesktops();
test_handles();
test_getuserobjectinformation();
test_foregroundwindow();
}