mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
added user32 wine regression test
svn path=/trunk/; revision=17125
This commit is contained in:
parent
68cfd5b234
commit
bf046096f1
19 changed files with 16283 additions and 0 deletions
613
reactos/regtests/winetests/user32/class.c
Executable file
613
reactos/regtests/winetests/user32/class.c
Executable file
|
@ -0,0 +1,613 @@
|
|||
/* Unit test suite for window classes.
|
||||
*
|
||||
* Copyright 2002 Mike McCormack
|
||||
* Copyright 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* To get CS_DROPSHADOW with the MSVC headers */
|
||||
#define _WIN32_WINNT 0x0501
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
|
||||
#define NUMCLASSWORDS 4
|
||||
|
||||
static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return DefWindowProcW (hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*/
|
||||
static void ClassTest(HINSTANCE hInstance, BOOL global)
|
||||
{
|
||||
WNDCLASSW cls, wc;
|
||||
static const WCHAR className[] = {'T','e','s','t','C','l','a','s','s',0};
|
||||
static const WCHAR winName[] = {'W','i','n','C','l','a','s','s','T','e','s','t',0};
|
||||
ATOM test_atom;
|
||||
HWND hTestWnd;
|
||||
LONG i;
|
||||
WCHAR str[20];
|
||||
ATOM classatom;
|
||||
|
||||
cls.style = CS_HREDRAW | CS_VREDRAW | (global?CS_GLOBALCLASS:0);
|
||||
cls.lpfnWndProc = ClassTest_WndProc;
|
||||
cls.cbClsExtra = NUMCLASSWORDS*sizeof(DWORD);
|
||||
cls.cbWndExtra = 12;
|
||||
cls.hInstance = hInstance;
|
||||
cls.hIcon = LoadIconW (0, (LPWSTR)IDI_APPLICATION);
|
||||
cls.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
|
||||
cls.hbrBackground = GetStockObject (WHITE_BRUSH);
|
||||
cls.lpszMenuName = 0;
|
||||
cls.lpszClassName = className;
|
||||
|
||||
classatom=RegisterClassW(&cls);
|
||||
if (!classatom && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return;
|
||||
ok(classatom, "failed to register class\n");
|
||||
|
||||
ok(!RegisterClassW (&cls),
|
||||
"RegisterClass of the same class should fail for the second time\n");
|
||||
|
||||
/* Setup windows */
|
||||
hTestWnd = CreateWindowW (className, winName,
|
||||
WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL,
|
||||
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0,
|
||||
0, hInstance, 0);
|
||||
|
||||
ok(hTestWnd!=0, "Failed to create window\n");
|
||||
|
||||
/* test initial values of valid classwords */
|
||||
for(i=0; i<NUMCLASSWORDS; i++)
|
||||
{
|
||||
SetLastError(0);
|
||||
ok(!GetClassLongW(hTestWnd,i*sizeof (DWORD)),
|
||||
"GetClassLongW initial value nonzero!\n");
|
||||
ok(!GetLastError(),
|
||||
"GetClassLongW failed!\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD))
|
||||
* does not fail on Win 98, though MSDN says it should
|
||||
*/
|
||||
SetLastError(0);
|
||||
GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD));
|
||||
ok(GetLastError(),
|
||||
"GetClassLongW() with invalid offset did not fail\n");
|
||||
#endif
|
||||
|
||||
/* set values of valid class words */
|
||||
for(i=0; i<NUMCLASSWORDS; i++)
|
||||
{
|
||||
SetLastError(0);
|
||||
ok(!SetClassLongW(hTestWnd,i*sizeof(DWORD),i+1),
|
||||
"GetClassLongW(%ld) initial value nonzero!\n",i*sizeof(DWORD));
|
||||
ok(!GetLastError(),
|
||||
"SetClassLongW(%ld) failed!\n",i*sizeof(DWORD));
|
||||
}
|
||||
|
||||
/* test values of valid classwords that we set */
|
||||
for(i=0; i<NUMCLASSWORDS; i++)
|
||||
{
|
||||
SetLastError(0);
|
||||
ok( (i+1) == GetClassLongW(hTestWnd,i*sizeof (DWORD)),
|
||||
"GetClassLongW value doesn't match what was set!\n");
|
||||
ok(!GetLastError(),
|
||||
"GetClassLongW failed!\n");
|
||||
}
|
||||
|
||||
/* check GetClassName */
|
||||
i = GetClassNameW(hTestWnd, str, sizeof(str));
|
||||
ok(i == lstrlenW(className),
|
||||
"GetClassName returned incorrect length\n");
|
||||
ok(!lstrcmpW(className,str),
|
||||
"GetClassName returned incorrect name for this window's class\n");
|
||||
|
||||
/* check GetClassInfo with our hInstance */
|
||||
if((test_atom = GetClassInfoW(hInstance, str, &wc)))
|
||||
{
|
||||
ok(test_atom == classatom,
|
||||
"class atom did not match\n");
|
||||
ok(wc.cbClsExtra == cls.cbClsExtra,
|
||||
"cbClsExtra did not match\n");
|
||||
ok(wc.cbWndExtra == cls.cbWndExtra,
|
||||
"cbWndExtra did not match\n");
|
||||
ok(wc.hbrBackground == cls.hbrBackground,
|
||||
"hbrBackground did not match\n");
|
||||
ok(wc.hCursor== cls.hCursor,
|
||||
"hCursor did not match\n");
|
||||
ok(wc.hInstance== cls.hInstance,
|
||||
"hInstance did not match\n");
|
||||
}
|
||||
else
|
||||
ok(FALSE,"GetClassInfo (hinstance) failed!\n");
|
||||
|
||||
/* check GetClassInfo with zero hInstance */
|
||||
if(global)
|
||||
{
|
||||
if((test_atom = GetClassInfoW(0, str, &wc)))
|
||||
{
|
||||
ok(test_atom == classatom,
|
||||
"class atom did not match %x != %x\n", test_atom, classatom);
|
||||
ok(wc.cbClsExtra == cls.cbClsExtra,
|
||||
"cbClsExtra did not match %x!=%x\n",wc.cbClsExtra,cls.cbClsExtra);
|
||||
ok(wc.cbWndExtra == cls.cbWndExtra,
|
||||
"cbWndExtra did not match %x!=%x\n",wc.cbWndExtra,cls.cbWndExtra);
|
||||
ok(wc.hbrBackground == cls.hbrBackground,
|
||||
"hbrBackground did not match %p!=%p\n",wc.hbrBackground,cls.hbrBackground);
|
||||
ok(wc.hCursor== cls.hCursor,
|
||||
"hCursor did not match %p!=%p\n",wc.hCursor,cls.hCursor);
|
||||
ok(!wc.hInstance,
|
||||
"hInstance not zero for global class %p\n",wc.hInstance);
|
||||
}
|
||||
else
|
||||
ok(FALSE,"GetClassInfo (0) failed for global class!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ok(!GetClassInfoW(0, str, &wc),
|
||||
"GetClassInfo (0) succeeded for local class!\n");
|
||||
}
|
||||
|
||||
ok(!UnregisterClassW(className, hInstance),
|
||||
"Unregister class succeeded with window existing\n");
|
||||
|
||||
ok(DestroyWindow(hTestWnd),
|
||||
"DestroyWindow() failed!\n");
|
||||
|
||||
ok(UnregisterClassW(className, hInstance),
|
||||
"UnregisterClass() failed\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void check_style( const char *name, int must_exist, UINT style, UINT ignore )
|
||||
{
|
||||
WNDCLASS wc;
|
||||
|
||||
if (GetClassInfo( 0, name, &wc ))
|
||||
{
|
||||
ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n",
|
||||
name, ~wc.style & style, wc.style, style );
|
||||
ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n",
|
||||
name, wc.style & ~style, wc.style, style );
|
||||
}
|
||||
else
|
||||
ok( !must_exist, "System class %s does not exist\n", name );
|
||||
}
|
||||
|
||||
/* test styles of system classes */
|
||||
static void test_styles(void)
|
||||
{
|
||||
/* check style bits */
|
||||
check_style( "Button", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 );
|
||||
check_style( "ComboBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 );
|
||||
check_style( "Edit", 1, CS_PARENTDC | CS_DBLCLKS, 0 );
|
||||
check_style( "ListBox", 1, CS_PARENTDC | CS_DBLCLKS, CS_PARENTDC /*FIXME*/ );
|
||||
check_style( "MDIClient", 1, 0, 0 );
|
||||
check_style( "ScrollBar", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 );
|
||||
check_style( "Static", 1, CS_PARENTDC | CS_DBLCLKS, 0 );
|
||||
check_style( "ComboLBox", 1, CS_SAVEBITS | CS_DBLCLKS, 0 );
|
||||
check_style( "DDEMLEvent", 0, 0, 0 );
|
||||
check_style( "Message", 0, 0, 0 );
|
||||
check_style( "#32768", 1, CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, CS_DROPSHADOW ); /* menu */
|
||||
check_style( "#32769", 1, CS_DBLCLKS, 0 ); /* desktop */
|
||||
check_style( "#32770", 1, CS_SAVEBITS | CS_DBLCLKS, 0 ); /* dialog */
|
||||
todo_wine { check_style( "#32771", 1, CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW, 0 ); } /* task switch */
|
||||
check_style( "#32772", 1, 0, 0 ); /* icon title */
|
||||
}
|
||||
|
||||
static void check_class(HINSTANCE inst, const char *name, const char *menu_name)
|
||||
{
|
||||
WNDCLASS wc;
|
||||
UINT atom = GetClassInfo(inst,name,&wc);
|
||||
ok( atom, "Class %s %p not found\n", name, inst );
|
||||
if (atom)
|
||||
{
|
||||
if (wc.lpszMenuName && menu_name)
|
||||
ok( !strcmp( menu_name, wc.lpszMenuName ), "Wrong name %s/%s for class %s %p\n",
|
||||
wc.lpszMenuName, menu_name, name, inst );
|
||||
else
|
||||
ok( !menu_name == !wc.lpszMenuName, "Wrong name %p/%p for class %s %p\n",
|
||||
wc.lpszMenuName, menu_name, name, inst );
|
||||
}
|
||||
}
|
||||
|
||||
static void check_instance( const char *name, HINSTANCE inst, HINSTANCE info_inst, HINSTANCE gcl_inst )
|
||||
{
|
||||
WNDCLASSA wc;
|
||||
HWND hwnd;
|
||||
|
||||
ok( GetClassInfo( inst, name, &wc ), "Couldn't find class %s inst %p\n", name, inst );
|
||||
ok( wc.hInstance == info_inst, "Wrong info instance %p/%p for class %s\n",
|
||||
wc.hInstance, info_inst, name );
|
||||
hwnd = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, inst, 0 );
|
||||
ok( hwnd != NULL, "Couldn't create window for class %s inst %p\n", name, inst );
|
||||
ok( (HINSTANCE)GetClassLongA( hwnd, GCL_HMODULE ) == gcl_inst,
|
||||
"Wrong GCL instance %p/%p for class %s\n",
|
||||
(HINSTANCE)GetClassLongA( hwnd, GCL_HMODULE ), gcl_inst, name );
|
||||
ok( (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE ) == inst,
|
||||
"Wrong GWL instance %p/%p for window %s\n",
|
||||
(HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE ), inst, name );
|
||||
ok(!UnregisterClassA(name, inst), "UnregisterClassA should fail while exists a class window\n");
|
||||
ok(GetLastError() == ERROR_CLASS_HAS_WINDOWS, "GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS not %ld\n", GetLastError());
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
struct class_info
|
||||
{
|
||||
const char *name;
|
||||
HINSTANCE inst, info_inst, gcl_inst;
|
||||
};
|
||||
|
||||
static DWORD WINAPI thread_proc(void *param)
|
||||
{
|
||||
struct class_info *class_info = (struct class_info *)param;
|
||||
|
||||
check_instance(class_info->name, class_info->inst, class_info->info_inst, class_info->gcl_inst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_thread_instance( const char *name, HINSTANCE inst, HINSTANCE info_inst, HINSTANCE gcl_inst )
|
||||
{
|
||||
HANDLE hThread;
|
||||
DWORD tid;
|
||||
struct class_info class_info;
|
||||
|
||||
class_info.name = name;
|
||||
class_info.inst = inst;
|
||||
class_info.info_inst = info_inst;
|
||||
class_info.gcl_inst = gcl_inst;
|
||||
|
||||
hThread = CreateThread(NULL, 0, thread_proc, &class_info, 0, &tid);
|
||||
ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
|
||||
ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
|
||||
/* test various instance parameters */
|
||||
static void test_instances(void)
|
||||
{
|
||||
WNDCLASSA cls, wc;
|
||||
HWND hwnd, hwnd2;
|
||||
const char *name = "__test__";
|
||||
HINSTANCE kernel32 = GetModuleHandleA("kernel32");
|
||||
HINSTANCE user32 = GetModuleHandleA("user32");
|
||||
HINSTANCE main_module = GetModuleHandleA(NULL);
|
||||
|
||||
memset( &cls, 0, sizeof(cls) );
|
||||
cls.style = CS_HREDRAW | CS_VREDRAW;
|
||||
cls.lpfnWndProc = ClassTest_WndProc;
|
||||
cls.cbClsExtra = 0;
|
||||
cls.cbWndExtra = 0;
|
||||
cls.lpszClassName = name;
|
||||
|
||||
cls.lpszMenuName = "main_module";
|
||||
cls.hInstance = main_module;
|
||||
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for main module\n" );
|
||||
check_class( main_module, name, "main_module" );
|
||||
check_instance( name, main_module, main_module, main_module );
|
||||
check_thread_instance( name, main_module, main_module, main_module );
|
||||
|
||||
cls.lpszMenuName = "kernel32";
|
||||
cls.hInstance = kernel32;
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
|
||||
check_class( kernel32, name, "kernel32" );
|
||||
check_class( main_module, name, "main_module" );
|
||||
check_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_thread_instance( name, kernel32, kernel32, kernel32 );
|
||||
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
|
||||
|
||||
/* Bug 2631 - Supplying an invalid number of bytes fails */
|
||||
cls.cbClsExtra = 0;
|
||||
cls.cbWndExtra = -1;
|
||||
SetLastError(0xdeadbeef);
|
||||
ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
|
||||
"Failed with invalid number of WndExtra bytes\n");
|
||||
|
||||
cls.cbClsExtra = -1;
|
||||
cls.cbWndExtra = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
|
||||
"Failed with invalid number of ClsExtra bytes\n");
|
||||
|
||||
cls.cbClsExtra = -1;
|
||||
cls.cbWndExtra = -1;
|
||||
SetLastError(0xdeadbeef);
|
||||
ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
|
||||
"Failed with invalid number of ClsExtra and cbWndExtra bytes\n");
|
||||
|
||||
cls.cbClsExtra = 0;
|
||||
cls.cbWndExtra = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
|
||||
/* setting global flag doesn't change status of class */
|
||||
hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 );
|
||||
SetClassLongA( hwnd, GCL_STYLE, CS_GLOBALCLASS );
|
||||
cls.lpszMenuName = "kernel32";
|
||||
cls.hInstance = kernel32;
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
|
||||
check_class( kernel32, name, "kernel32" );
|
||||
check_class( main_module, name, "main_module" );
|
||||
check_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_instance( name, main_module, main_module, main_module );
|
||||
check_thread_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_thread_instance( name, main_module, main_module, main_module );
|
||||
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
|
||||
|
||||
/* changing the instance doesn't make it global */
|
||||
SetClassLongA( hwnd, GCL_HMODULE, 0 );
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
|
||||
check_class( kernel32, name, "kernel32" );
|
||||
check_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_thread_instance( name, kernel32, kernel32, kernel32 );
|
||||
ok( !GetClassInfo( 0, name, &wc ), "Class found with null instance\n" );
|
||||
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
|
||||
|
||||
/* GetClassInfo with instance 0 finds user32 instance */
|
||||
SetClassLongA( hwnd, GCL_HMODULE, (LONG)user32 );
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
|
||||
check_class( kernel32, name, "kernel32" );
|
||||
check_class( user32, name, "main_module" );
|
||||
check_class( 0, name, "main_module" );
|
||||
check_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_instance( name, user32, 0, user32 );
|
||||
check_instance( name, 0, 0, kernel32 );
|
||||
check_thread_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_thread_instance( name, user32, 0, user32 );
|
||||
check_thread_instance( name, 0, 0, kernel32 );
|
||||
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
|
||||
|
||||
SetClassLongA( hwnd, GCL_HMODULE, 0x12345678 );
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
|
||||
check_class( kernel32, name, "kernel32" );
|
||||
check_class( (HINSTANCE)0x12345678, name, "main_module" );
|
||||
check_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 );
|
||||
check_thread_instance( name, kernel32, kernel32, kernel32 );
|
||||
check_thread_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 );
|
||||
ok( !GetClassInfo( 0, name, &wc ), "Class found with null instance\n" );
|
||||
|
||||
/* creating a window with instance 0 uses the first class found */
|
||||
cls.hInstance = (HINSTANCE)0xdeadbeef;
|
||||
cls.lpszMenuName = "deadbeef";
|
||||
cls.style = 3;
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for deadbeef\n" );
|
||||
hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 );
|
||||
ok( (HINSTANCE)GetClassLong( hwnd2, GCL_HMODULE ) == (HINSTANCE)0xdeadbeef,
|
||||
"Didn't get deadbeef class for null instance\n" );
|
||||
DestroyWindow( hwnd2 );
|
||||
ok( UnregisterClassA( name, (HINSTANCE)0xdeadbeef ), "Unregister failed for deadbeef\n" );
|
||||
|
||||
hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 );
|
||||
ok( (HINSTANCE)GetClassLong( hwnd2, GCL_HMODULE ) == kernel32,
|
||||
"Didn't get kernel32 class for null instance\n" );
|
||||
DestroyWindow( hwnd2 );
|
||||
|
||||
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
|
||||
|
||||
hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 );
|
||||
ok( GetClassLong( hwnd2, GCL_HMODULE ) == 0x12345678,
|
||||
"Didn't get 12345678 class for null instance\n" );
|
||||
DestroyWindow( hwnd2 );
|
||||
|
||||
SetClassLongA( hwnd, GCL_HMODULE, (LONG)main_module );
|
||||
DestroyWindow( hwnd );
|
||||
|
||||
/* null handle means the same thing as main module */
|
||||
cls.lpszMenuName = "null";
|
||||
cls.hInstance = 0;
|
||||
ok( !RegisterClassA( &cls ), "Succeeded registering local class for null instance\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %ld\n", GetLastError() );
|
||||
ok( UnregisterClassA( name, main_module ), "Unregister failed for main module\n" );
|
||||
|
||||
ok( RegisterClassA( &cls ), "Failed to register local class for null instance\n" );
|
||||
/* must be found with main module handle */
|
||||
check_class( main_module, name, "null" );
|
||||
check_instance( name, main_module, main_module, main_module );
|
||||
check_thread_instance( name, main_module, main_module, main_module );
|
||||
ok( !GetClassInfo( 0, name, &wc ), "Class found with null instance\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %ld\n", GetLastError() );
|
||||
ok( UnregisterClassA( name, 0 ), "Unregister failed for null instance\n" );
|
||||
|
||||
/* registering for user32 always fails */
|
||||
cls.lpszMenuName = "user32";
|
||||
cls.hInstance = user32;
|
||||
ok( !RegisterClassA( &cls ), "Succeeded registering local class for user32\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %ld\n", GetLastError() );
|
||||
cls.style |= CS_GLOBALCLASS;
|
||||
ok( !RegisterClassA( &cls ), "Succeeded registering global class for user32\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %ld\n", GetLastError() );
|
||||
|
||||
/* unregister is OK though */
|
||||
cls.hInstance = main_module;
|
||||
ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" );
|
||||
ok( UnregisterClassA( name, user32 ), "Unregister failed for user32\n" );
|
||||
|
||||
/* instance doesn't matter for global class */
|
||||
cls.style |= CS_GLOBALCLASS;
|
||||
cls.lpszMenuName = "main_module";
|
||||
cls.hInstance = main_module;
|
||||
ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" );
|
||||
cls.lpszMenuName = "kernel32";
|
||||
cls.hInstance = kernel32;
|
||||
ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %ld\n", GetLastError() );
|
||||
/* even if global flag is cleared */
|
||||
hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 );
|
||||
SetClassLongA( hwnd, GCL_STYLE, 0 );
|
||||
ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %ld\n", GetLastError() );
|
||||
|
||||
check_class( main_module, name, "main_module" );
|
||||
check_class( kernel32, name, "main_module" );
|
||||
check_class( 0, name, "main_module" );
|
||||
check_class( (HINSTANCE)0x12345678, name, "main_module" );
|
||||
check_instance( name, main_module, main_module, main_module );
|
||||
check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module );
|
||||
check_thread_instance( name, main_module, main_module, main_module );
|
||||
check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module );
|
||||
|
||||
/* changing the instance for global class doesn't make much difference */
|
||||
SetClassLongA( hwnd, GCL_HMODULE, 0xdeadbeef );
|
||||
check_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef );
|
||||
check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef );
|
||||
check_thread_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef );
|
||||
check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef );
|
||||
|
||||
DestroyWindow( hwnd );
|
||||
ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" );
|
||||
ok( !UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister succeeded the second time\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %ld\n", GetLastError() );
|
||||
|
||||
cls.hInstance = (HINSTANCE)0x12345678;
|
||||
ok( RegisterClassA( &cls ), "Failed to register global class for dummy instance\n" );
|
||||
check_instance( name, main_module, main_module, (HINSTANCE)0x12345678 );
|
||||
check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 );
|
||||
check_thread_instance( name, main_module, main_module, (HINSTANCE)0x12345678 );
|
||||
check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 );
|
||||
ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" );
|
||||
|
||||
/* check system classes */
|
||||
|
||||
/* we cannot register a global class with the name of a system class */
|
||||
cls.style |= CS_GLOBALCLASS;
|
||||
cls.lpszMenuName = "button_main_module";
|
||||
cls.lpszClassName = "BUTTON";
|
||||
cls.hInstance = main_module;
|
||||
ok( !RegisterClassA( &cls ), "Succeeded registering global button class for main module\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %ld\n", GetLastError() );
|
||||
cls.hInstance = kernel32;
|
||||
ok( !RegisterClassA( &cls ), "Succeeded registering global button class for kernel32\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %ld\n", GetLastError() );
|
||||
|
||||
/* local class is OK however */
|
||||
cls.style &= ~CS_GLOBALCLASS;
|
||||
cls.lpszMenuName = "button_main_module";
|
||||
cls.hInstance = main_module;
|
||||
ok( RegisterClassA( &cls ), "Failed to register local button class for main module\n" );
|
||||
check_class( main_module, "BUTTON", "button_main_module" );
|
||||
cls.lpszMenuName = "button_kernel32";
|
||||
cls.hInstance = kernel32;
|
||||
ok( RegisterClassA( &cls ), "Failed to register local button class for kernel32\n" );
|
||||
check_class( kernel32, "BUTTON", "button_kernel32" );
|
||||
check_class( main_module, "BUTTON", "button_main_module" );
|
||||
ok( UnregisterClassA( "BUTTON", kernel32 ), "Unregister failed for kernel32 button\n" );
|
||||
ok( UnregisterClassA( "BUTTON", main_module ), "Unregister failed for main module button\n" );
|
||||
/* GetClassInfo sets instance to passed value for global classes */
|
||||
check_instance( "BUTTON", 0, 0, user32 );
|
||||
check_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
|
||||
check_instance( "BUTTON", user32, 0, user32 );
|
||||
check_thread_instance( "BUTTON", 0, 0, user32 );
|
||||
check_thread_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
|
||||
check_thread_instance( "BUTTON", user32, 0, user32 );
|
||||
|
||||
/* we can unregister system classes */
|
||||
ok( GetClassInfo( 0, "BUTTON", &wc ), "Button class not found with null instance\n" );
|
||||
ok( GetClassInfo( kernel32, "BUTTON", &wc ), "Button class not found with kernel32\n" );
|
||||
ok( UnregisterClass( "BUTTON", (HINSTANCE)0x12345678 ), "Failed to unregister button\n" );
|
||||
ok( !UnregisterClass( "BUTTON", (HINSTANCE)0x87654321 ), "Unregistered button a second time\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %ld\n", GetLastError() );
|
||||
ok( !GetClassInfo( 0, "BUTTON", &wc ), "Button still exists\n" );
|
||||
ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %ld\n", GetLastError() );
|
||||
|
||||
/* we can change the instance of a system class */
|
||||
check_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
|
||||
check_thread_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
|
||||
hwnd = CreateWindowExA( 0, "EDIT", "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 );
|
||||
SetClassLongA( hwnd, GCL_HMODULE, 0xdeadbeef );
|
||||
check_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef );
|
||||
check_thread_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef );
|
||||
}
|
||||
|
||||
static LRESULT WINAPI TestDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static BOOL RegisterTestDialog(HINSTANCE hInstance)
|
||||
{
|
||||
WNDCLASSEX wcx;
|
||||
ATOM atom = 0;
|
||||
|
||||
ZeroMemory(&wcx, sizeof(WNDCLASSEX));
|
||||
wcx.cbSize = sizeof(wcx);
|
||||
wcx.lpfnWndProc = TestDlgProc;
|
||||
wcx.cbClsExtra = 0;
|
||||
wcx.cbWndExtra = DLGWINDOWEXTRA;
|
||||
wcx.hInstance = hInstance;
|
||||
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
||||
wcx.lpszClassName = "TestDialog";
|
||||
wcx.lpszMenuName = "TestDialog";
|
||||
wcx.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(5),
|
||||
IMAGE_ICON,
|
||||
GetSystemMetrics(SM_CXSMICON),
|
||||
GetSystemMetrics(SM_CYSMICON),
|
||||
LR_DEFAULTCOLOR);
|
||||
|
||||
atom = RegisterClassEx(&wcx);
|
||||
ok(atom != 0, "RegisterClassEx returned 0\n");
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
/* test registering a dialog box created by using the CLASS directive in a
|
||||
resource file, then test creating the dialog using CreateDialogParam. */
|
||||
static void WINAPI CreateDialogParamTest(HINSTANCE hInstance)
|
||||
{
|
||||
HWND hWndMain;
|
||||
|
||||
if (RegisterTestDialog(hInstance))
|
||||
{
|
||||
hWndMain = CreateDialogParam(hInstance, "CLASS_TEST_DIALOG", NULL, 0, 0);
|
||||
ok(hWndMain != NULL, "CreateDialogParam returned NULL\n");
|
||||
ShowWindow(hWndMain, SW_SHOW);
|
||||
DestroyWindow(hWndMain);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(class)
|
||||
{
|
||||
HANDLE hInstance = GetModuleHandleA( NULL );
|
||||
|
||||
if (!GetModuleHandleW(0))
|
||||
{
|
||||
trace("Class test is incompatible with Win9x implementation, skipping\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ClassTest(hInstance,FALSE);
|
||||
ClassTest(hInstance,TRUE);
|
||||
CreateDialogParamTest(hInstance);
|
||||
test_styles();
|
||||
test_instances();
|
||||
}
|
198
reactos/regtests/winetests/user32/clipboard.c
Executable file
198
reactos/regtests/winetests/user32/clipboard.c
Executable file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Unit test suite for clipboard functions.
|
||||
*
|
||||
* Copyright 2002 Dmitry Timoshkov
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "winuser.h"
|
||||
|
||||
static BOOL is_win9x = FALSE;
|
||||
|
||||
#define test_last_error(expected_error) \
|
||||
do \
|
||||
{ \
|
||||
if (!is_win9x) \
|
||||
ok(GetLastError() == expected_error, \
|
||||
"Last error should be set to %d, not %ld\n", \
|
||||
expected_error, GetLastError()); \
|
||||
} while (0)
|
||||
|
||||
static void test_ClipboardOwner(void)
|
||||
{
|
||||
HWND hWnd1, hWnd2;
|
||||
BOOL ret;
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef,
|
||||
"could not perform clipboard test: clipboard already owned\n");
|
||||
|
||||
hWnd1 = CreateWindowExA(0, "static", NULL, WS_POPUP,
|
||||
0, 0, 10, 10, 0, 0, 0, NULL);
|
||||
ok(hWnd1 != 0, "CreateWindowExA error %ld\n", GetLastError());
|
||||
trace("hWnd1 = %p\n", hWnd1);
|
||||
|
||||
hWnd2 = CreateWindowExA(0, "static", NULL, WS_POPUP,
|
||||
0, 0, 10, 10, 0, 0, 0, NULL);
|
||||
ok(hWnd2 != 0, "CreateWindowExA error %ld\n", GetLastError());
|
||||
trace("hWnd2 = %p\n", hWnd2);
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!CloseClipboard(), "CloseClipboard should fail if clipboard wasn't open\n");
|
||||
test_last_error(ERROR_CLIPBOARD_NOT_OPEN);
|
||||
|
||||
ok(OpenClipboard(0), "OpenClipboard failed\n");
|
||||
ok(!GetClipboardOwner(), "clipboard should still be not owned\n");
|
||||
ok(!OpenClipboard(hWnd1), "OpenClipboard should fail since clipboard already opened\n");
|
||||
ret = CloseClipboard();
|
||||
ok( ret, "CloseClipboard error %ld\n", GetLastError());
|
||||
|
||||
ok(OpenClipboard(hWnd1), "OpenClipboard failed\n");
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!OpenClipboard(hWnd2) && GetLastError() == 0xdeadbeef,
|
||||
"OpenClipboard should fail without setting last error value\n");
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should still be not owned\n");
|
||||
ret = EmptyClipboard();
|
||||
ok( ret, "EmptyClipboard error %ld\n", GetLastError());
|
||||
ok(GetClipboardOwner() == hWnd1, "clipboard should be owned by %p, not by %p\n", hWnd1, GetClipboardOwner());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!OpenClipboard(hWnd2) && GetLastError() == 0xdeadbeef,
|
||||
"OpenClipboard should fail without setting last error value\n");
|
||||
|
||||
ret = CloseClipboard();
|
||||
ok( ret, "CloseClipboard error %ld\n", GetLastError());
|
||||
ok(GetClipboardOwner() == hWnd1, "clipboard should still be owned\n");
|
||||
|
||||
ret = DestroyWindow(hWnd1);
|
||||
ok( ret, "DestroyWindow error %ld\n", GetLastError());
|
||||
ret = DestroyWindow(hWnd2);
|
||||
ok( ret, "DestroyWindow error %ld\n", GetLastError());
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n");
|
||||
}
|
||||
|
||||
static void test_RegisterClipboardFormatA(void)
|
||||
{
|
||||
ATOM atom_id;
|
||||
UINT format_id, format_id2;
|
||||
char buf[256];
|
||||
int len;
|
||||
BOOL ret;
|
||||
|
||||
format_id = RegisterClipboardFormatA("my_cool_clipboard_format");
|
||||
ok(format_id > 0xc000 && format_id < 0xffff, "invalid clipboard format id %04x\n", format_id);
|
||||
|
||||
format_id2 = RegisterClipboardFormatA("MY_COOL_CLIPBOARD_FORMAT");
|
||||
ok(format_id2 == format_id, "invalid clipboard format id %04x\n", format_id2);
|
||||
|
||||
len = GetClipboardFormatNameA(format_id, buf, 256);
|
||||
ok(len == lstrlenA("my_cool_clipboard_format"), "wrong format name length %d\n", len);
|
||||
ok(!lstrcmpA(buf, "my_cool_clipboard_format"), "wrong format name \"%s\"\n", buf);
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
SetLastError(0xdeadbeef);
|
||||
len = GetAtomNameA((ATOM)format_id, buf, 256);
|
||||
ok(len == 0, "GetAtomNameA should fail\n");
|
||||
test_last_error(ERROR_INVALID_HANDLE);
|
||||
|
||||
todo_wine
|
||||
{
|
||||
lstrcpyA(buf, "foo");
|
||||
SetLastError(0xdeadbeef);
|
||||
len = GlobalGetAtomNameA((ATOM)format_id, buf, 256);
|
||||
ok(len == 0, "GlobalGetAtomNameA should fail\n");
|
||||
test_last_error(ERROR_INVALID_HANDLE);
|
||||
}
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
atom_id = FindAtomA("my_cool_clipboard_format");
|
||||
ok(atom_id == 0, "FindAtomA should fail\n");
|
||||
test_last_error(ERROR_FILE_NOT_FOUND);
|
||||
|
||||
#if 0
|
||||
/* this relies on the clipboard and global atom table being different */
|
||||
SetLastError(0xdeadbeef);
|
||||
atom_id = GlobalFindAtomA("my_cool_clipboard_format");
|
||||
ok(atom_id == 0, "GlobalFindAtomA should fail\n");
|
||||
test_last_error(ERROR_FILE_NOT_FOUND);
|
||||
|
||||
for (format_id = 0; format_id < 0xffff; format_id++)
|
||||
{
|
||||
SetLastError(0xdeadbeef);
|
||||
len = GetClipboardFormatNameA(format_id, buf, 256);
|
||||
|
||||
if (format_id < 0xc000)
|
||||
{
|
||||
ok(!len, "GetClipboardFormatNameA should fail, but it returned %d (%s)\n", len, buf);
|
||||
test_last_error(ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len)
|
||||
trace("%04x: %s\n", format_id, len ? buf : "");
|
||||
else
|
||||
test_last_error(ERROR_INVALID_HANDLE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = OpenClipboard(0);
|
||||
ok( ret, "OpenClipboard error %ld\n", GetLastError());
|
||||
|
||||
trace("# of formats available: %d\n", CountClipboardFormats());
|
||||
|
||||
format_id = 0;
|
||||
while ((format_id = EnumClipboardFormats(format_id)))
|
||||
{
|
||||
ok(IsClipboardFormatAvailable(format_id), "format %04x was listed as available\n", format_id);
|
||||
len = GetClipboardFormatNameA(format_id, buf, 256);
|
||||
trace("%04x: %s\n", format_id, len ? buf : "");
|
||||
}
|
||||
|
||||
ret = EmptyClipboard();
|
||||
ok( ret, "EmptyClipboard error %ld\n", GetLastError());
|
||||
ret =CloseClipboard();
|
||||
ok( ret, "CloseClipboard error %ld\n", GetLastError());
|
||||
|
||||
if (CountClipboardFormats())
|
||||
{
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!EnumClipboardFormats(0), "EnumClipboardFormats should fail if clipboard wasn't open\n");
|
||||
ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN,
|
||||
"Last error should be set to ERROR_CLIPBOARD_NOT_OPEN, not %ld\n", GetLastError());
|
||||
}
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!EmptyClipboard(), "EmptyClipboard should fail if clipboard wasn't open\n");
|
||||
test_last_error(ERROR_CLIPBOARD_NOT_OPEN);
|
||||
}
|
||||
|
||||
START_TEST(clipboard)
|
||||
{
|
||||
SetLastError(0xdeadbeef);
|
||||
FindAtomW(NULL);
|
||||
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) is_win9x = TRUE;
|
||||
|
||||
test_RegisterClipboardFormatA();
|
||||
test_ClipboardOwner();
|
||||
}
|
416
reactos/regtests/winetests/user32/dce.c
Executable file
416
reactos/regtests/winetests/user32/dce.c
Executable file
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Unit tests for DCE support
|
||||
*
|
||||
* Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static HWND hwnd_cache, hwnd_owndc, hwnd_classdc, hwnd_classdc2;
|
||||
|
||||
/* test behavior of DC attributes with various GetDC/ReleaseDC combinations */
|
||||
static void test_dc_attributes(void)
|
||||
{
|
||||
HDC hdc, old_hdc;
|
||||
INT rop, def_rop;
|
||||
|
||||
/* test cache DC */
|
||||
|
||||
hdc = GetDC( hwnd_cache );
|
||||
def_rop = GetROP2( hdc );
|
||||
|
||||
SetROP2( hdc, R2_WHITE );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
|
||||
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
hdc = GetDC( hwnd_cache );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == def_rop, "wrong ROP2 %d after release\n", rop );
|
||||
SetROP2( hdc, R2_WHITE );
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
|
||||
hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
|
||||
rop = GetROP2( hdc );
|
||||
/* Win9x seems to silently ignore DCX_NORESETATTRS */
|
||||
ok( rop == def_rop || rop == R2_WHITE, "wrong ROP2 %d\n", rop );
|
||||
|
||||
SetROP2( hdc, R2_WHITE );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
|
||||
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == def_rop || rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
|
||||
hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == def_rop, "wrong ROP2 %d after release\n", rop );
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
|
||||
/* test own DC */
|
||||
|
||||
hdc = GetDC( hwnd_owndc );
|
||||
SetROP2( hdc, R2_WHITE );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
|
||||
|
||||
old_hdc = hdc;
|
||||
ReleaseDC( hwnd_owndc, hdc );
|
||||
hdc = GetDC( hwnd_owndc );
|
||||
ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
|
||||
ReleaseDC( hwnd_owndc, hdc );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
|
||||
|
||||
/* test class DC */
|
||||
|
||||
hdc = GetDC( hwnd_classdc );
|
||||
SetROP2( hdc, R2_WHITE );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
|
||||
|
||||
old_hdc = hdc;
|
||||
ReleaseDC( hwnd_classdc, hdc );
|
||||
hdc = GetDC( hwnd_classdc );
|
||||
ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
|
||||
ReleaseDC( hwnd_classdc, hdc );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
|
||||
|
||||
/* test class DC with 2 windows */
|
||||
|
||||
old_hdc = GetDC( hwnd_classdc );
|
||||
SetROP2( old_hdc, R2_BLACK );
|
||||
hdc = GetDC( hwnd_classdc2 );
|
||||
ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_BLACK, "wrong ROP2 %d for other window\n", rop );
|
||||
ReleaseDC( hwnd_classdc, old_hdc );
|
||||
ReleaseDC( hwnd_classdc, hdc );
|
||||
rop = GetROP2( hdc );
|
||||
ok( rop == R2_BLACK, "wrong ROP2 %d after release\n", rop );
|
||||
}
|
||||
|
||||
|
||||
/* test behavior with various invalid parameters */
|
||||
static void test_parameters(void)
|
||||
{
|
||||
HDC hdc;
|
||||
|
||||
hdc = GetDC( hwnd_cache );
|
||||
ok( ReleaseDC( hwnd_owndc, hdc ), "ReleaseDC with wrong window should succeed\n" );
|
||||
|
||||
hdc = GetDC( hwnd_cache );
|
||||
ok( !ReleaseDC( hwnd_cache, 0 ), "ReleaseDC with wrong HDC should fail\n" );
|
||||
ok( ReleaseDC( hwnd_cache, hdc ), "correct ReleaseDC should succeed\n" );
|
||||
ok( !ReleaseDC( hwnd_cache, hdc ), "second ReleaseDC should fail\n" );
|
||||
|
||||
hdc = GetDC( hwnd_owndc );
|
||||
ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
|
||||
hdc = GetDC( hwnd_owndc );
|
||||
ok( ReleaseDC( hwnd_owndc, hdc ), "correct ReleaseDC should succeed\n" );
|
||||
ok( ReleaseDC( hwnd_owndc, hdc ), "second ReleaseDC should succeed\n" );
|
||||
|
||||
hdc = GetDC( hwnd_classdc );
|
||||
ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
|
||||
hdc = GetDC( hwnd_classdc );
|
||||
ok( ReleaseDC( hwnd_classdc, hdc ), "correct ReleaseDC should succeed\n" );
|
||||
ok( ReleaseDC( hwnd_classdc, hdc ), "second ReleaseDC should succeed\n" );
|
||||
}
|
||||
|
||||
|
||||
static void test_dc_visrgn(void)
|
||||
{
|
||||
HDC old_hdc, hdc;
|
||||
HRGN hrgn, hrgn2;
|
||||
RECT rect;
|
||||
|
||||
/* cache DC */
|
||||
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
|
||||
hrgn = CreateRectRgnIndirect( &rect );
|
||||
hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
|
||||
|
||||
/* cache DC with NORESETATTRS */
|
||||
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
|
||||
hrgn = CreateRectRgnIndirect( &rect );
|
||||
hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE | DCX_NORESETATTRS );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
|
||||
hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
|
||||
"clip box sould have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ReleaseDC( hwnd_cache, hdc );
|
||||
|
||||
/* window DC */
|
||||
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
|
||||
hrgn = CreateRectRgnIndirect( &rect );
|
||||
hdc = GetDCEx( hwnd_owndc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
ReleaseDC( hwnd_owndc, hdc );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
hdc = GetDCEx( hwnd_owndc, 0, DCX_USESTYLE );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
ReleaseDC( hwnd_owndc, hdc );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
|
||||
SetRect( &rect, 20, 20, 30, 30 );
|
||||
MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
|
||||
hrgn2 = CreateRectRgnIndirect( &rect );
|
||||
hdc = GetDCEx( hwnd_owndc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
|
||||
ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
|
||||
ReleaseDC( hwnd_owndc, hdc );
|
||||
ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
|
||||
hdc = GetDCEx( hwnd_owndc, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
|
||||
ok( GetRgnBox( hrgn2, &rect ) == ERROR, "region must no longer be valid\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
|
||||
"clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ReleaseDC( hwnd_owndc, hdc );
|
||||
|
||||
/* class DC */
|
||||
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
|
||||
hrgn = CreateRectRgnIndirect( &rect );
|
||||
hdc = GetDCEx( hwnd_classdc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
ReleaseDC( hwnd_classdc, hdc );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
|
||||
hdc = GetDCEx( hwnd_classdc, 0, DCX_USESTYLE );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
ReleaseDC( hwnd_classdc, hdc );
|
||||
ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
|
||||
|
||||
SetRect( &rect, 20, 20, 30, 30 );
|
||||
MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
|
||||
hrgn2 = CreateRectRgnIndirect( &rect );
|
||||
hdc = GetDCEx( hwnd_classdc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
|
||||
ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
|
||||
|
||||
old_hdc = hdc;
|
||||
hdc = GetDCEx( hwnd_classdc2, 0, DCX_USESTYLE );
|
||||
ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
|
||||
ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
|
||||
"clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ReleaseDC( hwnd_classdc2, hdc );
|
||||
ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
|
||||
hdc = GetDCEx( hwnd_classdc2, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
|
||||
ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
|
||||
ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
|
||||
"clip box must have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ReleaseDC( hwnd_classdc2, hdc );
|
||||
}
|
||||
|
||||
|
||||
/* test various BeginPaint/EndPaint behaviors */
|
||||
static void test_begin_paint(void)
|
||||
{
|
||||
HDC old_hdc, hdc;
|
||||
RECT rect;
|
||||
PAINTSTRUCT ps;
|
||||
|
||||
/* cache DC */
|
||||
|
||||
/* clear update region */
|
||||
RedrawWindow( hwnd_cache, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
RedrawWindow( hwnd_cache, &rect, 0, RDW_INVALIDATE );
|
||||
hdc = BeginPaint( hwnd_cache, &ps );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
EndPaint( hwnd_cache, &ps );
|
||||
|
||||
/* window DC */
|
||||
|
||||
RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE );
|
||||
hdc = BeginPaint( hwnd_owndc, &ps );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ReleaseDC( hwnd_owndc, hdc );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
ok( GetDC( hwnd_owndc ) == hdc, "got different hdc\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
EndPaint( hwnd_owndc, &ps );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
|
||||
"clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE|RDW_ERASE );
|
||||
ok( GetDC( hwnd_owndc ) == hdc, "got different hdc\n" );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
|
||||
"clip box should be the whole window %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
RedrawWindow( hwnd_owndc, NULL, 0, RDW_ERASENOW );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
|
||||
"clip box should still be the whole window %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
|
||||
/* class DC */
|
||||
|
||||
RedrawWindow( hwnd_classdc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
|
||||
SetRect( &rect, 10, 10, 20, 20 );
|
||||
RedrawWindow( hwnd_classdc, &rect, 0, RDW_INVALIDATE );
|
||||
hdc = BeginPaint( hwnd_classdc, &ps );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
|
||||
"invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
|
||||
old_hdc = hdc;
|
||||
hdc = GetDC( hwnd_classdc2 );
|
||||
ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
|
||||
SetRectEmpty( &rect );
|
||||
GetClipBox( hdc, &rect );
|
||||
ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
|
||||
"clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
|
||||
}
|
||||
|
||||
|
||||
START_TEST(dce)
|
||||
{
|
||||
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, (LPSTR)IDC_ARROW);
|
||||
cls.hbrBackground = GetStockObject(WHITE_BRUSH);
|
||||
cls.lpszMenuName = NULL;
|
||||
cls.lpszClassName = "cache_class";
|
||||
RegisterClassA(&cls);
|
||||
cls.style = CS_DBLCLKS | CS_OWNDC;
|
||||
cls.lpszClassName = "owndc_class";
|
||||
RegisterClassA(&cls);
|
||||
cls.style = CS_DBLCLKS | CS_CLASSDC;
|
||||
cls.lpszClassName = "classdc_class";
|
||||
RegisterClassA(&cls);
|
||||
|
||||
hwnd_cache = CreateWindowA("cache_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
|
||||
0, 0, 100, 100,
|
||||
0, 0, GetModuleHandleA(0), NULL );
|
||||
hwnd_owndc = CreateWindowA("owndc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
|
||||
0, 200, 100, 100,
|
||||
0, 0, GetModuleHandleA(0), NULL );
|
||||
hwnd_classdc = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
|
||||
200, 0, 100, 100,
|
||||
0, 0, GetModuleHandleA(0), NULL );
|
||||
hwnd_classdc2 = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
|
||||
200, 200, 100, 100,
|
||||
0, 0, GetModuleHandleA(0), NULL );
|
||||
test_dc_attributes();
|
||||
test_parameters();
|
||||
test_dc_visrgn();
|
||||
test_begin_paint();
|
||||
}
|
390
reactos/regtests/winetests/user32/dde.c
Executable file
390
reactos/regtests/winetests/user32/dde.c
Executable file
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* Unit tests for DDE functions
|
||||
*
|
||||
* Copyright (c) 2004 Dmitry Timoshkov
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "dde.h"
|
||||
#include "ddeml.h"
|
||||
#include "winerror.h"
|
||||
|
||||
static const WCHAR TEST_DDE_SERVICE[] = {'T','e','s','t','D','D','E','S','e','r','v','i','c','e',0};
|
||||
|
||||
static const char exec_cmdA[] = "ANSI dde command";
|
||||
static const WCHAR exec_cmdW[] = {'u','n','i','c','o','d','e',' ','d','d','e',' ','c','o','m','m','a','n','d',0};
|
||||
|
||||
static WNDPROC old_dde_client_wndproc;
|
||||
|
||||
LRESULT WINAPI hook_dde_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
UINT_PTR lo, hi;
|
||||
|
||||
trace("hook_dde_client_wndproc: %p %04x %08x %08lx\n", hwnd, msg, wparam, lparam);
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DDE_ACK:
|
||||
UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
|
||||
trace("WM_DDE_ACK: status %04x hglobal %p\n", lo, (HGLOBAL)hi);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return CallWindowProcA(old_dde_client_wndproc, hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
trace("dde_server_wndproc: %p %04x %08x %08lx\n", hwnd, msg, wparam, lparam);
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DDE_INITIATE:
|
||||
{
|
||||
ATOM aService = GlobalAddAtomW(TEST_DDE_SERVICE);
|
||||
|
||||
trace("server: got WM_DDE_INITIATE from %p with %08lx\n", (HWND)wparam, lparam);
|
||||
|
||||
if (LOWORD(lparam) == aService)
|
||||
{
|
||||
ok(!IsWindowUnicode((HWND)wparam), "client should be an ANSI window\n");
|
||||
old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrA((HWND)wparam, GWLP_WNDPROC, (ULONG_PTR)hook_dde_client_wndproc);
|
||||
trace("server: sending WM_DDE_ACK to %p\n", (HWND)wparam);
|
||||
SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, MAKELPARAM(aService, 0));
|
||||
}
|
||||
else
|
||||
GlobalDeleteAtom(aService);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_DDE_EXECUTE:
|
||||
{
|
||||
DDEACK ack;
|
||||
WORD status;
|
||||
LPCSTR cmd;
|
||||
UINT_PTR lo, hi;
|
||||
|
||||
trace("server: got WM_DDE_EXECUTE from %p with %08lx\n", (HWND)wparam, lparam);
|
||||
|
||||
UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi);
|
||||
trace("%08lx => lo %04x hi %04x\n", lparam, lo, hi);
|
||||
|
||||
ack.bAppReturnCode = 0;
|
||||
ack.reserved = 0;
|
||||
ack.fBusy = 0;
|
||||
|
||||
cmd = GlobalLock((HGLOBAL)hi);
|
||||
|
||||
if (!cmd || (lstrcmpW((LPCWSTR)cmd, exec_cmdW) && lstrcmpA(cmd, exec_cmdA)))
|
||||
{
|
||||
trace("ignoring unknown WM_DDE_EXECUTE command\n");
|
||||
/* We have to send a negative acknowledge even if we don't
|
||||
* accept the command, otherwise Windows goes mad and next time
|
||||
* we send an acknowledge DDEML drops the connection.
|
||||
* Not sure how to call it: a bug or a feature.
|
||||
*/
|
||||
ack.fAck = 0;
|
||||
}
|
||||
else
|
||||
ack.fAck = 1;
|
||||
GlobalUnlock((HGLOBAL)hi);
|
||||
|
||||
trace("server: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam);
|
||||
|
||||
status = *((WORD *)&ack);
|
||||
lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, status, hi);
|
||||
|
||||
PostMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, lparam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_DDE_TERMINATE:
|
||||
{
|
||||
DDEACK ack;
|
||||
WORD status;
|
||||
|
||||
trace("server: got WM_DDE_TERMINATE from %p with %08lx\n", (HWND)wparam, lparam);
|
||||
|
||||
ack.bAppReturnCode = 0;
|
||||
ack.reserved = 0;
|
||||
ack.fBusy = 0;
|
||||
ack.fAck = 1;
|
||||
|
||||
trace("server: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam);
|
||||
|
||||
status = *((WORD *)&ack);
|
||||
lparam = PackDDElParam(WM_DDE_ACK, status, 0);
|
||||
|
||||
PostMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, lparam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProcW(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
static LRESULT WINAPI dde_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
static BOOL create_dde_windows(HWND *hwnd_client, HWND *hwnd_server)
|
||||
{
|
||||
WNDCLASSA wcA;
|
||||
WNDCLASSW wcW;
|
||||
static const WCHAR server_class_name[] = {'d','d','e','_','s','e','r','v','e','r','_','w','i','n','d','o','w',0};
|
||||
static const char client_class_name[] = "dde_client_window";
|
||||
|
||||
memset(&wcW, 0, sizeof(wcW));
|
||||
wcW.lpfnWndProc = dde_server_wndproc;
|
||||
wcW.lpszClassName = server_class_name;
|
||||
wcW.hInstance = GetModuleHandleA(0);
|
||||
if (!RegisterClassW(&wcW)) return FALSE;
|
||||
|
||||
memset(&wcA, 0, sizeof(wcA));
|
||||
wcA.lpfnWndProc = dde_client_wndproc;
|
||||
wcA.lpszClassName = client_class_name;
|
||||
wcA.hInstance = GetModuleHandleA(0);
|
||||
assert(RegisterClassA(&wcA));
|
||||
|
||||
*hwnd_server = CreateWindowExW(0, server_class_name, NULL,
|
||||
WS_POPUP,
|
||||
100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
GetDesktopWindow(), 0,
|
||||
GetModuleHandleA(0), NULL);
|
||||
assert(*hwnd_server);
|
||||
|
||||
*hwnd_client = CreateWindowExA(0, client_class_name, NULL,
|
||||
WS_POPUP,
|
||||
100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
GetDesktopWindow(), 0,
|
||||
GetModuleHandleA(0), NULL);
|
||||
assert(*hwnd_client);
|
||||
|
||||
trace("server hwnd %p, client hwnd %p\n", *hwnd_server, *hwnd_client);
|
||||
|
||||
ok(IsWindowUnicode(*hwnd_server), "server has to be a unicode window\n");
|
||||
ok(!IsWindowUnicode(*hwnd_client), "client has to be an ANSI window\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static HDDEDATA CALLBACK client_dde_callback(UINT uType, UINT uFmt, HCONV hconv,
|
||||
HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
|
||||
ULONG_PTR dwData1, ULONG_PTR dwData2)
|
||||
{
|
||||
static const char * const cmd_type[15] = {
|
||||
"XTYP_ERROR", "XTYP_ADVDATA", "XTYP_ADVREQ", "XTYP_ADVSTART",
|
||||
"XTYP_ADVSTOP", "XTYP_EXECUTE", "XTYP_CONNECT", "XTYP_CONNECT_CONFIRM",
|
||||
"XTYP_XACT_COMPLETE", "XTYP_POKE", "XTYP_REGISTER", "XTYP_REQUEST",
|
||||
"XTYP_DISCONNECT", "XTYP_UNREGISTER", "XTYP_WILDCONNECT" };
|
||||
UINT type;
|
||||
const char *cmd_name;
|
||||
|
||||
type = (uType & XTYP_MASK) >> XTYP_SHIFT;
|
||||
cmd_name = (type >= 0 && type <= 14) ? cmd_type[type] : "unknown";
|
||||
|
||||
trace("client_dde_callback: %04x (%s) %d %p %p %p %p %08lx %08lx\n",
|
||||
uType, cmd_name, uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_dde_transaction(void)
|
||||
{
|
||||
HSZ hsz_server;
|
||||
DWORD dde_inst, ret, err;
|
||||
HCONV hconv;
|
||||
HWND hwnd_client, hwnd_server;
|
||||
CONVINFO info;
|
||||
HDDEDATA hdata;
|
||||
static const char test_cmd[] = "test dde command";
|
||||
|
||||
/* server: unicode, client: ansi */
|
||||
if (!create_dde_windows(&hwnd_client, &hwnd_server)) return;
|
||||
|
||||
dde_inst = 0;
|
||||
ret = DdeInitializeA(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0);
|
||||
ok(ret == DMLERR_NO_ERROR, "DdeInitializeW failed with error %04lx (%x)\n",
|
||||
ret, DdeGetLastError(dde_inst));
|
||||
|
||||
hsz_server = DdeCreateStringHandleW(dde_inst, TEST_DDE_SERVICE, CP_WINUNICODE);
|
||||
|
||||
hconv = DdeConnect(dde_inst, hsz_server, 0, NULL);
|
||||
ok(hconv != 0, "DdeConnect error %x\n", DdeGetLastError(dde_inst));
|
||||
err = DdeGetLastError(dde_inst);
|
||||
ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err);
|
||||
|
||||
info.cb = sizeof(info);
|
||||
ret = DdeQueryConvInfo(hconv, QID_SYNC, &info);
|
||||
ok(ret, "wrong info size %ld, DdeQueryConvInfo error %x\n", ret, DdeGetLastError(dde_inst));
|
||||
/* should be CP_WINANSI since we used DdeInitializeA */
|
||||
ok(info.ConvCtxt.iCodePage == CP_WINANSI, "wrong iCodePage %d\n", info.ConvCtxt.iCodePage);
|
||||
ok(!info.hConvPartner, "unexpected info.hConvPartner: %p\n", info.hConvPartner);
|
||||
todo_wine {
|
||||
ok((info.wStatus & DDE_FACK), "unexpected info.wStatus: %04x\n", info.wStatus);
|
||||
}
|
||||
ok((info.wStatus & (ST_CONNECTED | ST_CLIENT)) == (ST_CONNECTED | ST_CLIENT), "unexpected info.wStatus: %04x\n", info.wStatus);
|
||||
ok(info.wConvst == XST_CONNECTED, "unexpected info.wConvst: %04x\n", info.wConvst);
|
||||
ok(info.wType == 0, "unexpected info.wType: %04x\n", info.wType);
|
||||
|
||||
trace("hwnd %p, hwndPartner %p\n", info.hwnd, info.hwndPartner);
|
||||
|
||||
trace("sending test client transaction command\n");
|
||||
ret = 0xdeadbeef;
|
||||
hdata = DdeClientTransaction((LPBYTE)test_cmd, strlen(test_cmd) + 1, hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret);
|
||||
ok(!hdata, "DdeClientTransaction succeeded\n");
|
||||
ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret);
|
||||
err = DdeGetLastError(dde_inst);
|
||||
ok(err == DMLERR_NOTPROCESSED, "wrong dde error %lx\n", err);
|
||||
|
||||
trace("sending ANSI client transaction command\n");
|
||||
ret = 0xdeadbeef;
|
||||
hdata = DdeClientTransaction((LPBYTE)exec_cmdA, lstrlenA(exec_cmdA) + 1, hconv, 0, 0, XTYP_EXECUTE, 1000, &ret);
|
||||
ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, DdeGetLastError(dde_inst));
|
||||
ok(ret == DDE_FACK, "wrong status code %04lx\n", ret);
|
||||
|
||||
err = DdeGetLastError(dde_inst);
|
||||
ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err);
|
||||
|
||||
trace("sending unicode client transaction command\n");
|
||||
ret = 0xdeadbeef;
|
||||
hdata = DdeClientTransaction((LPBYTE)exec_cmdW, (lstrlenW(exec_cmdW) + 1) * sizeof(WCHAR), hconv, 0, 0, XTYP_EXECUTE, 1000, &ret);
|
||||
ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, DdeGetLastError(dde_inst));
|
||||
ok(ret == DDE_FACK, "wrong status code %04lx\n", ret);
|
||||
err = DdeGetLastError(dde_inst);
|
||||
ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err);
|
||||
|
||||
ok(DdeDisconnect(hconv), "DdeDisconnect error %x\n", DdeGetLastError(dde_inst));
|
||||
|
||||
info.cb = sizeof(info);
|
||||
ret = DdeQueryConvInfo(hconv, QID_SYNC, &info);
|
||||
ok(!ret, "DdeQueryConvInfo should fail\n");
|
||||
err = DdeGetLastError(dde_inst);
|
||||
todo_wine {
|
||||
ok(err == DMLERR_INVALIDPARAMETER, "wrong dde error %lx\n", err);
|
||||
}
|
||||
|
||||
ok(DdeFreeStringHandle(dde_inst, hsz_server), "DdeFreeStringHandle error %x\n", DdeGetLastError(dde_inst));
|
||||
|
||||
/* This call hangs on win2k SP4.
|
||||
DdeUninitialize(dde_inst);*/
|
||||
|
||||
DestroyWindow(hwnd_client);
|
||||
DestroyWindow(hwnd_server);
|
||||
|
||||
DdeUninitialize(dde_inst);
|
||||
}
|
||||
|
||||
static void test_DdeCreateStringHandleW(DWORD dde_inst, int codepage)
|
||||
{
|
||||
static const WCHAR dde_string[] = {'D','D','E',' ','S','t','r','i','n','g',0};
|
||||
HSZ str_handle;
|
||||
WCHAR bufW[256];
|
||||
char buf[256];
|
||||
int ret;
|
||||
|
||||
str_handle = DdeCreateStringHandleW(dde_inst, dde_string, codepage);
|
||||
ok(str_handle != 0, "DdeCreateStringHandleW failed with error %08x\n",
|
||||
DdeGetLastError(dde_inst));
|
||||
|
||||
ret = DdeQueryStringW(dde_inst, str_handle, NULL, 0, codepage);
|
||||
if (codepage == CP_WINANSI)
|
||||
ok(ret == 1, "DdeQueryStringW returned wrong length %d\n", ret);
|
||||
else
|
||||
ok(ret == lstrlenW(dde_string), "DdeQueryStringW returned wrong length %d\n", ret);
|
||||
|
||||
ret = DdeQueryStringW(dde_inst, str_handle, bufW, 256, codepage);
|
||||
if (codepage == CP_WINANSI)
|
||||
{
|
||||
ok(ret == 1, "DdeQueryStringW returned wrong length %d\n", ret);
|
||||
ok(!lstrcmpA("D", (LPCSTR)bufW), "DdeQueryStringW returned wrong string\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ok(ret == lstrlenW(dde_string), "DdeQueryStringW returned wrong length %d\n", ret);
|
||||
ok(!lstrcmpW(dde_string, bufW), "DdeQueryStringW returned wrong string\n");
|
||||
}
|
||||
|
||||
ret = DdeQueryStringA(dde_inst, str_handle, buf, 256, CP_WINANSI);
|
||||
if (codepage == CP_WINANSI)
|
||||
{
|
||||
ok(ret == 1, "DdeQueryStringA returned wrong length %d\n", ret);
|
||||
ok(!lstrcmpA("D", buf), "DdeQueryStringW returned wrong string\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ok(ret == lstrlenA("DDE String"), "DdeQueryStringA returned wrong length %d\n", ret);
|
||||
ok(!lstrcmpA("DDE String", buf), "DdeQueryStringA returned wrong string %s\n", buf);
|
||||
}
|
||||
|
||||
ret = DdeQueryStringA(dde_inst, str_handle, buf, 256, CP_WINUNICODE);
|
||||
if (codepage == CP_WINANSI)
|
||||
{
|
||||
ok(ret == 1, "DdeQueryStringA returned wrong length %d\n", ret);
|
||||
ok(!lstrcmpA("D", buf), "DdeQueryStringA returned wrong string %s\n", buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok(ret == lstrlenA("DDE String"), "DdeQueryStringA returned wrong length %d\n", ret);
|
||||
ok(!lstrcmpW(dde_string, (LPCWSTR)buf), "DdeQueryStringW returned wrong string\n");
|
||||
}
|
||||
|
||||
ok(DdeFreeStringHandle(dde_inst, str_handle), "DdeFreeStringHandle failed\n");
|
||||
}
|
||||
|
||||
static void test_DdeCreateStringHandle(void)
|
||||
{
|
||||
DWORD dde_inst, ret;
|
||||
|
||||
dde_inst = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = DdeInitializeW(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0);
|
||||
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||
{
|
||||
trace("Skipping the DDE test on a Win9x platform\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(ret == DMLERR_INVALIDPARAMETER, "DdeInitializeW should fail, but got %04lx instead\n", ret);
|
||||
ok(DdeGetLastError(dde_inst) == DMLERR_INVALIDPARAMETER, "expected DMLERR_INVALIDPARAMETER\n");
|
||||
|
||||
dde_inst = 0;
|
||||
ret = DdeInitializeW(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0);
|
||||
ok(ret == DMLERR_NO_ERROR, "DdeInitializeW failed with error %04lx (%08x)\n",
|
||||
ret, DdeGetLastError(dde_inst));
|
||||
|
||||
test_DdeCreateStringHandleW(dde_inst, 0);
|
||||
test_DdeCreateStringHandleW(dde_inst, CP_WINUNICODE);
|
||||
test_DdeCreateStringHandleW(dde_inst, CP_WINANSI);
|
||||
|
||||
ok(DdeUninitialize(dde_inst), "DdeUninitialize failed\n");
|
||||
}
|
||||
|
||||
START_TEST(dde)
|
||||
{
|
||||
test_DdeCreateStringHandle();
|
||||
test_dde_transaction();
|
||||
}
|
876
reactos/regtests/winetests/user32/dialog.c
Executable file
876
reactos/regtests/winetests/user32/dialog.c
Executable file
|
@ -0,0 +1,876 @@
|
|||
/* Unit test suite for the dialog functions.
|
||||
*
|
||||
* Copyright 2004 Bill Medland
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*
|
||||
*
|
||||
* This test suite currently works by building a quite complex hierarchy of
|
||||
* objects in a variety of styles and then performs a limited number of tests
|
||||
* for the previous and next dialog group or tab items.
|
||||
*
|
||||
* The test specifically does not test all possibilities at this time since
|
||||
* there are several cases where the Windows behaviour is rather strange and
|
||||
* significant work would be required to get the Wine code to duplicate the
|
||||
* strangeness, especially since most are in situations that would not
|
||||
* normally be met.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
|
||||
#define MAXHWNDS 1024
|
||||
static HWND hwnd [MAXHWNDS];
|
||||
static unsigned int numwnds=1; /* 0 is reserved for null */
|
||||
|
||||
/* Global handles */
|
||||
static HINSTANCE g_hinst; /* This application's HINSTANCE */
|
||||
static HWND g_hwndMain, g_hwndButton1, g_hwndButton2, g_hwndButtonCancel;
|
||||
static HWND g_hwndTestDlg, g_hwndTestDlgBut1, g_hwndTestDlgBut2, g_hwndTestDlgEdit;
|
||||
static HWND g_hwndInitialFocusT1, g_hwndInitialFocusT2, g_hwndInitialFocusGroupBox;
|
||||
|
||||
static LONG g_styleInitialFocusT1, g_styleInitialFocusT2;
|
||||
static BOOL g_bInitialFocusInitDlgResult;
|
||||
|
||||
static int g_terminated;
|
||||
|
||||
typedef struct {
|
||||
unsigned int id;
|
||||
int parent;
|
||||
DWORD style;
|
||||
DWORD exstyle;
|
||||
} h_entry;
|
||||
|
||||
static const h_entry hierarchy [] = {
|
||||
/* 0 is reserved for the null window */
|
||||
{ 1, 0, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE},
|
||||
{ 20, 1, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 2, 1, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
|
||||
{ 60, 2, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
/* What happens with groups when the parent is disabled */
|
||||
{ 8, 2, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, WS_EX_CONTROLPARENT},
|
||||
{ 85, 8, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP, 0},
|
||||
{ 9, 8, WS_CHILD, WS_EX_CONTROLPARENT},
|
||||
{ 86, 9, WS_CHILD | WS_VISIBLE, 0},
|
||||
{ 87, 9, WS_CHILD | WS_VISIBLE, 0},
|
||||
{ 31, 8, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 10, 2, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
|
||||
{ 88, 10, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 11, 10, WS_CHILD, WS_EX_CONTROLPARENT},
|
||||
{ 89, 11, WS_CHILD | WS_VISIBLE, 0},
|
||||
{ 32, 11, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 90, 11, WS_CHILD | WS_VISIBLE, 0},
|
||||
{ 33, 10, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 21, 2, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 61, 2, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
{ 3, 1, WS_CHILD | WS_VISIBLE | DS_CONTROL, 0},
|
||||
{ 22, 3, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 62, 3, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
{ 7, 3, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
|
||||
{ 4, 7, WS_CHILD | WS_VISIBLE | DS_CONTROL, 0},
|
||||
{ 83, 4, WS_CHILD | WS_VISIBLE, 0},
|
||||
{ 5, 4, WS_CHILD | WS_VISIBLE | DS_CONTROL, 0},
|
||||
/* A couple of controls around the main dialog */
|
||||
{ 29, 5, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 81, 5, WS_CHILD | WS_VISIBLE, 0},
|
||||
/* The main dialog with lots of controls */
|
||||
{ 6, 5, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
|
||||
/* At the start of a dialog */
|
||||
/* Disabled controls are skipped */
|
||||
{ 63, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
|
||||
/* Invisible controls are skipped */
|
||||
{ 64, 6, WS_CHILD | WS_TABSTOP, 0},
|
||||
/* Invisible disabled controls are skipped */
|
||||
{ 65, 6, WS_CHILD | WS_DISABLED | WS_TABSTOP, 0},
|
||||
/* Non-tabstop controls are skipped for tabs but not for groups */
|
||||
{ 66, 6, WS_CHILD | WS_VISIBLE, 0},
|
||||
/* End of first group, with no tabstops in it */
|
||||
{ 23, 6, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
/* At last a tabstop */
|
||||
{ 67, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
/* A group that is totally disabled or invisible */
|
||||
{ 24, 6, WS_CHILD | WS_DISABLED | WS_GROUP, 0},
|
||||
{ 68, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
|
||||
{ 69, 6, WS_CHILD | WS_TABSTOP, 0},
|
||||
/* A valid group in the middle of the dialog (not the first nor last group*/
|
||||
{ 25, 6, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
/* A non-tabstop item will be skipped for tabs */
|
||||
{ 70, 6, WS_CHILD | WS_VISIBLE, 0},
|
||||
/* A disabled item will be skipped for tabs and groups */
|
||||
{ 71, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
|
||||
/* A valid item will be found for tabs and groups */
|
||||
{ 72, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
/* A disabled item to skip when looking for the next group item */
|
||||
{ 73, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
|
||||
/* The next group begins with an enabled visible label */
|
||||
{ 26, 6, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
{ 74, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
{ 75, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
/* That group is terminated by a disabled label */
|
||||
{ 27, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_GROUP, 0},
|
||||
{ 76, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
{ 77, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
/* That group is terminated by an invisible label */
|
||||
{ 28, 6, WS_CHILD | WS_GROUP, 0},
|
||||
/* The end of the dialog with item for loop and recursion testing */
|
||||
{ 78, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
/* No tabstop so skipped for prev tab, but found for prev group */
|
||||
{ 79, 6, WS_CHILD | WS_VISIBLE, 0},
|
||||
{ 80, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
|
||||
/* A couple of controls after the main dialog */
|
||||
{ 82, 5, WS_CHILD | WS_VISIBLE, 0},
|
||||
{ 30, 5, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
|
||||
/* And around them */
|
||||
{ 84, 4, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static BOOL CreateWindows (HINSTANCE hinst)
|
||||
{
|
||||
const h_entry *p = hierarchy;
|
||||
|
||||
while (p->id != 0)
|
||||
{
|
||||
DWORD style, exstyle;
|
||||
char ctrlname[9];
|
||||
|
||||
/* Basically assert that the hierarchy is valid and track the
|
||||
* maximum control number
|
||||
*/
|
||||
if (p->id >= numwnds)
|
||||
{
|
||||
if (p->id >= sizeof(hwnd)/sizeof(hwnd[0]))
|
||||
{
|
||||
trace ("Control %d is out of range\n", p->id);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
numwnds = p->id+1;
|
||||
}
|
||||
if (p->id <= 0)
|
||||
{
|
||||
trace ("Control %d is out of range\n", p->id);
|
||||
return FALSE;
|
||||
}
|
||||
if (hwnd[p->id] != 0)
|
||||
{
|
||||
trace ("Control %d is used more than once\n", p->id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Create the control */
|
||||
sprintf (ctrlname, "ctrl%4.4d", p->id);
|
||||
hwnd[p->id] = CreateWindowEx (p->exstyle, TEXT(p->parent ? "static" : "GetNextDlgItemWindowClass"), TEXT(ctrlname), p->style, 10, 10, 10, 10, hwnd[p->parent], p->parent ? (HMENU) (2000 + p->id) : 0, hinst, 0);
|
||||
if (!hwnd[p->id])
|
||||
{
|
||||
trace ("Failed to create control %d\n", p->id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check that the styles are as we specified (except the main one
|
||||
* which is quite frequently messed up). If this keeps breaking then
|
||||
* we could mask out the bits that don't concern us.
|
||||
*/
|
||||
if (p->parent)
|
||||
{
|
||||
style = GetWindowLong (hwnd[p->id], GWL_STYLE);
|
||||
exstyle = GetWindowLong (hwnd[p->id], GWL_EXSTYLE);
|
||||
if (style == p->style && exstyle == p->exstyle)
|
||||
{
|
||||
trace ("Style mismatch at %d: %8.8lx %8.8lx cf %8.8lx %8.8lx\n", p->id, style, exstyle, p->style, p->exstyle);
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Form the lParam of a WM_KEYDOWN message */
|
||||
static DWORD KeyDownData (int repeat, int scancode, int extended, int wasdown)
|
||||
{
|
||||
return ((repeat & 0x0000FFFF) | ((scancode & 0x00FF) >> 16) |
|
||||
(extended ? 0x01000000 : 0) | (wasdown ? 0x40000000 : 0));
|
||||
}
|
||||
|
||||
/* Form a WM_KEYDOWN VK_TAB message to the specified window */
|
||||
static void FormTabMsg (MSG *pMsg, HWND hwnd)
|
||||
{
|
||||
pMsg->hwnd = hwnd;
|
||||
pMsg->message = WM_KEYDOWN;
|
||||
pMsg->wParam = VK_TAB;
|
||||
pMsg->lParam = KeyDownData (1, 0x0F, 0, 0);
|
||||
/* pMsg->time is not set. It shouldn't be needed */
|
||||
/* pMsg->pt is ignored */
|
||||
}
|
||||
|
||||
/* Form a WM_KEYDOWN VK_RETURN message to the specified window */
|
||||
static void FormEnterMsg (MSG *pMsg, HWND hwnd)
|
||||
{
|
||||
pMsg->hwnd = hwnd;
|
||||
pMsg->message = WM_KEYDOWN;
|
||||
pMsg->wParam = VK_RETURN;
|
||||
pMsg->lParam = KeyDownData (1, 0x1C, 0, 0);
|
||||
/* pMsg->time is not set. It shouldn't be needed */
|
||||
/* pMsg->pt is ignored */
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* The actual tests
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int isok; /* or is it todo */
|
||||
int test;
|
||||
int dlg;
|
||||
int ctl;
|
||||
int tab;
|
||||
int prev;
|
||||
int res;
|
||||
} test_record;
|
||||
|
||||
static int id (HWND h)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < numwnds; i++)
|
||||
if (hwnd[i] == h)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Tests
|
||||
*
|
||||
* Tests 1-8 test the hCtl argument of null or the dialog itself.
|
||||
*
|
||||
* 1. Prev Group of null is null
|
||||
* 2. Prev Tab of null is null
|
||||
* 3. Prev Group of hDlg in hDlg is null
|
||||
* 4. Prev Tab of hDlg in hDlg is null
|
||||
* 5. Next Group of null is first visible enabled child
|
||||
* Check it skips invisible, diabled and both.
|
||||
* 6. Next Tab of null is first visible enabled tabstop
|
||||
* Check it skips invisible, disabled, nontabstop, and in combination.
|
||||
* 7. Next Group of hDlg in hDlg is as of null
|
||||
* 8. Next Tab of hDlg in hDlg is as of null
|
||||
*
|
||||
* Tests 9-14 test descent
|
||||
*
|
||||
* 9. DS_CONTROL does not result in descending the hierarchy for Tab Next
|
||||
* 10. DS_CONTROL does not result in descending the hierarchy for Group Next
|
||||
* 11. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Next
|
||||
* 12. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Next
|
||||
* 13. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Prev
|
||||
* 14. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Prev
|
||||
*
|
||||
* Tests 15-24 are the basic Prev/Next Group tests
|
||||
*
|
||||
* 15. Next Group of a visible enabled non-group control is the next visible
|
||||
* enabled non-group control, if there is one before the next group
|
||||
* 16. Next Group of a visible enabled non-group control wraps around to the
|
||||
* beginning of the group on finding a control that starts another group.
|
||||
* Note that the group is in the middle of the dialog.
|
||||
* 17. As 16 except note that the next group is started with a disabled
|
||||
* visible control.
|
||||
* 18. As 16 except note that the next group is started with an invisible
|
||||
* enabled control.
|
||||
* 19. Next Group wraps around the controls of the dialog
|
||||
* 20. Next Group is the same even if the initial control is disabled.
|
||||
* 21. Next Group is the same even if the initial control is invisible.
|
||||
* 22. Next Group is the same even if the initial control has the group style
|
||||
* 23. Next Group returns the initial control if there is no visible enabled
|
||||
* control in the group. (Initial control disabled and not group style).
|
||||
* 24. Prev version of test 16.
|
||||
* Prev Group of a visible enabled non-group control wraps around to the
|
||||
* beginning of the group on finding a control that starts the group.
|
||||
* Note that the group is in the middle of the dialog.
|
||||
*
|
||||
* In tests 25 to 28 the control is sitting under dialogs which do not have
|
||||
* the WS_EX_CONTROLPARENT style and so cannot be reached from the top of
|
||||
* the dialog.
|
||||
*
|
||||
* 25. Next Group of an inaccessible control is as if it were accessible
|
||||
* 26. Prev Group of an inaccessible control begins searching at the highest
|
||||
* level ancestor that did not permit recursion down the hierarchy
|
||||
* 27. Next Tab of an inaccessible control is as if it were accessible
|
||||
* 28. Prev Tab of an inaccessible control begins searching at the highest
|
||||
* level ancestor that did not permit recursion down the hierarchy.
|
||||
*
|
||||
* Tests 29- are the basic Tab tests
|
||||
*
|
||||
* 29. Next Tab of a control is the next visible enabled control with the
|
||||
* Tabstop style (N.B. skips disabled, invisible and non-tabstop)
|
||||
* 30. Prev Tab of a control is the previous visible enabled control with the
|
||||
* Tabstop style (N.B. skips disabled, invisible and non-tabstop)
|
||||
* 31. Next Tab test with at least two layers of descent and finding the
|
||||
* result not at the first control.
|
||||
* 32. Next Tab test with at least two layers of descent with the descent and
|
||||
* control at the start of each level.
|
||||
* 33. Prev Tab test with at least two layers of descent and finding the
|
||||
* result not at the last control.
|
||||
* 34. Prev Tab test with at least two layers of descent with the descent and
|
||||
* control at the end of each level.
|
||||
*
|
||||
* 35. Passing NULL may result in the first child being the one returned.
|
||||
* (group test)
|
||||
* 36. Passing NULL may result in the first child being the one returned.
|
||||
* (tab test)
|
||||
*/
|
||||
|
||||
static void GetNextDlgItemTest (void)
|
||||
{
|
||||
static test_record test [] =
|
||||
{
|
||||
/* isok test dlg ctl tab prev res */
|
||||
|
||||
{ 1, 1, 6, 0, 0, 1, 0},
|
||||
{ 1, 2, 6, 0, 1, 1, 0},
|
||||
{ 1, 3, 6, 6, 0, 1, 0},
|
||||
{ 1, 4, 6, 6, 1, 1, 0},
|
||||
{ 1, 5, 6, 0, 0, 0, 66},
|
||||
{ 1, 6, 6, 0, 1, 0, 67},
|
||||
{ 1, 7, 6, 6, 0, 0, 66},
|
||||
{ 1, 8, 6, 6, 1, 0, 67},
|
||||
|
||||
{ 1, 9, 4, 83, 1, 0, 84},
|
||||
{ 1, 10, 4, 83, 0, 0, 5},
|
||||
{ 1, 11, 5, 81, 1, 0, 67},
|
||||
{ 1, 12, 5, 81, 0, 0, 66},
|
||||
{ 1, 13, 5, 82, 1, 1, 78},
|
||||
|
||||
{ 1, 14, 5, 82, 0, 1, 79},
|
||||
{ 1, 15, 6, 70, 0, 0, 72},
|
||||
{ 1, 16, 6, 72, 0, 0, 25},
|
||||
{ 1, 17, 6, 75, 0, 0, 26},
|
||||
{ 1, 18, 6, 77, 0, 0, 76},
|
||||
{ 1, 19, 6, 79, 0, 0, 66},
|
||||
{ 1, 20, 6, 71, 0, 0, 72},
|
||||
{ 1, 21, 6, 64, 0, 0, 66},
|
||||
|
||||
{ 1, 22, 6, 25, 0, 0, 70},
|
||||
{ 1, 23, 6, 68, 0, 0, 68},
|
||||
{ 1, 24, 6, 25, 0, 1, 72},
|
||||
{ 1, 25, 1, 70, 0, 0, 72},
|
||||
/*{ 0, 26, 1, 70, 0, 1, 3}, Crashes Win95*/
|
||||
{ 1, 27, 1, 70, 1, 0, 72},
|
||||
/*{ 0, 28, 1, 70, 1, 1, 61}, Crashes Win95*/
|
||||
|
||||
{ 1, 29, 6, 67, 1, 0, 72},
|
||||
{ 1, 30, 6, 72, 1, 1, 67},
|
||||
|
||||
{ 1, 35, 2, 0, 0, 0, 60},
|
||||
{ 1, 36, 2, 0, 1, 0, 60},
|
||||
|
||||
{ 0, 0, 0, 0, 0, 0, 0} /* End of test */
|
||||
};
|
||||
const test_record *p = test;
|
||||
|
||||
ok (CreateWindows (g_hinst), "Could not create test windows\n");
|
||||
|
||||
while (p->dlg)
|
||||
{
|
||||
HWND a;
|
||||
a = (p->tab ? GetNextDlgTabItem : GetNextDlgGroupItem) (hwnd[p->dlg], hwnd[p->ctl], p->prev);
|
||||
if (p->isok)
|
||||
{
|
||||
ok (a == hwnd[p->res], "Test %d: %s %s item of %d in %d was %d instead of %d\n", p->test, p->prev ? "Prev" : "Next", p->tab ? "Tab" : "Group", p->ctl, p->dlg, id(a), p->res);
|
||||
}
|
||||
else
|
||||
{
|
||||
todo_wine
|
||||
{
|
||||
ok (a == hwnd[p->res], "Test %d: %s %s item of %d in %d was actually %d matching expected %d\n", p->test, p->prev ? "Prev" : "Next", p->tab ? "Tab" : "Group", p->ctl, p->dlg, id(a), p->res);
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OnMainWindowCreate
|
||||
*/
|
||||
static BOOL OnMainWindowCreate (HWND hwnd, LPCREATESTRUCT lpcs)
|
||||
{
|
||||
g_hwndButton1 = CreateWindow (TEXT("button"), TEXT("Button &1"),
|
||||
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON | BS_TEXT,
|
||||
10, 10, 80, 80, hwnd, (HMENU)100, g_hinst, 0);
|
||||
if (!g_hwndButton1) return FALSE;
|
||||
|
||||
g_hwndButton2 = CreateWindow (TEXT("button"), TEXT("Button &2"),
|
||||
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
|
||||
110, 10, 80, 80, hwnd, (HMENU)200, g_hinst, 0);
|
||||
if (!g_hwndButton2) return FALSE;
|
||||
|
||||
g_hwndButtonCancel = CreateWindow (TEXT("button"), TEXT("Cancel"),
|
||||
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
|
||||
210, 10, 80, 80, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
|
||||
if (!g_hwndButtonCancel) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* OnTestDlgCreate
|
||||
*/
|
||||
|
||||
static BOOL OnTestDlgCreate (HWND hwnd, LPCREATESTRUCT lpcs)
|
||||
{
|
||||
g_hwndTestDlgEdit = CreateWindowEx ( WS_EX_LEFT | WS_EX_LTRREADING |
|
||||
WS_EX_RIGHTSCROLLBAR | WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
|
||||
TEXT("Edit"), TEXT("Edit"),
|
||||
WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL,
|
||||
16,33,184,24, hwnd, (HMENU)101, g_hinst, 0);
|
||||
if (!g_hwndTestDlgEdit) return FALSE;
|
||||
|
||||
g_hwndTestDlgBut1 = CreateWindowEx ( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
|
||||
| WS_EX_NOPARENTNOTIFY,
|
||||
TEXT("button"), TEXT("Button &1"),
|
||||
WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
|
||||
204,33,30,24, hwnd, (HMENU)201, g_hinst, 0);
|
||||
if (!g_hwndTestDlgBut1) return FALSE;
|
||||
|
||||
g_hwndTestDlgBut2 = CreateWindowEx ( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
|
||||
| WS_EX_NOPARENTNOTIFY, TEXT("button"),
|
||||
TEXT("Button &2"),
|
||||
WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
|
||||
90,102,80,24, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
|
||||
if (!g_hwndTestDlgBut2) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK main_window_procA (HWND hwnd, UINT uiMsg, WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
LRESULT result;
|
||||
switch (uiMsg)
|
||||
{
|
||||
/* Add blank case statements for these to ensure we don't use them
|
||||
* by mistake.
|
||||
*/
|
||||
case DM_GETDEFID: break;
|
||||
case DM_SETDEFID: break;
|
||||
|
||||
case WM_CREATE:
|
||||
return (OnMainWindowCreate (hwnd,
|
||||
(LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
|
||||
case WM_COMMAND:
|
||||
if (wParam == IDCANCEL)
|
||||
{
|
||||
g_terminated = TRUE;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
result=DefWindowProcA (hwnd, uiMsg, wParam, lParam);
|
||||
return result;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK testDlgWinProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
LRESULT result;
|
||||
switch (uiMsg)
|
||||
{
|
||||
/* Add blank case statements for these to ensure we don't use them
|
||||
* by mistake.
|
||||
*/
|
||||
case DM_GETDEFID: break;
|
||||
case DM_SETDEFID: break;
|
||||
|
||||
case WM_CREATE:
|
||||
return (OnTestDlgCreate (hwnd,
|
||||
(LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
|
||||
}
|
||||
|
||||
result=DefWindowProcA (hwnd, uiMsg, wParam, lParam);
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL RegisterWindowClasses (void)
|
||||
{
|
||||
WNDCLASSA cls;
|
||||
|
||||
cls.style = 0;
|
||||
cls.lpfnWndProc = DefWindowProcA;
|
||||
cls.cbClsExtra = 0;
|
||||
cls.cbWndExtra = 0;
|
||||
cls.hInstance = g_hinst;
|
||||
cls.hIcon = NULL;
|
||||
cls.hCursor = LoadCursorA (NULL, IDC_ARROW);
|
||||
cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
cls.lpszMenuName = NULL;
|
||||
cls.lpszClassName = "GetNextDlgItemWindowClass";
|
||||
|
||||
if (!RegisterClassA (&cls)) return FALSE;
|
||||
|
||||
cls.lpfnWndProc = main_window_procA;
|
||||
cls.lpszClassName = "IsDialogMessageWindowClass";
|
||||
|
||||
if (!RegisterClassA (&cls)) return FALSE;
|
||||
|
||||
GetClassInfoA(0, "#32770", &cls);
|
||||
cls.lpfnWndProc = testDlgWinProc;
|
||||
cls.lpszClassName = "WM_NEXTDLGCTLWndClass";
|
||||
if (!RegisterClassA (&cls)) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void WM_NEXTDLGCTLTest(void)
|
||||
{
|
||||
DWORD dwVal;
|
||||
|
||||
g_hwndTestDlg = CreateWindowEx( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
|
||||
| WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW,
|
||||
"WM_NEXTDLGCTLWndClass",
|
||||
"WM_NEXTDLGCTL Message test window",
|
||||
WS_POPUPWINDOW | WS_CLIPSIBLINGS | WS_DLGFRAME | WS_OVERLAPPED |
|
||||
WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK | DS_SETFONT | DS_MODALFRAME,
|
||||
0, 0, 235, 135,
|
||||
NULL, NULL, g_hinst, 0);
|
||||
|
||||
assert (g_hwndTestDlg);
|
||||
assert (g_hwndTestDlgBut1);
|
||||
assert (g_hwndTestDlgBut2);
|
||||
assert (g_hwndTestDlgEdit);
|
||||
|
||||
/*
|
||||
* Test message DM_SETDEFID
|
||||
*/
|
||||
|
||||
DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, IDCANCEL, 0 );
|
||||
DefDlgProcA( g_hwndTestDlgBut1, BM_SETSTYLE, BS_DEFPUSHBUTTON, FALSE );
|
||||
dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
|
||||
|
||||
ok ( IDCANCEL == (LOWORD(dwVal)), "Did not set default ID\n" );
|
||||
|
||||
/*
|
||||
* Check whether message WM_NEXTDLGCTL is changing the focus to next control and if
|
||||
* the destination control is a button, style of the button should be changed to
|
||||
* BS_DEFPUSHBUTTON with out making it default.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Keep the focus on Edit control.
|
||||
*/
|
||||
|
||||
if ( SetFocus( g_hwndTestDlgEdit ) )
|
||||
{
|
||||
ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't set on Edit control\n");
|
||||
|
||||
/*
|
||||
* Test message WM_NEXTDLGCTL
|
||||
*/
|
||||
DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
|
||||
ok ((GetFocus() == g_hwndTestDlgBut1), "Focus didn't move to first button\n");
|
||||
|
||||
/*
|
||||
* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
|
||||
*/
|
||||
dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
|
||||
ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
|
||||
|
||||
/*
|
||||
* Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
|
||||
* the style of default button changed to BS_PUSHBUTTON.
|
||||
*/
|
||||
if ( IDCANCEL == (LOWORD(dwVal)) )
|
||||
{
|
||||
ok ( ((GetWindowLong( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON),
|
||||
"Button1 style not set to BS_DEFPUSHBUTTON\n" );
|
||||
|
||||
ok ( !((GetWindowLong( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON),
|
||||
"Button2's style not chaged to BS_PUSHBUTTON\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
* Move focus to Button2 using "WM_NEXTDLGCTL"
|
||||
*/
|
||||
DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
|
||||
ok ((GetFocus() == g_hwndTestDlgBut2), "Focus didn't move to second button\n");
|
||||
|
||||
/*
|
||||
* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
|
||||
*/
|
||||
dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
|
||||
ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
|
||||
|
||||
/*
|
||||
* Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
|
||||
* the style of button which lost the focus changed to BS_PUSHBUTTON.
|
||||
*/
|
||||
if ( IDCANCEL == (LOWORD(dwVal)) )
|
||||
{
|
||||
ok ( ((GetWindowLong( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON),
|
||||
"Button2 style not set to BS_DEFPUSHBUTTON\n" );
|
||||
|
||||
ok ( !((GetWindowLong( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON),
|
||||
"Button1's style not chaged to BS_PUSHBUTTON\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
* Move focus to Edit control using "WM_NEXTDLGCTL"
|
||||
*/
|
||||
DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
|
||||
ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't move to Edit control\n");
|
||||
|
||||
/*
|
||||
* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
|
||||
*/
|
||||
dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
|
||||
ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
|
||||
}
|
||||
DestroyWindow(g_hwndTestDlg);
|
||||
}
|
||||
|
||||
static void IsDialogMessageWTest (void)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
g_hwndMain = CreateWindow ("IsDialogMessageWindowClass", "IsDialogMessageWindowClass",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
NULL, NULL, g_hinst, 0);
|
||||
|
||||
assert (g_hwndMain);
|
||||
assert (g_hwndButton1);
|
||||
assert (g_hwndButtonCancel);
|
||||
|
||||
/* The focus should initially be nowhere. The first TAB should take it
|
||||
* to the first button. The second TAB should take it to the Cancel
|
||||
* button.
|
||||
*/
|
||||
FormTabMsg (&msg, g_hwndMain);
|
||||
ok (IsDialogMessage (g_hwndMain, &msg), "Did not handle first TAB\n");
|
||||
ok ((GetFocus() == g_hwndButton1), "Focus did not move to first button\n");
|
||||
FormTabMsg (&msg, g_hwndButton1);
|
||||
ok (IsDialogMessage (g_hwndMain, &msg), "Did not handle second TAB\n");
|
||||
ok ((GetFocus() == g_hwndButtonCancel),
|
||||
"Focus did not move to cancel button\n");
|
||||
FormEnterMsg (&msg, g_hwndButtonCancel);
|
||||
ok (IsDialogMessage (g_hwndMain, &msg), "Did not handle the ENTER\n");
|
||||
ok (g_terminated, "ENTER did not terminate\n");
|
||||
}
|
||||
|
||||
|
||||
static LRESULT CALLBACK delayFocusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
switch (uiMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
g_hwndMain = hDlg;
|
||||
g_hwndInitialFocusGroupBox = GetDlgItem(hDlg,100);
|
||||
g_hwndButton1 = GetDlgItem(hDlg,200);
|
||||
g_hwndButton2 = GetDlgItem(hDlg,201);
|
||||
g_hwndButtonCancel = GetDlgItem(hDlg,IDCANCEL);
|
||||
g_styleInitialFocusT1 = GetWindowLong(g_hwndInitialFocusGroupBox, GWL_STYLE);
|
||||
|
||||
/* Initially check the second radio button */
|
||||
SendMessage(g_hwndButton1, BM_SETCHECK, BST_UNCHECKED, 0);
|
||||
SendMessage(g_hwndButton2, BM_SETCHECK, BST_CHECKED , 0);
|
||||
/* Continue testing after dialog initialization */
|
||||
PostMessage(hDlg, WM_USER, 0, 0);
|
||||
return g_bInitialFocusInitDlgResult;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wParam) == IDCANCEL)
|
||||
{
|
||||
EndDialog(hDlg, LOWORD(wParam));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case WM_USER:
|
||||
g_styleInitialFocusT2 = GetWindowLong(hDlg, GWL_STYLE);
|
||||
g_hwndInitialFocusT1 = GetFocus();
|
||||
SetFocus(hDlg);
|
||||
g_hwndInitialFocusT2 = GetFocus();
|
||||
PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK focusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
switch (uiMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wParam) == IDCANCEL)
|
||||
{
|
||||
EndDialog(hDlg, LOWORD(wParam));
|
||||
return TRUE;
|
||||
}
|
||||
else if (LOWORD(wParam) == 200)
|
||||
{
|
||||
if (HIWORD(wParam) == EN_SETFOCUS)
|
||||
g_hwndInitialFocusT1 = (HWND)lParam;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Helper for InitialFocusTest */
|
||||
static const char * GetHwndString(HWND hw)
|
||||
{
|
||||
if (hw == NULL)
|
||||
return "a null handle";
|
||||
if (hw == g_hwndMain)
|
||||
return "the dialog handle";
|
||||
if (hw == g_hwndInitialFocusGroupBox)
|
||||
return "the group box control";
|
||||
if (hw == g_hwndButton1)
|
||||
return "the first button";
|
||||
if (hw == g_hwndButton2)
|
||||
return "the second button";
|
||||
if (hw == g_hwndButtonCancel)
|
||||
return "the cancel button";
|
||||
|
||||
return "unknown handle";
|
||||
}
|
||||
|
||||
static void InitialFocusTest (void)
|
||||
{
|
||||
/* Test 1:
|
||||
* This test intentionally returns FALSE in response to WM_INITDIALOG
|
||||
* without setting focus to a control. This is not allowed according to
|
||||
* MSDN, but it is exactly what MFC's CFormView does.
|
||||
*
|
||||
* Since the WM_INITDIALOG handler returns FALSE without setting the focus,
|
||||
* the focus should initially be NULL. Later, when we manually set focus to
|
||||
* the dialog, the default handler should set focus to the first control that
|
||||
* is "visible, not disabled, and has the WS_TABSTOP style" (MSDN). Because the
|
||||
* second radio button has been checked, it should be the first control
|
||||
* that meets these criteria and should receive the focus.
|
||||
*/
|
||||
|
||||
g_bInitialFocusInitDlgResult = FALSE;
|
||||
g_hwndInitialFocusT1 = (HWND) -1;
|
||||
g_hwndInitialFocusT2 = (HWND) -1;
|
||||
g_styleInitialFocusT1 = -1;
|
||||
g_styleInitialFocusT2 = -1;
|
||||
|
||||
DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, (DLGPROC)delayFocusDlgWinProc);
|
||||
|
||||
ok (((g_styleInitialFocusT1 & WS_TABSTOP) == 0),
|
||||
"Error in wrc - Detected WS_TABSTOP as default style for GROUPBOX\n");
|
||||
|
||||
ok (((g_styleInitialFocusT2 & WS_VISIBLE) == 0),
|
||||
"Modal dialogs should not be shown until the message queue first goes empty\n");
|
||||
|
||||
ok ((g_hwndInitialFocusT1 == NULL),
|
||||
"Error in initial focus when WM_INITDIALOG returned FALSE: "
|
||||
"Expected NULL focus, got %s (%p).\n",
|
||||
GetHwndString(g_hwndInitialFocusT1), g_hwndInitialFocusT1);
|
||||
|
||||
ok ((g_hwndInitialFocusT2 == g_hwndButton2),
|
||||
"Error after first SetFocus() when WM_INITDIALOG returned FALSE: "
|
||||
"Expected the second button (%p), got %s (%p).\n",
|
||||
g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
|
||||
g_hwndInitialFocusT2);
|
||||
|
||||
/* Test 2:
|
||||
* This is the same as above, except WM_INITDIALOG is made to return TRUE.
|
||||
* This should cause the focus to go to the second radio button right away
|
||||
* and stay there (until the user indicates otherwise).
|
||||
*/
|
||||
|
||||
g_bInitialFocusInitDlgResult = TRUE;
|
||||
g_hwndInitialFocusT1 = (HWND) -1;
|
||||
g_hwndInitialFocusT2 = (HWND) -1;
|
||||
g_styleInitialFocusT1 = -1;
|
||||
g_styleInitialFocusT2 = -1;
|
||||
|
||||
DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, (DLGPROC)delayFocusDlgWinProc);
|
||||
|
||||
ok ((g_hwndInitialFocusT1 == g_hwndButton2),
|
||||
"Error in initial focus when WM_INITDIALOG returned TRUE: "
|
||||
"Expected the second button (%p), got %s (%p).\n",
|
||||
g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
|
||||
g_hwndInitialFocusT2);
|
||||
|
||||
ok ((g_hwndInitialFocusT2 == g_hwndButton2),
|
||||
"Error after first SetFocus() when WM_INITDIALOG returned TRUE: "
|
||||
"Expected the second button (%p), got %s (%p).\n",
|
||||
g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
|
||||
g_hwndInitialFocusT2);
|
||||
|
||||
/* Test 3:
|
||||
* If the dialog has DS_CONTROL and it's not visible then we shouldn't change focus */
|
||||
{
|
||||
HWND hDlg;
|
||||
HRSRC hResource;
|
||||
HANDLE hTemplate;
|
||||
DLGTEMPLATE* pTemplate;
|
||||
|
||||
hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", (LPSTR)RT_DIALOG);
|
||||
hTemplate = LoadResource(g_hinst, hResource);
|
||||
pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
|
||||
|
||||
g_hwndInitialFocusT1 = 0;
|
||||
hDlg = CreateDialogIndirectParamW(g_hinst, pTemplate, NULL, (DLGPROC)focusDlgWinProc,0);
|
||||
ok (hDlg != 0, "Failed to create test dialog.\n");
|
||||
|
||||
ok ((g_hwndInitialFocusT1 == 0),
|
||||
"Focus should not be set for an invisible DS_CONTROL dialog %p.\n", g_hwndInitialFocusT1);
|
||||
|
||||
DestroyWindow(hDlg);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_GetDlgItemText(void)
|
||||
{
|
||||
char string[64];
|
||||
BOOL ret;
|
||||
|
||||
strcpy(string, "Overwrite Me");
|
||||
ret = GetDlgItemTextA(NULL, 0, string, sizeof(string)/sizeof(string[0]));
|
||||
ok(!ret, "GetDlgItemText(NULL) shouldn't have succeeded\n");
|
||||
|
||||
ok(string[0] == '\0', "string retrieved using GetDlgItemText should have been NULL terminated\n");
|
||||
}
|
||||
|
||||
|
||||
START_TEST(dialog)
|
||||
{
|
||||
g_hinst = GetModuleHandleA (0);
|
||||
|
||||
if (!RegisterWindowClasses()) assert(0);
|
||||
|
||||
GetNextDlgItemTest();
|
||||
IsDialogMessageWTest();
|
||||
WM_NEXTDLGCTLTest();
|
||||
InitialFocusTest();
|
||||
test_GetDlgItemText();
|
||||
}
|
988
reactos/regtests/winetests/user32/edit.c
Executable file
988
reactos/regtests/winetests/user32/edit.c
Executable file
|
@ -0,0 +1,988 @@
|
|||
/* Unit test suite for edit control.
|
||||
*
|
||||
* Copyright 2004 Vitaliy Margolen
|
||||
* Copyright 2005 C. Scott Ananian
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
#ifndef ES_COMBO
|
||||
#define ES_COMBO 0x200
|
||||
#endif
|
||||
|
||||
#define ID_EDITTEST2 99
|
||||
#define MAXLEN 200
|
||||
|
||||
struct edit_notify {
|
||||
int en_change, en_maxtext, en_update;
|
||||
};
|
||||
|
||||
static struct edit_notify notifications;
|
||||
|
||||
static char szEditTest2Name[] = "Edit Test 2 window class";
|
||||
static HINSTANCE hinst;
|
||||
static HWND hwndET2;
|
||||
|
||||
static HWND create_editcontrol (DWORD style, DWORD exstyle)
|
||||
{
|
||||
HWND handle;
|
||||
|
||||
handle = CreateWindowEx(exstyle,
|
||||
"EDIT",
|
||||
NULL,
|
||||
ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
|
||||
10, 10, 300, 300,
|
||||
NULL, NULL, NULL, NULL);
|
||||
assert (handle);
|
||||
if (winetest_interactive)
|
||||
ShowWindow (handle, SW_SHOW);
|
||||
return handle;
|
||||
}
|
||||
|
||||
static LONG get_edit_style (HWND hwnd)
|
||||
{
|
||||
return GetWindowLongA( hwnd, GWL_STYLE ) & (
|
||||
ES_LEFT |
|
||||
/* FIXME: not implemented
|
||||
ES_CENTER |
|
||||
ES_RIGHT |
|
||||
ES_OEMCONVERT |
|
||||
*/
|
||||
ES_MULTILINE |
|
||||
ES_UPPERCASE |
|
||||
ES_LOWERCASE |
|
||||
ES_PASSWORD |
|
||||
ES_AUTOVSCROLL |
|
||||
ES_AUTOHSCROLL |
|
||||
ES_NOHIDESEL |
|
||||
ES_COMBO |
|
||||
ES_READONLY |
|
||||
ES_WANTRETURN |
|
||||
ES_NUMBER
|
||||
);
|
||||
}
|
||||
|
||||
static void set_client_height(HWND Wnd, unsigned Height)
|
||||
{
|
||||
RECT ClientRect, WindowRect;
|
||||
|
||||
GetWindowRect(Wnd, &WindowRect);
|
||||
GetClientRect(Wnd, &ClientRect);
|
||||
SetWindowPos(Wnd, NULL, WindowRect.left, WindowRect.top,
|
||||
WindowRect.right - WindowRect.left,
|
||||
Height + (WindowRect.bottom - WindowRect.top) - (ClientRect.bottom - ClientRect.top),
|
||||
SWP_NOMOVE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
#define edit_pos_ok(exp, got, txt) \
|
||||
ok(exp == got, "wrong " #txt " expected %d got %ld\n", exp, got);
|
||||
|
||||
#define edit_todo_pos_ok(exp, got, txt, todo) \
|
||||
if (todo) todo_wine { edit_pos_ok(exp, got, txt); } \
|
||||
else edit_pos_ok(exp, got, txt)
|
||||
|
||||
#define check_pos(hwEdit, set_height, test_top, test_height, test_left, todo_top, todo_height, todo_left) \
|
||||
do { \
|
||||
RECT format_rect; \
|
||||
int left_margin; \
|
||||
set_client_height(hwEdit, set_height); \
|
||||
SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \
|
||||
left_margin = LOWORD(SendMessage(hwEdit, EM_GETMARGINS, 0, 0)); \
|
||||
edit_todo_pos_ok(test_top, format_rect.top, vertical position, todo_top); \
|
||||
edit_todo_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height, todo_height); \
|
||||
edit_todo_pos_ok(test_left, format_rect.left - left_margin, left, todo_left); \
|
||||
} while(0)
|
||||
|
||||
static void test_edit_control_1(void)
|
||||
{
|
||||
HWND hwEdit;
|
||||
MSG msMessage;
|
||||
int i;
|
||||
LONG r;
|
||||
HFONT Font, OldFont;
|
||||
HDC Dc;
|
||||
TEXTMETRIC Metrics;
|
||||
|
||||
msMessage.message = WM_KEYDOWN;
|
||||
|
||||
trace("EDIT: Single line\n");
|
||||
hwEdit = create_editcontrol(0, 0);
|
||||
r = get_edit_style(hwEdit);
|
||||
ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%lx\n", r);
|
||||
for (i=0;i<65535;i++)
|
||||
{
|
||||
msMessage.wParam = i;
|
||||
r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
|
||||
ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
|
||||
"Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
|
||||
}
|
||||
DestroyWindow (hwEdit);
|
||||
|
||||
trace("EDIT: Single line want returns\n");
|
||||
hwEdit = create_editcontrol(ES_WANTRETURN, 0);
|
||||
r = get_edit_style(hwEdit);
|
||||
ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%lx\n", r);
|
||||
for (i=0;i<65535;i++)
|
||||
{
|
||||
msMessage.wParam = i;
|
||||
r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
|
||||
ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
|
||||
"Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
|
||||
}
|
||||
DestroyWindow (hwEdit);
|
||||
|
||||
trace("EDIT: Multiline line\n");
|
||||
hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL, 0);
|
||||
r = get_edit_style(hwEdit);
|
||||
ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%lx\n", r);
|
||||
for (i=0;i<65535;i++)
|
||||
{
|
||||
msMessage.wParam = i;
|
||||
r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
|
||||
ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
|
||||
"Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
|
||||
}
|
||||
DestroyWindow (hwEdit);
|
||||
|
||||
trace("EDIT: Multi line want returns\n");
|
||||
hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL | ES_WANTRETURN, 0);
|
||||
r = get_edit_style(hwEdit);
|
||||
ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%lx\n", r);
|
||||
for (i=0;i<65535;i++)
|
||||
{
|
||||
msMessage.wParam = i;
|
||||
r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
|
||||
ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
|
||||
"Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
|
||||
}
|
||||
DestroyWindow (hwEdit);
|
||||
|
||||
/* Get a stock font for which we can determine the metrics */
|
||||
Font = GetStockObject(SYSTEM_FONT);
|
||||
assert(NULL != Font);
|
||||
Dc = GetDC(NULL);
|
||||
assert(NULL != Dc);
|
||||
OldFont = SelectObject(Dc, Font);
|
||||
assert(NULL != OldFont);
|
||||
if (! GetTextMetrics(Dc, &Metrics))
|
||||
{
|
||||
assert(FALSE);
|
||||
}
|
||||
SelectObject(Dc, OldFont);
|
||||
ReleaseDC(NULL, Dc);
|
||||
|
||||
trace("EDIT: Text position\n");
|
||||
hwEdit = create_editcontrol(0, 0);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, 0);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(0, WS_EX_CLIENTEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, WS_EX_CLIENTEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(0, WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(0, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP, 0);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, 0);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 3, 0, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 2, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 2, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP, WS_EX_CLIENTEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP, WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 0, Metrics.tmHeight , 0, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 3, 0, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 2, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 2, Metrics.tmHeight , 2, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(0, ES_MULTILINE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(0, ES_MULTILINE | WS_EX_CLIENTEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE | WS_EX_CLIENTEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(0, ES_MULTILINE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(0, ES_MULTILINE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
|
||||
SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
|
||||
check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
|
||||
DestroyWindow(hwEdit);
|
||||
}
|
||||
|
||||
/* WM_SETTEXT is implemented by selecting all text, and then replacing the
|
||||
* selection. This test checks that the first 'select all' doesn't generate
|
||||
* an UPDATE message which can escape and (via a handler) change the
|
||||
* selection, which would cause WM_SETTEXT to break. This old bug
|
||||
* was fixed 18-Mar-2005; we check here to ensure it doesn't regress.
|
||||
*/
|
||||
static void test_edit_control_2(void)
|
||||
{
|
||||
HWND hwndMain;
|
||||
char szLocalString[MAXLEN];
|
||||
|
||||
/* Create main and edit windows. */
|
||||
hwndMain = CreateWindow(szEditTest2Name, "ET2", WS_OVERLAPPEDWINDOW,
|
||||
0, 0, 200, 200, NULL, NULL, hinst, NULL);
|
||||
assert(hwndMain);
|
||||
if (winetest_interactive)
|
||||
ShowWindow (hwndMain, SW_SHOW);
|
||||
|
||||
hwndET2 = CreateWindow("EDIT", NULL,
|
||||
WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,
|
||||
0, 0, 150, 50, /* important this not be 0 size. */
|
||||
hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
|
||||
assert(hwndET2);
|
||||
if (winetest_interactive)
|
||||
ShowWindow (hwndET2, SW_SHOW);
|
||||
|
||||
trace("EDIT: SETTEXT atomicity\n");
|
||||
/* Send messages to "type" in the word 'foo'. */
|
||||
SendMessage(hwndET2, WM_CHAR, 'f', 1);
|
||||
SendMessage(hwndET2, WM_CHAR, 'o', 1);
|
||||
SendMessage(hwndET2, WM_CHAR, 'o', 1);
|
||||
/* 'foo' should have been changed to 'bar' by the UPDATE handler. */
|
||||
GetWindowText(hwndET2, szLocalString, MAXLEN);
|
||||
ok(lstrcmp(szLocalString, "bar")==0,
|
||||
"Wrong contents of edit: %s\n", szLocalString);
|
||||
|
||||
/* OK, done! */
|
||||
DestroyWindow (hwndET2);
|
||||
DestroyWindow (hwndMain);
|
||||
}
|
||||
|
||||
static void ET2_check_change(void) {
|
||||
char szLocalString[MAXLEN];
|
||||
/* This EN_UPDATE handler changes any 'foo' to 'bar'. */
|
||||
GetWindowText(hwndET2, szLocalString, MAXLEN);
|
||||
if (lstrcmp(szLocalString, "foo")==0) {
|
||||
lstrcpy(szLocalString, "bar");
|
||||
SendMessage(hwndET2, WM_SETTEXT, 0, (LPARAM) szLocalString);
|
||||
}
|
||||
/* always leave the cursor at the end. */
|
||||
SendMessage(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1);
|
||||
}
|
||||
static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
|
||||
{
|
||||
if (id==ID_EDITTEST2 && codeNotify == EN_UPDATE)
|
||||
ET2_check_change();
|
||||
}
|
||||
static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (iMsg) {
|
||||
HANDLE_MSG(hwnd, WM_COMMAND, ET2_OnCommand);
|
||||
}
|
||||
return DefWindowProc(hwnd, iMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static BOOL RegisterWindowClasses (void)
|
||||
{
|
||||
WNDCLASSA cls;
|
||||
cls.style = 0;
|
||||
cls.lpfnWndProc = ET2_WndProc;
|
||||
cls.cbClsExtra = 0;
|
||||
cls.cbWndExtra = 0;
|
||||
cls.hInstance = hinst;
|
||||
cls.hIcon = NULL;
|
||||
cls.hCursor = LoadCursorA (NULL, IDC_ARROW);
|
||||
cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
cls.lpszMenuName = NULL;
|
||||
cls.lpszClassName = szEditTest2Name;
|
||||
if (!RegisterClassA (&cls)) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void zero_notify(void)
|
||||
{
|
||||
notifications.en_change = 0;
|
||||
notifications.en_maxtext = 0;
|
||||
notifications.en_update = 0;
|
||||
}
|
||||
|
||||
#define test_notify(enchange, enmaxtext, enupdate) \
|
||||
ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \
|
||||
"got %d\n", enchange, notifications.en_change); \
|
||||
ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \
|
||||
"got %d\n", enmaxtext, notifications.en_maxtext); \
|
||||
ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \
|
||||
"got %d\n", enupdate, notifications.en_update)
|
||||
|
||||
|
||||
static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_COMMAND:
|
||||
switch (HIWORD(wParam)) {
|
||||
case EN_MAXTEXT:
|
||||
notifications.en_maxtext++;
|
||||
break;
|
||||
case EN_UPDATE:
|
||||
notifications.en_update++;
|
||||
break;
|
||||
case EN_CHANGE:
|
||||
notifications.en_change++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return DefWindowProcA(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
/* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notificatisons sent in response
|
||||
* to these messages.
|
||||
*/
|
||||
static void test_edit_control_3(void)
|
||||
{
|
||||
WNDCLASSA cls;
|
||||
HWND hWnd;
|
||||
HWND hParent;
|
||||
int len;
|
||||
static const char *str = "this is a long string.";
|
||||
static const char *str2 = "this is a long string.\r\nthis is a long string.\r\nthis is a long string.\r\nthis is a long string.";
|
||||
|
||||
trace("EDIT: Test notifications\n");
|
||||
|
||||
cls.style = 0;
|
||||
cls.lpfnWndProc = edit3_wnd_procA;
|
||||
cls.cbClsExtra = 0;
|
||||
cls.cbWndExtra = 0;
|
||||
cls.hInstance = GetModuleHandleA(0);
|
||||
cls.hIcon = 0;
|
||||
cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
|
||||
cls.hbrBackground = GetStockObject(WHITE_BRUSH);
|
||||
cls.lpszMenuName = NULL;
|
||||
cls.lpszClassName = "ParentWindowClass";
|
||||
|
||||
assert(RegisterClassA(&cls));
|
||||
|
||||
hParent = CreateWindowExA(0,
|
||||
"ParentWindowClass",
|
||||
NULL,
|
||||
0,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
|
||||
NULL, NULL, NULL, NULL);
|
||||
assert(hParent);
|
||||
|
||||
trace("EDIT: Single line, no ES_AUTOHSCROLL\n");
|
||||
hWnd = CreateWindowExA(0,
|
||||
"EDIT",
|
||||
NULL,
|
||||
0,
|
||||
10, 10, 50, 50,
|
||||
hParent, NULL, NULL, NULL);
|
||||
assert(hWnd);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) > len, "text should have been truncated\n");
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(1 == len, "wrong text length, expected 1, got %d\n", len);
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
|
||||
trace("EDIT: Single line, ES_AUTOHSCROLL\n");
|
||||
hWnd = CreateWindowExA(0,
|
||||
"EDIT",
|
||||
NULL,
|
||||
ES_AUTOHSCROLL,
|
||||
10, 10, 50, 50,
|
||||
hParent, NULL, NULL, NULL);
|
||||
assert(hWnd);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
|
||||
trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
|
||||
hWnd = CreateWindowExA(0,
|
||||
"EDIT",
|
||||
NULL,
|
||||
ES_MULTILINE,
|
||||
10, 10, 50, 50,
|
||||
hParent, NULL, NULL, NULL);
|
||||
assert(hWnd);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(0, 0, 0);
|
||||
|
||||
SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(0, 0, 0);
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
|
||||
trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
|
||||
hWnd = CreateWindowExA(0,
|
||||
"EDIT",
|
||||
NULL,
|
||||
ES_MULTILINE | ES_AUTOHSCROLL,
|
||||
10, 10, 50, 50,
|
||||
hParent, NULL, NULL, NULL);
|
||||
assert(hWnd);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(0, 0, 0);
|
||||
|
||||
SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(0, 0, 0);
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
|
||||
trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n");
|
||||
hWnd = CreateWindowExA(0,
|
||||
"EDIT",
|
||||
NULL,
|
||||
ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
|
||||
10, 10, 50, 50,
|
||||
hParent, NULL, NULL, NULL);
|
||||
assert(hWnd);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(1, 0, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(0, 0, 0);
|
||||
|
||||
SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
|
||||
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
|
||||
test_notify(1, 1, 1);
|
||||
|
||||
zero_notify();
|
||||
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
|
||||
len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
|
||||
test_notify(0, 0, 0);
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
}
|
||||
|
||||
/* Test EM_CHARFROMPOS and EM_POSFROMCHAR
|
||||
*/
|
||||
static void test_edit_control_4(void)
|
||||
{
|
||||
HWND hwEdit;
|
||||
int lo, hi, mid;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
trace("EDIT: Test EM_CHARFROMPOS and EM_POSFROMCHAR\n");
|
||||
hwEdit = create_editcontrol(0, 0);
|
||||
SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
|
||||
lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
|
||||
hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
|
||||
mid = lo + (hi - lo) / 2;
|
||||
|
||||
for (i = lo; i < mid; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(0 == ret, "expected 0 got %d\n", ret);
|
||||
}
|
||||
for (i = mid; i <= hi; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(1 == ret, "expected 1 got %d\n", ret);
|
||||
}
|
||||
ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
|
||||
ok(-1 == ret, "expected -1 got %d\n", ret);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(ES_RIGHT, 0);
|
||||
SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
|
||||
lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
|
||||
hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
|
||||
mid = lo + (hi - lo) / 2;
|
||||
|
||||
for (i = lo; i < mid; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(0 == ret, "expected 0 got %d\n", ret);
|
||||
}
|
||||
for (i = mid; i <= hi; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(1 == ret, "expected 1 got %d\n", ret);
|
||||
}
|
||||
ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
|
||||
ok(-1 == ret, "expected -1 got %d\n", ret);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(ES_CENTER, 0);
|
||||
SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
|
||||
lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
|
||||
hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
|
||||
mid = lo + (hi - lo) / 2;
|
||||
|
||||
for (i = lo; i < mid; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(0 == ret, "expected 0 got %d\n", ret);
|
||||
}
|
||||
for (i = mid; i <= hi; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(1 == ret, "expected 1 got %d\n", ret);
|
||||
}
|
||||
ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
|
||||
ok(-1 == ret, "expected -1 got %d\n", ret);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(ES_MULTILINE, 0);
|
||||
SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
|
||||
lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
|
||||
hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
|
||||
mid = lo + (hi - lo) / 2 +1;
|
||||
|
||||
for (i = lo; i < mid; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(0 == ret, "expected 0 got %d\n", ret);
|
||||
}
|
||||
for (i = mid; i <= hi; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(1 == ret, "expected 1 got %d\n", ret);
|
||||
}
|
||||
ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
|
||||
ok(-1 == ret, "expected -1 got %d\n", ret);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT, 0);
|
||||
SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
|
||||
lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
|
||||
hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
|
||||
mid = lo + (hi - lo) / 2 +1;
|
||||
|
||||
for (i = lo; i < mid; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(0 == ret, "expected 0 got %d\n", ret);
|
||||
}
|
||||
for (i = mid; i <= hi; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(1 == ret, "expected 1 got %d\n", ret);
|
||||
}
|
||||
ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
|
||||
ok(-1 == ret, "expected -1 got %d\n", ret);
|
||||
DestroyWindow(hwEdit);
|
||||
|
||||
hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER, 0);
|
||||
SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
|
||||
lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
|
||||
hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
|
||||
mid = lo + (hi - lo) / 2 +1;
|
||||
|
||||
for (i = lo; i < mid; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(0 == ret, "expected 0 got %d\n", ret);
|
||||
}
|
||||
for (i = mid; i <= hi; i++) {
|
||||
ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
|
||||
ok(1 == ret, "expected 1 got %d\n", ret);
|
||||
}
|
||||
ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
|
||||
ok(-1 == ret, "expected -1 got %d\n", ret);
|
||||
DestroyWindow(hwEdit);
|
||||
}
|
||||
|
||||
static void test_margins(void)
|
||||
{
|
||||
HWND hwEdit;
|
||||
RECT old_rect, new_rect;
|
||||
INT old_left_margin, old_right_margin;
|
||||
DWORD old_margins, new_margins;
|
||||
|
||||
hwEdit = create_editcontrol(WS_BORDER, 0);
|
||||
|
||||
old_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
|
||||
old_left_margin = LOWORD(old_margins);
|
||||
old_right_margin = HIWORD(old_margins);
|
||||
|
||||
/* Check if setting the margins works */
|
||||
|
||||
SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
|
||||
new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
|
||||
ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
|
||||
ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
|
||||
|
||||
SendMessage(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
|
||||
new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
|
||||
ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
|
||||
ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
|
||||
|
||||
|
||||
/* The size of the rectangle must decrease if we increase the margin */
|
||||
|
||||
SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
|
||||
SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
|
||||
SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
|
||||
SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
|
||||
ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
|
||||
ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
|
||||
ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
|
||||
ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
|
||||
|
||||
|
||||
/* If we set the margin to same value as the current margin,
|
||||
the rectangle must not change */
|
||||
|
||||
SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
|
||||
old_rect.left = 1;
|
||||
old_rect.right = 99;
|
||||
old_rect.top = 1;
|
||||
old_rect.bottom = 99;
|
||||
SendMessage(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);
|
||||
SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
|
||||
SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
|
||||
SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
|
||||
ok(new_rect.left == old_rect.left, "The left border of the rectangle has changed\n");
|
||||
ok(new_rect.right == old_rect.right, "The right border of the rectangle has changed\n");
|
||||
ok(new_rect.top == old_rect.top, "The top border of the rectangle has changed\n");
|
||||
ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle has changed\n");
|
||||
|
||||
DestroyWindow (hwEdit);
|
||||
}
|
||||
|
||||
START_TEST(edit)
|
||||
{
|
||||
hinst = GetModuleHandleA (NULL);
|
||||
if (!RegisterWindowClasses())
|
||||
assert(0);
|
||||
|
||||
test_edit_control_1();
|
||||
test_edit_control_2();
|
||||
test_edit_control_3();
|
||||
test_edit_control_4();
|
||||
test_margins();
|
||||
}
|
366
reactos/regtests/winetests/user32/input.c
Executable file
366
reactos/regtests/winetests/user32/input.c
Executable file
|
@ -0,0 +1,366 @@
|
|||
/* Test Key event to Key message translation
|
||||
*
|
||||
* Copyright 2003 Rein Klazes
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* test whether the right type of messages:
|
||||
* WM_KEYUP/DOWN vs WM_SYSKEYUP/DOWN are sent in case of combined
|
||||
* keystrokes.
|
||||
*
|
||||
* For instance <ALT>-X can be accompished by
|
||||
* the sequence ALT-KEY-DOWN, X-KEY-DOWN, ALT-KEY-UP, X-KEY-UP
|
||||
* but also X-KEY-DOWN, ALT-KEY-DOWN, X-KEY-UP, ALT-KEY-UP
|
||||
* Whether a KEY or a SYSKEY message is sent is not always clear, it is
|
||||
* also not the same in WINNT as in WIN9X */
|
||||
|
||||
/* NOTE that there will be test failures under WIN9X
|
||||
* No applications are known to me that rely on this
|
||||
* so I don't fix it */
|
||||
|
||||
/* TODO:
|
||||
* 1. extend it to the wm_command and wm_syscommand notifications
|
||||
* 2. add some more tests with special cases like dead keys or right (alt) key
|
||||
* 3. there is some adapted code from input.c in here. Should really
|
||||
* make that code exactly the same.
|
||||
* 4. resolve the win9x case when there is a need or the testing frame work
|
||||
* offers a nice way.
|
||||
* 5. The test app creates a window, the user should not take the focus
|
||||
* away during its short existence. I could do something to prevent that
|
||||
* if it is a problem.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x403
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
/* globals */
|
||||
static HWND hWndTest;
|
||||
static long timetag = 0x10000000;
|
||||
|
||||
static UINT (WINAPI *ptr_SendInput) (UINT, INPUT*, size_t);
|
||||
|
||||
#define MAXKEYEVENTS 6
|
||||
#define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one
|
||||
and only one message */
|
||||
|
||||
/* keyboard message names, sorted as their value */
|
||||
static const char *MSGNAME[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR",
|
||||
"WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"};
|
||||
|
||||
/* keyevents, add more as needed */
|
||||
typedef enum KEVtag
|
||||
{ ALTDOWN = 1, ALTUP, XDOWN, XUP, SHIFTDOWN, SHIFTUP, CTRLDOWN, CTRLUP } KEV;
|
||||
/* matching VK's */
|
||||
static const int GETVKEY[]={0, VK_MENU, VK_MENU, 'X', 'X', VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL};
|
||||
/* matching scan codes */
|
||||
static const int GETSCAN[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D };
|
||||
/* matching updown events */
|
||||
static const int GETUPDOWN[]={0, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP};
|
||||
/* matching descripts */
|
||||
static const char *getdesc[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"};
|
||||
|
||||
/* The MSVC headers ignore our NONAMELESSUNION requests so we have to define our own type */
|
||||
typedef struct
|
||||
{
|
||||
DWORD type;
|
||||
union
|
||||
{
|
||||
MOUSEINPUT mi;
|
||||
KEYBDINPUT ki;
|
||||
HARDWAREINPUT hi;
|
||||
} u;
|
||||
} TEST_INPUT;
|
||||
|
||||
#define ADDTOINPUTS(kev) \
|
||||
inputs[evtctr].type = INPUT_KEYBOARD; \
|
||||
((TEST_INPUT*)inputs)[evtctr].u.ki.wVk = GETVKEY[ kev]; \
|
||||
((TEST_INPUT*)inputs)[evtctr].u.ki.wScan = GETSCAN[ kev]; \
|
||||
((TEST_INPUT*)inputs)[evtctr].u.ki.dwFlags = GETUPDOWN[ kev]; \
|
||||
((TEST_INPUT*)inputs)[evtctr].u.ki.dwExtraInfo = 0; \
|
||||
((TEST_INPUT*)inputs)[evtctr].u.ki.time = ++timetag; \
|
||||
if( kev) evtctr++;
|
||||
|
||||
typedef struct {
|
||||
UINT message;
|
||||
WPARAM wParam;
|
||||
LPARAM lParam;
|
||||
} KMSG;
|
||||
|
||||
/*******************************************
|
||||
* add new test sets here
|
||||
* the software will make all combinations of the
|
||||
* keyevent defined here
|
||||
*/
|
||||
static const struct {
|
||||
int nrkev;
|
||||
KEV keydwn[MAXKEYEVENTS];
|
||||
KEV keyup[MAXKEYEVENTS];
|
||||
} testkeyset[]= {
|
||||
{ 2, { ALTDOWN, XDOWN }, { ALTUP, XUP}},
|
||||
{ 3, { ALTDOWN, XDOWN , SHIFTDOWN}, { ALTUP, XUP, SHIFTUP}},
|
||||
{ 3, { ALTDOWN, XDOWN , CTRLDOWN}, { ALTUP, XUP, CTRLUP}},
|
||||
{ 3, { SHIFTDOWN, XDOWN , CTRLDOWN}, { SHIFTUP, XUP, CTRLUP}},
|
||||
{ 0 } /* mark the end */
|
||||
};
|
||||
|
||||
/**********************adapted from input.c **********************************/
|
||||
|
||||
static BYTE InputKeyStateTable[256];
|
||||
static BYTE AsyncKeyStateTable[256];
|
||||
static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
|
||||
or a WM_KEYUP message */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long count : 16;
|
||||
unsigned long code : 8;
|
||||
unsigned long extended : 1;
|
||||
unsigned long unused : 2;
|
||||
unsigned long win_internal : 2;
|
||||
unsigned long context : 1;
|
||||
unsigned long previous : 1;
|
||||
unsigned long transition : 1;
|
||||
} lp1;
|
||||
unsigned long lp2;
|
||||
} KEYLP;
|
||||
|
||||
static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam )
|
||||
{
|
||||
UINT message;
|
||||
int VKey = GETVKEY[kev];
|
||||
KEYLP keylp;
|
||||
|
||||
keylp.lp2 = 0;
|
||||
|
||||
keylp.lp1.count = 1;
|
||||
keylp.lp1.code = GETSCAN[kev];
|
||||
keylp.lp1.extended = 0 ;/* FIXME (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) != 0; */
|
||||
keylp.lp1.win_internal = 0;
|
||||
|
||||
if (GETUPDOWN[kev] & KEYEVENTF_KEYUP )
|
||||
{
|
||||
message = WM_KEYUP;
|
||||
if( (InputKeyStateTable[VK_MENU] & 0x80) && (
|
||||
(VKey == VK_MENU) || (VKey == VK_CONTROL) ||
|
||||
!(InputKeyStateTable[VK_CONTROL] & 0x80))) {
|
||||
if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
|
||||
(VKey != VK_MENU)) /* <ALT>-down...<something else>-up */
|
||||
message = WM_SYSKEYUP;
|
||||
TrackSysKey = 0;
|
||||
}
|
||||
InputKeyStateTable[VKey] &= ~0x80;
|
||||
keylp.lp1.previous = 1;
|
||||
keylp.lp1.transition = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
keylp.lp1.previous = (InputKeyStateTable[VKey] & 0x80) != 0;
|
||||
keylp.lp1.transition = 0;
|
||||
if (!(InputKeyStateTable[VKey] & 0x80)) InputKeyStateTable[VKey] ^= 0x01;
|
||||
InputKeyStateTable[VKey] |= 0x80;
|
||||
AsyncKeyStateTable[VKey] |= 0x80;
|
||||
|
||||
message = WM_KEYDOWN;
|
||||
if( (InputKeyStateTable[VK_MENU] & 0x80) &&
|
||||
!(InputKeyStateTable[VK_CONTROL] & 0x80)) {
|
||||
message = WM_SYSKEYDOWN;
|
||||
TrackSysKey = VKey;
|
||||
}
|
||||
}
|
||||
|
||||
keylp.lp1.context = (InputKeyStateTable[VK_MENU] & 0x80) != 0; /* 1 if alt */
|
||||
|
||||
if( plParam) *plParam = keylp.lp2;
|
||||
if( pwParam) *pwParam = VKey;
|
||||
return message;
|
||||
}
|
||||
|
||||
/****************************** end copy input.c ****************************/
|
||||
|
||||
/*
|
||||
* . prepare the keyevents for SendInputs
|
||||
* . calculate the "expected" messages
|
||||
* . Send the events to our window
|
||||
* . retrieve the messages from the input queue
|
||||
* . verify
|
||||
*/
|
||||
static void do_test( HWND hwnd, int seqnr, const KEV td[] )
|
||||
{
|
||||
HMODULE module;
|
||||
INPUT inputs[MAXKEYEVENTS];
|
||||
KMSG expmsg[MAXKEYEVENTS];
|
||||
MSG msg;
|
||||
char buf[100];
|
||||
UINT evtctr=0;
|
||||
int kmctr, i;
|
||||
|
||||
module = GetModuleHandleA("user32");
|
||||
if (!module) return;
|
||||
ptr_SendInput = (void *)GetProcAddress(module, "SendInput");
|
||||
if (!ptr_SendInput) return;
|
||||
|
||||
buf[0]='\0';
|
||||
TrackSysKey=0; /* see input.c */
|
||||
for( i = 0; i < MAXKEYEVENTS; i++) {
|
||||
ADDTOINPUTS(td[i])
|
||||
strcat(buf, getdesc[td[i]]);
|
||||
if(td[i])
|
||||
expmsg[i].message = KbdMessage(td[i], &(expmsg[i].wParam), &(expmsg[i].lParam)); /* see queue_kbd_event() */
|
||||
else
|
||||
expmsg[i].message = 0;
|
||||
}
|
||||
for( kmctr = 0; kmctr < MAXKEYEVENTS && expmsg[kmctr].message; kmctr++)
|
||||
;
|
||||
assert( evtctr <= MAXKEYEVENTS );
|
||||
assert( evtctr == ptr_SendInput(evtctr, &inputs[0], sizeof(INPUT)));
|
||||
i = 0;
|
||||
trace("======== key stroke sequence #%d: %s =============\n",
|
||||
seqnr + 1, buf);
|
||||
while( PeekMessage(&msg,hwnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE) ) {
|
||||
trace("message[%d] %-15s wParam %04x lParam %08lx time %lx\n", i,
|
||||
MSGNAME[msg.message - WM_KEYFIRST], msg.wParam, msg.lParam, msg.time);
|
||||
if( i < kmctr ) {
|
||||
ok( msg.message == expmsg[i].message &&
|
||||
msg.wParam == expmsg[i].wParam &&
|
||||
msg.lParam == expmsg[i].lParam,
|
||||
"wrong message! expected:\n"
|
||||
"message[%d] %-15s wParam %04x lParam %08lx\n",i,
|
||||
MSGNAME[(expmsg[i]).message - WM_KEYFIRST],
|
||||
expmsg[i].wParam, expmsg[i].lParam );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
trace("%d messages retrieved\n", i);
|
||||
ok( i == kmctr, "message count is wrong: got %d expected: %d\n", i, kmctr);
|
||||
}
|
||||
|
||||
/* test all combinations of the specified key events */
|
||||
static void TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[] )
|
||||
{
|
||||
int i,j,k,l,m,n;
|
||||
static int count=0;
|
||||
KEV kbuf[MAXKEYEVENTS];
|
||||
assert( nrkev==2 || nrkev==3);
|
||||
for(i=0;i<MAXKEYEVENTS;i++) kbuf[i]=0;
|
||||
/* two keys involved gives 4 test cases */
|
||||
if(nrkev==2) {
|
||||
for(i=0;i<nrkev;i++) {
|
||||
for(j=0;j<nrkev;j++) {
|
||||
kbuf[0] = kevdwn[i];
|
||||
kbuf[1] = kevdwn[1-i];
|
||||
kbuf[2] = kevup[j];
|
||||
kbuf[3] = kevup[1-j];
|
||||
do_test( hWnd, count++, kbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* three keys involved gives 36 test cases */
|
||||
if(nrkev==3){
|
||||
for(i=0;i<nrkev;i++){
|
||||
for(j=0;j<nrkev;j++){
|
||||
if(j==i) continue;
|
||||
for(k=0;k<nrkev;k++){
|
||||
if(k==i || k==j) continue;
|
||||
for(l=0;l<nrkev;l++){
|
||||
for(m=0;m<nrkev;m++){
|
||||
if(m==l) continue;
|
||||
for(n=0;n<nrkev;n++){
|
||||
if(n==l ||n==m) continue;
|
||||
kbuf[0] = kevdwn[i];
|
||||
kbuf[1] = kevdwn[j];
|
||||
kbuf[2] = kevdwn[k];
|
||||
kbuf[3] = kevup[l];
|
||||
kbuf[4] = kevup[m];
|
||||
kbuf[5] = kevup[n];
|
||||
do_test( hWnd, count++, kbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* test each set specified in the global testkeyset array */
|
||||
static void TestSysKeys( HWND hWnd)
|
||||
{
|
||||
int i;
|
||||
for(i=0; testkeyset[i].nrkev;i++)
|
||||
TestASet( hWnd, testkeyset[i].nrkev, testkeyset[i].keydwn,
|
||||
testkeyset[i].keyup);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam,
|
||||
LPARAM lParam )
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_USER:
|
||||
SetFocus(hWnd);
|
||||
/* window has focus, now do the test */
|
||||
if( hWnd == hWndTest) TestSysKeys( hWnd);
|
||||
/* finished :-) */
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage( 0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
START_TEST(input)
|
||||
{
|
||||
MSG msg;
|
||||
WNDCLASSA wclass;
|
||||
HANDLE hInstance = GetModuleHandleA( NULL );
|
||||
|
||||
wclass.lpszClassName = "InputSysKeyTestClass";
|
||||
wclass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wclass.lpfnWndProc = WndProc;
|
||||
wclass.hInstance = hInstance;
|
||||
wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
|
||||
wclass.hCursor = LoadCursorA( NULL, IDC_ARROW);
|
||||
wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
|
||||
wclass.lpszMenuName = 0;
|
||||
wclass.cbClsExtra = 0;
|
||||
wclass.cbWndExtra = 0;
|
||||
assert (RegisterClassA( &wclass ));
|
||||
/* create the test window that will receive the keystrokes */
|
||||
assert ( hWndTest = CreateWindowA( wclass.lpszClassName, "InputSysKeyTest",
|
||||
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
|
||||
NULL, NULL, hInstance, NULL) );
|
||||
ShowWindow( hWndTest, SW_SHOW);
|
||||
UpdateWindow( hWndTest);
|
||||
|
||||
/* flush pending messages */
|
||||
while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
|
||||
|
||||
SendMessageA(hWndTest, WM_USER, 0, 0);
|
||||
DestroyWindow(hWndTest);
|
||||
}
|
363
reactos/regtests/winetests/user32/listbox.c
Normal file
363
reactos/regtests/winetests/user32/listbox.c
Normal file
|
@ -0,0 +1,363 @@
|
|||
/* Unit test suite for list boxes.
|
||||
*
|
||||
* Copyright 2003 Ferenc Wagner
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "winnls.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
#ifdef VISIBLE
|
||||
#define WAIT Sleep (1000)
|
||||
#define REDRAW RedrawWindow (handle, NULL, 0, RDW_UPDATENOW)
|
||||
#else
|
||||
#define WAIT
|
||||
#define REDRAW
|
||||
#endif
|
||||
|
||||
static const char * const strings[4] = {
|
||||
"First added",
|
||||
"Second added",
|
||||
"Third added",
|
||||
"Fourth added which is very long because at some time we only had a 256 byte character buffer and that was overflowing in one of those applications that had a common dialog file open box and tried to add a 300 characters long custom filter string which of course the code did not like and crashed. Just make sure this string is longer than 256 characters."
|
||||
};
|
||||
|
||||
static HWND
|
||||
create_listbox (DWORD add_style, HWND parent)
|
||||
{
|
||||
HWND handle=CreateWindow ("LISTBOX", "TestList",
|
||||
(LBS_STANDARD & ~LBS_SORT) | add_style,
|
||||
0, 0, 100, 100,
|
||||
parent, (HMENU)1, NULL, 0);
|
||||
|
||||
assert (handle);
|
||||
SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[0]);
|
||||
SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[1]);
|
||||
SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[2]);
|
||||
SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[3]);
|
||||
|
||||
#ifdef VISIBLE
|
||||
ShowWindow (handle, SW_SHOW);
|
||||
#endif
|
||||
REDRAW;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
struct listbox_prop {
|
||||
DWORD add_style;
|
||||
};
|
||||
|
||||
struct listbox_stat {
|
||||
int selected, anchor, caret, selcount;
|
||||
};
|
||||
|
||||
struct listbox_test {
|
||||
struct listbox_prop prop;
|
||||
struct listbox_stat init, init_todo;
|
||||
struct listbox_stat click, click_todo;
|
||||
struct listbox_stat step, step_todo;
|
||||
struct listbox_stat sel, sel_todo;
|
||||
};
|
||||
|
||||
static void
|
||||
listbox_query (HWND handle, struct listbox_stat *results)
|
||||
{
|
||||
results->selected = SendMessage (handle, LB_GETCURSEL, 0, 0);
|
||||
results->anchor = SendMessage (handle, LB_GETANCHORINDEX, 0, 0);
|
||||
results->caret = SendMessage (handle, LB_GETCARETINDEX, 0, 0);
|
||||
results->selcount = SendMessage (handle, LB_GETSELCOUNT, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
buttonpress (HWND handle, WORD x, WORD y)
|
||||
{
|
||||
LPARAM lp=x+(y<<16);
|
||||
|
||||
WAIT;
|
||||
SendMessage (handle, WM_LBUTTONDOWN, (WPARAM) MK_LBUTTON, lp);
|
||||
SendMessage (handle, WM_LBUTTONUP , (WPARAM) 0 , lp);
|
||||
REDRAW;
|
||||
}
|
||||
|
||||
static void
|
||||
keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
|
||||
{
|
||||
LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0);
|
||||
|
||||
WAIT;
|
||||
SendMessage (handle, WM_KEYDOWN, keycode, lp);
|
||||
SendMessage (handle, WM_KEYUP , keycode, lp | 0xc000000);
|
||||
REDRAW;
|
||||
}
|
||||
|
||||
#define listbox_field_ok(t, s, f, got) \
|
||||
ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
|
||||
": expected %d, got %d\n", (unsigned int)t.prop.add_style, \
|
||||
t.s.f, got.f)
|
||||
|
||||
#define listbox_todo_field_ok(t, s, f, got) \
|
||||
if (t.s##_todo.f) todo_wine { listbox_field_ok(t, s, f, got); } \
|
||||
else listbox_field_ok(t, s, f, got)
|
||||
|
||||
#define listbox_ok(t, s, got) \
|
||||
listbox_todo_field_ok(t, s, selected, got); \
|
||||
listbox_todo_field_ok(t, s, anchor, got); \
|
||||
listbox_todo_field_ok(t, s, caret, got); \
|
||||
listbox_todo_field_ok(t, s, selcount, got)
|
||||
|
||||
static void
|
||||
check (const struct listbox_test test)
|
||||
{
|
||||
struct listbox_stat answer;
|
||||
HWND hLB=create_listbox (test.prop.add_style, 0);
|
||||
RECT second_item;
|
||||
int i;
|
||||
|
||||
listbox_query (hLB, &answer);
|
||||
listbox_ok (test, init, answer);
|
||||
|
||||
SendMessage (hLB, LB_GETITEMRECT, (WPARAM) 1, (LPARAM) &second_item);
|
||||
buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
|
||||
|
||||
listbox_query (hLB, &answer);
|
||||
listbox_ok (test, click, answer);
|
||||
|
||||
keypress (hLB, VK_DOWN, 0x50, TRUE);
|
||||
|
||||
listbox_query (hLB, &answer);
|
||||
listbox_ok (test, step, answer);
|
||||
|
||||
DestroyWindow (hLB);
|
||||
hLB=create_listbox (test.prop.add_style, 0);
|
||||
|
||||
SendMessage (hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
|
||||
listbox_query (hLB, &answer);
|
||||
listbox_ok (test, sel, answer);
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
DWORD size = SendMessage (hLB, LB_GETTEXTLEN, i, 0);
|
||||
CHAR *txt;
|
||||
WCHAR *txtw;
|
||||
|
||||
txt = HeapAlloc (GetProcessHeap(), 0, size+1);
|
||||
SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
|
||||
ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
|
||||
|
||||
txtw = HeapAlloc (GetProcessHeap(), 0, 2*size+2);
|
||||
SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
|
||||
WideCharToMultiByte( CP_ACP, 0, txtw, -1, txt, size, NULL, NULL );
|
||||
ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
|
||||
|
||||
HeapFree (GetProcessHeap(), 0, txtw);
|
||||
HeapFree (GetProcessHeap(), 0, txt);
|
||||
}
|
||||
|
||||
WAIT;
|
||||
DestroyWindow (hLB);
|
||||
}
|
||||
|
||||
static void check_item_height(void)
|
||||
{
|
||||
HWND hLB;
|
||||
HDC hdc;
|
||||
HFONT font;
|
||||
TEXTMETRIC tm;
|
||||
INT itemHeight;
|
||||
|
||||
hLB = create_listbox (0, 0);
|
||||
ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
|
||||
ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
|
||||
ok (GetTextMetrics( hdc, &tm ), "Can't read font metrics\n");
|
||||
ReleaseDC( hLB, hdc);
|
||||
|
||||
ok (SendMessage(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
|
||||
|
||||
itemHeight = SendMessage(hLB, LB_GETITEMHEIGHT, 0, 0);
|
||||
ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %ld\n", itemHeight, tm.tmHeight);
|
||||
|
||||
DestroyWindow (hLB);
|
||||
}
|
||||
|
||||
static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DRAWITEM:
|
||||
{
|
||||
RECT rc_item, rc_client, rc_clip;
|
||||
DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
|
||||
|
||||
trace("%p WM_DRAWITEM %08x %08lx\n", hwnd, wparam, lparam);
|
||||
|
||||
ok(wparam == 0, "wrong wparam %04x\n", wparam);
|
||||
ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
|
||||
|
||||
GetClientRect(dis->hwndItem, &rc_client);
|
||||
trace("hwndItem %p client rect (%ld,%ld-%ld,%ld)\n", dis->hwndItem,
|
||||
rc_client.left, rc_client.top, rc_client.right, rc_client.bottom);
|
||||
GetClipBox(dis->hDC, &rc_clip);
|
||||
trace("clip rect (%ld,%ld-%ld,%ld)\n", rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
|
||||
ok(EqualRect(&rc_client, &rc_clip), "client rect of the listbox should be equal to the clip box\n");
|
||||
|
||||
trace("rcItem (%ld,%ld-%ld,%ld)\n", dis->rcItem.left, dis->rcItem.top,
|
||||
dis->rcItem.right, dis->rcItem.bottom);
|
||||
SendMessage(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
|
||||
trace("item rect (%ld,%ld-%ld,%ld)\n", rc_item.left, rc_item.top, rc_item.right, rc_item.bottom);
|
||||
ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
static void test_ownerdraw(void)
|
||||
{
|
||||
WNDCLASS cls;
|
||||
HWND parent, hLB;
|
||||
INT ret;
|
||||
RECT rc;
|
||||
|
||||
cls.style = 0;
|
||||
cls.lpfnWndProc = main_window_proc;
|
||||
cls.cbClsExtra = 0;
|
||||
cls.cbWndExtra = 0;
|
||||
cls.hInstance = GetModuleHandle(0);
|
||||
cls.hIcon = 0;
|
||||
cls.hCursor = LoadCursor(0, (LPSTR)IDC_ARROW);
|
||||
cls.hbrBackground = GetStockObject(WHITE_BRUSH);
|
||||
cls.lpszMenuName = NULL;
|
||||
cls.lpszClassName = "main_window_class";
|
||||
assert(RegisterClass(&cls));
|
||||
|
||||
parent = CreateWindowEx(0, "main_window_class", NULL,
|
||||
WS_POPUP | WS_VISIBLE,
|
||||
100, 100, 400, 400,
|
||||
GetDesktopWindow(), 0,
|
||||
GetModuleHandle(0), NULL);
|
||||
assert(parent);
|
||||
|
||||
hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
|
||||
assert(hLB);
|
||||
|
||||
UpdateWindow(hLB);
|
||||
|
||||
/* make height short enough */
|
||||
SendMessage(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
|
||||
SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
|
||||
SWP_NOZORDER | SWP_NOMOVE);
|
||||
|
||||
/* make 0 item invisible */
|
||||
SendMessage(hLB, LB_SETTOPINDEX, 1, 0);
|
||||
ret = SendMessage(hLB, LB_GETTOPINDEX, 0, 0);
|
||||
ok(ret == 1, "wrong top index %d\n", ret);
|
||||
|
||||
SendMessage(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
|
||||
trace("item 0 rect (%ld,%ld-%ld,%ld)\n", rc.left, rc.top, rc.right, rc.bottom);
|
||||
ok(!IsRectEmpty(&rc), "empty item rect\n");
|
||||
ok(rc.top < 0, "rc.top is not negative (%ld)\n", rc.top);
|
||||
|
||||
DestroyWindow(hLB);
|
||||
DestroyWindow(parent);
|
||||
}
|
||||
|
||||
START_TEST(listbox)
|
||||
{
|
||||
const struct listbox_test SS =
|
||||
/* {add_style} */
|
||||
{{0},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
|
||||
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
|
||||
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
|
||||
/* {selected, anchor, caret, selcount}{TODO fields} */
|
||||
const struct listbox_test SS_NS =
|
||||
{{LBS_NOSEL},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
|
||||
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
|
||||
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
|
||||
const struct listbox_test MS =
|
||||
{{LBS_MULTIPLESEL},
|
||||
{ 0, LB_ERR, 0, 0}, {0,0,0,0},
|
||||
{ 1, 1, 1, 1}, {0,0,0,0},
|
||||
{ 2, 1, 2, 1}, {0,0,0,0},
|
||||
{ 0, LB_ERR, 0, 2}, {0,0,0,0}};
|
||||
const struct listbox_test MS_NS =
|
||||
{{LBS_MULTIPLESEL | LBS_NOSEL},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
|
||||
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
|
||||
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
|
||||
const struct listbox_test ES =
|
||||
{{LBS_EXTENDEDSEL},
|
||||
{ 0, LB_ERR, 0, 0}, {0,0,0,0},
|
||||
{ 1, 1, 1, 1}, {0,0,0,0},
|
||||
{ 2, 2, 2, 1}, {0,0,0,0},
|
||||
{ 0, LB_ERR, 0, 2}, {0,0,0,0}};
|
||||
const struct listbox_test ES_NS =
|
||||
{{LBS_EXTENDEDSEL | LBS_NOSEL},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
|
||||
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
|
||||
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
|
||||
const struct listbox_test EMS =
|
||||
{{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
|
||||
{ 0, LB_ERR, 0, 0}, {0,0,0,0},
|
||||
{ 1, 1, 1, 1}, {0,0,0,0},
|
||||
{ 2, 2, 2, 1}, {0,0,0,0},
|
||||
{ 0, LB_ERR, 0, 2}, {0,0,0,0}};
|
||||
const struct listbox_test EMS_NS =
|
||||
{{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
|
||||
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
|
||||
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
|
||||
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
|
||||
|
||||
trace (" Testing single selection...\n");
|
||||
check (SS);
|
||||
trace (" ... with NOSEL\n");
|
||||
check (SS_NS);
|
||||
trace (" Testing multiple selection...\n");
|
||||
check (MS);
|
||||
trace (" ... with NOSEL\n");
|
||||
check (MS_NS);
|
||||
trace (" Testing extended selection...\n");
|
||||
check (ES);
|
||||
trace (" ... with NOSEL\n");
|
||||
check (ES_NS);
|
||||
trace (" Testing extended and multiple selection...\n");
|
||||
check (EMS);
|
||||
trace (" ... with NOSEL\n");
|
||||
check (EMS_NS);
|
||||
|
||||
check_item_height();
|
||||
test_ownerdraw();
|
||||
}
|
260
reactos/regtests/winetests/user32/menu.c
Executable file
260
reactos/regtests/winetests/user32/menu.c
Executable file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Unit tests for menus
|
||||
*
|
||||
* Copyright 2005 Robert Shearman
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static ATOM atomMenuCheckClass;
|
||||
|
||||
static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_ENTERMENULOOP:
|
||||
/* mark window as having entered menu loop */
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, TRUE);
|
||||
/* exit menu modal loop
|
||||
* ( A SendMessage does not work on NT3.51 here ) */
|
||||
return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
|
||||
}
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
/* globals to communicate between test and wndproc */
|
||||
unsigned int MOD_maxid;
|
||||
RECT MOD_rc[4];
|
||||
int MOD_avec, MOD_hic;
|
||||
int MOD_odheight;
|
||||
#define MOD_SIZE 10
|
||||
/* wndproc used by test_menu_ownerdraw() */
|
||||
static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_MEASUREITEM:
|
||||
{
|
||||
MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
|
||||
if( winetest_debug)
|
||||
trace("WM_MEASUREITEM received %d,%d\n",
|
||||
pmis->itemWidth, pmis->itemHeight);
|
||||
MOD_odheight = pmis->itemHeight;
|
||||
pmis->itemWidth = MOD_SIZE;
|
||||
pmis->itemHeight = MOD_SIZE;
|
||||
return TRUE;
|
||||
}
|
||||
case WM_DRAWITEM:
|
||||
{
|
||||
DRAWITEMSTRUCT * pdis;
|
||||
TEXTMETRIC tm;
|
||||
HPEN oldpen;
|
||||
char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
SIZE sz;
|
||||
pdis = (DRAWITEMSTRUCT *) lparam;
|
||||
if( winetest_debug) {
|
||||
trace("WM_DRAWITEM received itemdata %ld item %d rc %ld,%ld-%ld,%ld \n",
|
||||
pdis->itemData,
|
||||
pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
|
||||
pdis->rcItem.right,pdis->rcItem.bottom );
|
||||
oldpen=SelectObject( pdis->hDC, GetStockObject(
|
||||
pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
|
||||
Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
|
||||
pdis->rcItem.right,pdis->rcItem.bottom );
|
||||
SelectObject( pdis->hDC, oldpen);
|
||||
}
|
||||
if( pdis->itemData > MOD_maxid) return TRUE;
|
||||
/* store the rectangl */
|
||||
MOD_rc[pdis->itemData] = pdis->rcItem;
|
||||
/* calculate average character width */
|
||||
GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
|
||||
MOD_avec = (sz.cx + 26)/52;
|
||||
GetTextMetrics( pdis->hDC, &tm);
|
||||
MOD_hic = tm.tmHeight;
|
||||
if( pdis->itemData == MOD_maxid) PostMessage(hwnd, WM_CANCELMODE, 0, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
static void register_menu_check_class(void)
|
||||
{
|
||||
WNDCLASS wc =
|
||||
{
|
||||
0,
|
||||
menu_check_wnd_proc,
|
||||
0,
|
||||
0,
|
||||
GetModuleHandle(NULL),
|
||||
NULL,
|
||||
LoadCursor(NULL, IDC_ARROW),
|
||||
(HBRUSH)(COLOR_BTNFACE+1),
|
||||
NULL,
|
||||
TEXT("WineMenuCheck"),
|
||||
};
|
||||
|
||||
atomMenuCheckClass = RegisterClass(&wc);
|
||||
}
|
||||
|
||||
/* demonstrates that windows lock the menu object so that it is still valid
|
||||
* even after a client calls DestroyMenu on it */
|
||||
static void test_menu_locked_by_window(void)
|
||||
{
|
||||
BOOL ret;
|
||||
HMENU hmenu;
|
||||
HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
|
||||
WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
NULL, NULL, NULL, NULL);
|
||||
ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
|
||||
hmenu = CreateMenu();
|
||||
ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
|
||||
ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
|
||||
ok(ret, "InsertMenu failed with error %ld\n", GetLastError());
|
||||
ret = SetMenu(hwnd, hmenu);
|
||||
ok(ret, "SetMenu failed with error %ld\n", GetLastError());
|
||||
ret = DestroyMenu(hmenu);
|
||||
ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
|
||||
|
||||
ret = DrawMenuBar(hwnd);
|
||||
todo_wine {
|
||||
ok(ret, "DrawMenuBar failed with error %ld\n", GetLastError());
|
||||
}
|
||||
ret = IsMenu(GetMenu(hwnd));
|
||||
ok(!ret, "Menu handle should have been destroyed\n");
|
||||
|
||||
SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
|
||||
/* did we process the WM_INITMENU message? */
|
||||
ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
todo_wine {
|
||||
ok(ret, "WM_INITMENU should have been sent\n");
|
||||
}
|
||||
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
static void test_menu_ownerdraw(void)
|
||||
{
|
||||
int i,j,k;
|
||||
BOOL ret;
|
||||
HMENU hmenu;
|
||||
LONG leftcol;
|
||||
HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
|
||||
WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
NULL, NULL, NULL, NULL);
|
||||
ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
|
||||
if( !hwnd) return;
|
||||
SetWindowLong( hwnd, GWL_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
|
||||
hmenu = CreatePopupMenu();
|
||||
ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
|
||||
if( !hmenu) { DestroyWindow(hwnd);return;}
|
||||
k=0;
|
||||
for( j=0;j<2;j++) /* create columns */
|
||||
for(i=0;i<2;i++) { /* create rows */
|
||||
ret = AppendMenu( hmenu, MF_OWNERDRAW |
|
||||
(i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
|
||||
k++;
|
||||
ok( ret, "AppendMenu failed for %d\n", k-1);
|
||||
}
|
||||
MOD_maxid = k-1;
|
||||
assert( k <= sizeof(MOD_rc)/sizeof(RECT));
|
||||
/* display the menu */
|
||||
ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
|
||||
|
||||
/* columns have a 4 pixel gap between them */
|
||||
ok( MOD_rc[0].right + 4 == MOD_rc[2].left,
|
||||
"item rectangles are not separated by 4 pixels space\n");
|
||||
/* height should be what the MEASUREITEM message has returned */
|
||||
ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
|
||||
"menu item has wrong height: %ld should be %d\n",
|
||||
MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
|
||||
/* no gaps between the rows */
|
||||
ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
|
||||
"There should not be a space between the rows, gap is %ld\n",
|
||||
MOD_rc[0].bottom - MOD_rc[1].top);
|
||||
/* test the correct value of the item height that was sent
|
||||
* by the WM_MEASUREITEM message */
|
||||
ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
|
||||
MOD_odheight == MOD_hic, /* Win95,98,ME */
|
||||
"Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
|
||||
HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
|
||||
/* test what MF_MENUBREAK did at the first position. Also show
|
||||
* that an MF_SEPARATOR is ignored in the height calculation. */
|
||||
leftcol= MOD_rc[0].left;
|
||||
ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
|
||||
/* display the menu */
|
||||
ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
|
||||
/* left should be 4 pixels less now */
|
||||
ok( leftcol == MOD_rc[0].left + 4,
|
||||
"columns should be 4 pixels to the left (actual %ld).\n",
|
||||
leftcol - MOD_rc[0].left);
|
||||
/* test width */
|
||||
ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
|
||||
"width of owner drawn menu item is wrong. Got %ld expected %d\n",
|
||||
MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
|
||||
/* and height */
|
||||
ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
|
||||
"Height is incorrect. Got %ld expected %d\n",
|
||||
MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
|
||||
|
||||
/* test width/height of a OD menu bar as well */
|
||||
ret = DestroyMenu(hmenu);
|
||||
ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
|
||||
hmenu = CreateMenu();
|
||||
ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
|
||||
if( !hmenu) { DestroyWindow(hwnd);return;}
|
||||
MOD_maxid=1;
|
||||
for(i=0;i<2;i++) {
|
||||
ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
|
||||
ok( ret, "AppendMenu failed for %d\n", i);
|
||||
}
|
||||
SetMenu( hwnd, hmenu);
|
||||
UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
|
||||
ok(ret, "SetMenu failed with error %ld\n", GetLastError());
|
||||
/* test width */
|
||||
ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
|
||||
"width of owner drawn menu item is wrong. Got %ld expected %d\n",
|
||||
MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
|
||||
/* test hight */
|
||||
ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
|
||||
"Height of owner drawn menu item is wrong. Got %ld expected %d\n",
|
||||
MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
|
||||
/* clean up */
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
START_TEST(menu)
|
||||
{
|
||||
register_menu_check_class();
|
||||
|
||||
test_menu_locked_by_window();
|
||||
test_menu_ownerdraw();
|
||||
}
|
5858
reactos/regtests/winetests/user32/msg.c
Executable file
5858
reactos/regtests/winetests/user32/msg.c
Executable file
File diff suppressed because it is too large
Load diff
255
reactos/regtests/winetests/user32/resource.c
Executable file
255
reactos/regtests/winetests/user32/resource.c
Executable file
|
@ -0,0 +1,255 @@
|
|||
/* Unit test suite for resources.
|
||||
*
|
||||
* Copyright 2004 Ferenc Wagner
|
||||
* Copyright 2003, 2004 Mike McCormack
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static void test_LoadStringA (void)
|
||||
{
|
||||
HINSTANCE hInst = GetModuleHandle (NULL);
|
||||
static const char str[] = "String resource"; /* same in resource.rc */
|
||||
char buf[128];
|
||||
struct string_test {
|
||||
int bufsiz;
|
||||
int expected;
|
||||
};
|
||||
struct string_test tests[] = {{sizeof buf, sizeof str - 1},
|
||||
{sizeof str, sizeof str - 1},
|
||||
{sizeof str - 1, sizeof str - 2}};
|
||||
unsigned int i;
|
||||
|
||||
assert (sizeof str < sizeof buf);
|
||||
for (i = 0; i < sizeof tests / sizeof tests[0]; i++) {
|
||||
const int bufsiz = tests[i].bufsiz;
|
||||
const int expected = tests[i].expected;
|
||||
const int len = LoadStringA (hInst, 0, buf, bufsiz);
|
||||
|
||||
ok (len == expected, "bufsiz=%d: got %d, expected %d\n",
|
||||
bufsiz, len, expected);
|
||||
ok (!memcmp (buf, str, len),
|
||||
"bufsiz=%d: got '%s', expected '%.*s'\n",
|
||||
bufsiz, buf, len, str);
|
||||
ok (buf[len] == 0, "bufsiz=%d: NUL termination missing\n",
|
||||
bufsiz);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_accel1(void)
|
||||
{
|
||||
UINT r, n;
|
||||
HACCEL hAccel;
|
||||
ACCEL ac[10];
|
||||
|
||||
/* now create our own valid accelerator table */
|
||||
n = 0;
|
||||
ac[n].cmd = 1000;
|
||||
ac[n].key = 'A';
|
||||
ac[n++].fVirt = FVIRTKEY | FNOINVERT;
|
||||
|
||||
ac[n].cmd = 1001;
|
||||
ac[n].key = 'B';
|
||||
ac[n++].fVirt = FNOINVERT;
|
||||
|
||||
ac[n].cmd = 0;
|
||||
ac[n].key = 0;
|
||||
ac[n++].fVirt = 0;
|
||||
|
||||
hAccel = CreateAcceleratorTable( &ac[0], n );
|
||||
ok( hAccel != NULL, "create accelerator table\n");
|
||||
|
||||
r = DestroyAcceleratorTable( hAccel );
|
||||
ok( r, "destroy accelerator table\n");
|
||||
|
||||
/* now try create an invalid one */
|
||||
n = 0;
|
||||
ac[n].cmd = 1000;
|
||||
ac[n].key = 'A';
|
||||
ac[n++].fVirt = FVIRTKEY | FNOINVERT;
|
||||
|
||||
ac[n].cmd = 0xffff;
|
||||
ac[n].key = 0xffff;
|
||||
ac[n++].fVirt = (SHORT) 0xffff;
|
||||
|
||||
ac[n].cmd = 0xfff0;
|
||||
ac[n].key = 0xffff;
|
||||
ac[n++].fVirt = (SHORT) 0xfff0;
|
||||
|
||||
ac[n].cmd = 0xfff0;
|
||||
ac[n].key = 0xffff;
|
||||
ac[n++].fVirt = (SHORT) 0x0000;
|
||||
|
||||
ac[n].cmd = 0xfff0;
|
||||
ac[n].key = 0xffff;
|
||||
ac[n++].fVirt = (SHORT) 0x0001;
|
||||
|
||||
hAccel = CreateAcceleratorTable( &ac[0], n );
|
||||
ok( hAccel != NULL, "create accelerator table\n");
|
||||
|
||||
r = CopyAcceleratorTable( hAccel, NULL, 0 );
|
||||
ok( r == n, "two entries in table\n");
|
||||
|
||||
r = CopyAcceleratorTable( hAccel, &ac[0], r );
|
||||
ok( r == n, "still should be two entries in table\n");
|
||||
|
||||
n=0;
|
||||
ok( ac[n].cmd == 1000, "cmd 0 not preserved\n");
|
||||
ok( ac[n].key == 'A', "key 0 not preserved\n");
|
||||
ok( ac[n].fVirt == (FVIRTKEY | FNOINVERT), "fVirt 0 not preserved\n");
|
||||
|
||||
n++;
|
||||
ok( ac[n].cmd == 0xffff, "cmd 1 not preserved\n");
|
||||
ok( ac[n].key == 0xffff, "key 1 not preserved\n");
|
||||
ok( ac[n].fVirt == 0x007f, "fVirt 1 not changed\n");
|
||||
|
||||
n++;
|
||||
ok( ac[n].cmd == 0xfff0, "cmd 2 not preserved\n");
|
||||
ok( ac[n].key == 0x00ff, "key 2 not preserved\n");
|
||||
ok( ac[n].fVirt == 0x0070, "fVirt 2 not changed\n");
|
||||
|
||||
n++;
|
||||
ok( ac[n].cmd == 0xfff0, "cmd 3 not preserved\n");
|
||||
ok( ac[n].key == 0x00ff, "key 3 not preserved\n");
|
||||
ok( ac[n].fVirt == 0x0000, "fVirt 3 not changed\n");
|
||||
|
||||
n++;
|
||||
ok( ac[n].cmd == 0xfff0, "cmd 4 not preserved\n");
|
||||
ok( ac[n].key == 0xffff, "key 4 not preserved\n");
|
||||
ok( ac[n].fVirt == 0x0001, "fVirt 4 not changed\n");
|
||||
|
||||
r = DestroyAcceleratorTable( hAccel );
|
||||
ok( r, "destroy accelerator table\n");
|
||||
|
||||
hAccel = CreateAcceleratorTable( &ac[0], 0 );
|
||||
ok( !hAccel, "zero elements should fail\n");
|
||||
|
||||
/* these will on crash win2k
|
||||
hAccel = CreateAcceleratorTable( NULL, 1 );
|
||||
hAccel = CreateAcceleratorTable( &ac[0], -1 );
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* memcmp on the tables works in Windows, but does not work in wine, as
|
||||
* there is an extra undefined and unused byte between fVirt and the key
|
||||
*/
|
||||
static void test_accel2(void)
|
||||
{
|
||||
ACCEL ac[2], out[2];
|
||||
HACCEL hac;
|
||||
|
||||
ac[0].cmd = 0;
|
||||
ac[0].fVirt = 0;
|
||||
ac[0].key = 0;
|
||||
|
||||
ac[1].cmd = 0;
|
||||
ac[1].fVirt = 0;
|
||||
ac[1].key = 0;
|
||||
|
||||
/*
|
||||
* crashes on win2k
|
||||
* hac = CreateAcceleratorTable( NULL, 1 );
|
||||
*/
|
||||
|
||||
/* try a zero count */
|
||||
hac = CreateAcceleratorTable( &ac[0], 0 );
|
||||
ok( !hac , "fail\n");
|
||||
ok( !DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
|
||||
/* creating one accelerator should work */
|
||||
hac = CreateAcceleratorTable( &ac[0], 1 );
|
||||
ok( hac != NULL , "fail\n");
|
||||
ok( 1 == CopyAcceleratorTable( hac, out, 1 ), "copy failed\n");
|
||||
ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
|
||||
/* how about two of the same type? */
|
||||
hac = CreateAcceleratorTable( &ac[0], 2);
|
||||
ok( hac != NULL , "fail\n");
|
||||
ok( 2 == CopyAcceleratorTable( hac, NULL, 100 ), "copy null failed\n");
|
||||
ok( 2 == CopyAcceleratorTable( hac, NULL, 0 ), "copy null failed\n");
|
||||
ok( 2 == CopyAcceleratorTable( hac, NULL, 1 ), "copy null failed\n");
|
||||
ok( 1 == CopyAcceleratorTable( hac, out, 1 ), "copy 1 failed\n");
|
||||
ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n");
|
||||
ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
/* ok( !memcmp( ac, out, sizeof ac ), "tables different\n"); */
|
||||
|
||||
/* how about two of the same type with a non-zero key? */
|
||||
ac[0].key = 0x20;
|
||||
ac[1].key = 0x20;
|
||||
hac = CreateAcceleratorTable( &ac[0], 2);
|
||||
ok( hac != NULL , "fail\n");
|
||||
ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n");
|
||||
ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
/* ok( !memcmp( ac, out, sizeof ac ), "tables different\n"); */
|
||||
|
||||
/* how about two of the same type with a non-zero virtual key? */
|
||||
ac[0].fVirt = FVIRTKEY;
|
||||
ac[0].key = 0x40;
|
||||
ac[1].fVirt = FVIRTKEY;
|
||||
ac[1].key = 0x40;
|
||||
hac = CreateAcceleratorTable( &ac[0], 2);
|
||||
ok( hac != NULL , "fail\n");
|
||||
ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n");
|
||||
/* ok( !memcmp( ac, out, sizeof ac ), "tables different\n"); */
|
||||
ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
|
||||
/* how virtual key codes */
|
||||
ac[0].fVirt = FVIRTKEY;
|
||||
hac = CreateAcceleratorTable( &ac[0], 1);
|
||||
ok( hac != NULL , "fail\n");
|
||||
ok( 1 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n");
|
||||
/* ok( !memcmp( ac, out, sizeof ac/2 ), "tables different\n"); */
|
||||
ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
|
||||
/* how turning on all bits? */
|
||||
ac[0].cmd = 0xffff;
|
||||
ac[0].fVirt = 0xff;
|
||||
ac[0].key = 0xffff;
|
||||
hac = CreateAcceleratorTable( &ac[0], 1);
|
||||
ok( hac != NULL , "fail\n");
|
||||
ok( 1 == CopyAcceleratorTable( hac, out, 1 ), "copy 1 failed\n");
|
||||
/* ok( memcmp( ac, out, sizeof ac/2 ), "tables not different\n"); */
|
||||
ok( out[0].cmd == ac[0].cmd, "cmd modified\n");
|
||||
ok( out[0].fVirt == (ac[0].fVirt&0x7f), "fVirt not modified\n");
|
||||
ok( out[0].key == ac[0].key, "key modified\n");
|
||||
ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
|
||||
/* how turning on all bits? */
|
||||
memset( ac, 0xff, sizeof ac );
|
||||
hac = CreateAcceleratorTable( &ac[0], 2);
|
||||
ok( hac != NULL , "fail\n");
|
||||
ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n");
|
||||
/* ok( memcmp( ac, out, sizeof ac ), "tables not different\n"); */
|
||||
ok( out[0].cmd == ac[0].cmd, "cmd modified\n");
|
||||
ok( out[0].fVirt == (ac[0].fVirt&0x7f), "fVirt not modified\n");
|
||||
ok( out[0].key == ac[0].key, "key modified\n");
|
||||
ok( out[1].cmd == ac[1].cmd, "cmd modified\n");
|
||||
ok( out[1].fVirt == (ac[1].fVirt&0x7f), "fVirt not modified\n");
|
||||
ok( out[1].key == ac[1].key, "key modified\n");
|
||||
ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
|
||||
}
|
||||
|
||||
START_TEST(resource)
|
||||
{
|
||||
test_LoadStringA ();
|
||||
test_accel1();
|
||||
test_accel2();
|
||||
}
|
79
reactos/regtests/winetests/user32/resource.rc
Executable file
79
reactos/regtests/winetests/user32/resource.rc
Executable file
|
@ -0,0 +1,79 @@
|
|||
/* Unit test suite for resources.
|
||||
*
|
||||
* Copyright 2004 Ferenc Wagner
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "windef.h"
|
||||
#include "winuser.h"
|
||||
|
||||
1 ACCELERATORS
|
||||
{
|
||||
"^N", 1000 /* Ctrl+'N' */
|
||||
"N", 1001 /* Shift+'n' */
|
||||
"n", 1002 /* 'n' */
|
||||
}
|
||||
|
||||
2 ACCELERATORS
|
||||
{
|
||||
78, 1000, VIRTKEY, CONTROL /* Ctrl+'N' */
|
||||
78, 1001, ASCII /* 'N' */
|
||||
110, 1002, ASCII /* 'n' */
|
||||
78, 1003, VIRTKEY, ALT /* Alt+'N' */
|
||||
78, 1004, VIRTKEY, CONTROL, SHIFT /* Ctrl+Shift+'N' */
|
||||
78, 1005, VIRTKEY, CONTROL, ALT, SHIFT /* Ctrl+Alt+Shift+'N' */
|
||||
}
|
||||
|
||||
STRINGTABLE
|
||||
{
|
||||
0 "String resource"
|
||||
}
|
||||
|
||||
TEST_DIALOG DIALOG DISCARDABLE 0, 0, 60, 30
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
|
||||
CAPTION "Test dialog"
|
||||
FONT 8, "MS Shell Dlg"
|
||||
{
|
||||
DEFPUSHBUTTON "OK", IDOK,4,4,50,14, WS_TABSTOP | WS_GROUP
|
||||
}
|
||||
|
||||
RADIO_TEST_DIALOG DIALOGEX 0, 0, 160, 80
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Radio Button Test Dialog"
|
||||
FONT 8, "MS Shell Dlg"
|
||||
{
|
||||
GROUPBOX "Static", 100,6,5,92,70
|
||||
CONTROL "Radio1", 200,"Button",BS_AUTORADIOBUTTON |
|
||||
WS_GROUP | WS_TABSTOP,17,27,39,10
|
||||
CONTROL "Radio2", 201,"Button",BS_AUTORADIOBUTTON,17,40,39,10
|
||||
PUSHBUTTON "Cancel", IDCANCEL,109,20,50,14, WS_TABSTOP | WS_GROUP
|
||||
}
|
||||
|
||||
CLASS_TEST_DIALOG DIALOG DISCARDABLE 0, 0, 91, 28
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "CreateDialogParams Test"
|
||||
CLASS "TestDialog"
|
||||
FONT 8, "MS Shell Dlg"
|
||||
{
|
||||
}
|
||||
|
||||
FOCUS_TEST_DIALOG DIALOG DISCARDABLE 0, 0, 60, 30
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_CONTROL
|
||||
CAPTION "Test dialog"
|
||||
FONT 8, "MS Shell Dlg"
|
||||
{
|
||||
EDITTEXT 200,4,4,50,14
|
||||
}
|
1737
reactos/regtests/winetests/user32/sysparams.c
Executable file
1737
reactos/regtests/winetests/user32/sysparams.c
Executable file
File diff suppressed because it is too large
Load diff
55
reactos/regtests/winetests/user32/testlist.c
Normal file
55
reactos/regtests/winetests/user32/testlist.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* Automatically generated file; DO NOT EDIT!! */
|
||||
|
||||
/* stdarg.h is needed for Winelib */
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
||||
struct test
|
||||
{
|
||||
const char *name;
|
||||
void (*func)(void);
|
||||
};
|
||||
|
||||
extern void func_class(void);
|
||||
extern void func_clipboard(void);
|
||||
extern void func_dce(void);
|
||||
extern void func_dde(void);
|
||||
extern void func_dialog(void);
|
||||
extern void func_edit(void);
|
||||
extern void func_input(void);
|
||||
extern void func_listbox(void);
|
||||
extern void func_menu(void);
|
||||
extern void func_msg(void);
|
||||
extern void func_resource(void);
|
||||
extern void func_sysparams(void);
|
||||
extern void func_text(void);
|
||||
extern void func_win(void);
|
||||
extern void func_winstation(void);
|
||||
extern void func_wsprintf(void);
|
||||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "class", func_class },
|
||||
{ "clipboard", func_clipboard },
|
||||
{ "dce", func_dce },
|
||||
{ "dde", func_dde },
|
||||
{ "dialog", func_dialog },
|
||||
{ "edit", func_edit },
|
||||
{ "input", func_input },
|
||||
{ "listbox", func_listbox },
|
||||
{ "menu", func_menu },
|
||||
{ "msg", func_msg },
|
||||
{ "resource", func_resource },
|
||||
{ "sysparams", func_sysparams },
|
||||
{ "text", func_text },
|
||||
{ "win", func_win },
|
||||
{ "winstation", func_winstation },
|
||||
{ "wsprintf", func_wsprintf },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
#define WINETEST_WANT_MAIN
|
||||
#include "wine/test.h"
|
117
reactos/regtests/winetests/user32/text.c
Executable file
117
reactos/regtests/winetests/user32/text.c
Executable file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* DrawText tests
|
||||
*
|
||||
* Copyright (c) 2004 Zach Gorman
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "winerror.h"
|
||||
|
||||
|
||||
static void test_DrawTextCalcRect(void)
|
||||
{
|
||||
HWND hwnd;
|
||||
HDC hdc;
|
||||
HFONT hFont, hOldFont;
|
||||
LOGFONTA lf;
|
||||
const char text[] = "Example text for testing DrawText in "
|
||||
"MM_HIENGLISH mode";
|
||||
INT textlen,textheight;
|
||||
RECT rect = { 0, 0, 100, 0 };
|
||||
BOOL ret;
|
||||
|
||||
/* Initialization */
|
||||
hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
|
||||
0, 0, 200, 200, 0, 0, 0, NULL);
|
||||
ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
|
||||
hdc = GetDC(hwnd);
|
||||
ok(hdc != 0, "GetDC error %lu\n", GetLastError());
|
||||
trace("hdc %p\n", hdc);
|
||||
textlen = lstrlenA(text);
|
||||
|
||||
/* LOGFONT initialization */
|
||||
memset(&lf, 0, sizeof(lf));
|
||||
lf.lfCharSet = ANSI_CHARSET;
|
||||
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
lf.lfWeight = FW_DONTCARE;
|
||||
lf.lfHeight = 0; /* mapping mode dependent */
|
||||
lf.lfQuality = DEFAULT_QUALITY;
|
||||
lstrcpyA(lf.lfFaceName, "Arial");
|
||||
|
||||
/* DrawText in MM_HIENGLISH with DT_CALCRECT */
|
||||
SetMapMode(hdc, MM_HIENGLISH);
|
||||
lf.lfHeight = 100 * 9 / 72; /* 9 point */
|
||||
hFont = CreateFontIndirectA(&lf);
|
||||
ok(hFont != 0, "CreateFontIndirectA error %lu\n",
|
||||
GetLastError());
|
||||
hOldFont = SelectObject(hdc, hFont);
|
||||
|
||||
textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT |
|
||||
DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT |
|
||||
DT_NOPREFIX);
|
||||
ok( textheight, "DrawTextA error %lu\n", GetLastError());
|
||||
|
||||
trace("MM_HIENGLISH rect.bottom %ld\n", rect.bottom);
|
||||
todo_wine ok(rect.bottom < 0, "In MM_HIENGLISH, DrawText with "
|
||||
"DT_CALCRECT should return a negative rectangle bottom. "
|
||||
"(bot=%ld)\n", rect.bottom);
|
||||
|
||||
SelectObject(hdc, hOldFont);
|
||||
ret = DeleteObject(hFont);
|
||||
ok( ret, "DeleteObject error %lu\n", GetLastError());
|
||||
|
||||
|
||||
/* DrawText in MM_TEXT with DT_CALCRECT */
|
||||
SetMapMode(hdc, MM_TEXT);
|
||||
lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc,
|
||||
LOGPIXELSY), 72); /* 9 point */
|
||||
hFont = CreateFontIndirectA(&lf);
|
||||
ok(hFont != 0, "CreateFontIndirectA error %lu\n",
|
||||
GetLastError());
|
||||
hOldFont = SelectObject(hdc, hFont);
|
||||
|
||||
textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT |
|
||||
DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT |
|
||||
DT_NOPREFIX);
|
||||
ok( textheight, "DrawTextA error %lu\n", GetLastError());
|
||||
|
||||
trace("MM_TEXT rect.bottom %ld\n", rect.bottom);
|
||||
ok(rect.bottom > 0, "In MM_TEXT, DrawText with DT_CALCRECT "
|
||||
"should return a positive rectangle bottom. (bot=%ld)\n",
|
||||
rect.bottom);
|
||||
|
||||
SelectObject(hdc, hOldFont);
|
||||
ret = DeleteObject(hFont);
|
||||
ok( ret, "DeleteObject error %lu\n", GetLastError());
|
||||
|
||||
/* Clean up */
|
||||
ret = ReleaseDC(hwnd, hdc);
|
||||
ok( ret, "ReleaseDC error %lu\n", GetLastError());
|
||||
ret = DestroyWindow(hwnd);
|
||||
ok( ret, "DestroyWindow error %lu\n", GetLastError());
|
||||
}
|
||||
|
||||
START_TEST(text)
|
||||
{
|
||||
test_DrawTextCalcRect();
|
||||
}
|
25
reactos/regtests/winetests/user32/user32_test.xml
Normal file
25
reactos/regtests/winetests/user32/user32_test.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<module name="user32_test" type="win32cui" installbase="bin" installname="user32_test.exe" warnings="true">
|
||||
<include base="user32_test">.</include>
|
||||
<define name="__USE_W32API" />
|
||||
<library>ntdll</library>
|
||||
<library>user32</library>
|
||||
<library>gdi32</library>
|
||||
<file>class.c</file>
|
||||
<file>clipboard.c</file>
|
||||
<file>dce.c</file>
|
||||
<file>dde.c</file>
|
||||
<file>dialog.c</file>
|
||||
<file>edit.c</file>
|
||||
<file>input.c</file>
|
||||
<file>listbox.c</file>
|
||||
<file>menu.c</file>
|
||||
<file>msg.c</file>
|
||||
<file>resource.c</file>
|
||||
<file>sysparams.c</file>
|
||||
<file>text.c</file>
|
||||
<file>win.c</file>
|
||||
<file>winstation.c</file>
|
||||
<file>wsprintf.c</file>
|
||||
<file>testlist.c</file>
|
||||
<file>resource.rc</file>
|
||||
</module>
|
3412
reactos/regtests/winetests/user32/win.c
Normal file
3412
reactos/regtests/winetests/user32/win.c
Normal file
File diff suppressed because it is too large
Load diff
218
reactos/regtests/winetests/user32/winstation.c
Executable file
218
reactos/regtests/winetests/user32/winstation.c
Executable file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
|
||||
#define WINSTA_ALL_ACCESS 0x037f// fixme
|
||||
#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 HDESK initial_desktop;
|
||||
|
||||
static DWORD CALLBACK thread( LPVOID arg )
|
||||
{
|
||||
HDESK d1, d2;
|
||||
HWND hwnd = CreateWindowExA(0,"BUTTON","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 %ld\n", GetLastError() );
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( !CloseDesktop( d1 ), "CloseDesktop succeeded\n" );
|
||||
ok( GetLastError() == ERROR_BUSY, "bad last error %ld\n", GetLastError() );
|
||||
print_object( d1 );
|
||||
d2 = CreateDesktop( "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, "bad last error %ld\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;
|
||||
|
||||
/* 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 %ld\n", GetLastError() );
|
||||
print_object( w1 );
|
||||
|
||||
flags = 0;
|
||||
ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" );
|
||||
ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "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 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
|
||||
ok( w2 != 0, "CreateWindowStation failed\n" );
|
||||
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, "bad last error %ld\n", GetLastError() );
|
||||
ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
|
||||
|
||||
w2 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
|
||||
ok( CloseHandle( w2 ), "CloseHandle failed\n" );
|
||||
|
||||
w2 = OpenWindowStation("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 = OpenWindowStation("dummy name", TRUE, WINSTA_ALL_ACCESS );
|
||||
ok( !w2, "open dummy win station succeeded\n" );
|
||||
|
||||
CreateMutexA( NULL, 0, "foobar" );
|
||||
w2 = CreateWindowStation("foobar", 0, WINSTA_ALL_ACCESS, NULL );
|
||||
ok( w2 != 0, "create foobar station failed\n" );
|
||||
|
||||
w3 = OpenWindowStation("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 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
|
||||
ok( !w3, "open foobar station succeeded\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, "bad last error %ld\n", GetLastError() );
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( !CloseHandle(d1), "closing thread desktop handle failed\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %ld\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 = OpenDesktop( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
|
||||
ok( !d2, "open dummy desktop succeeded\n" );
|
||||
|
||||
d2 = CreateDesktop( "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, "bad last error %ld\n", GetLastError() );
|
||||
|
||||
d3 = OpenDesktop( "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 = OpenDesktop( "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" );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
START_TEST(winstation)
|
||||
{
|
||||
/* Check whether this platform supports WindowStation calls */
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
GetProcessWindowStation();
|
||||
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||
{
|
||||
trace("WindowStation calls not supported on this platform\n");
|
||||
return;
|
||||
}
|
||||
|
||||
test_handles();
|
||||
}
|
57
reactos/regtests/winetests/user32/wsprintf.c
Executable file
57
reactos/regtests/winetests/user32/wsprintf.c
Executable file
|
@ -0,0 +1,57 @@
|
|||
/* Unit test suite for the wsprintf functions
|
||||
*
|
||||
* Copyright 2002 Bill Medland
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
|
||||
static void wsprintfATest(void)
|
||||
{
|
||||
char buf[25];
|
||||
int rc;
|
||||
|
||||
rc=wsprintfA(buf, "%010ld", -1);
|
||||
ok(rc == 10, "wsPrintfA length failure: rc=%d error=%ld\n",rc,GetLastError());
|
||||
ok((lstrcmpA(buf, "-000000001") == 0),
|
||||
"wsprintfA zero padded negative value failure: buf=[%s]\n",buf);
|
||||
}
|
||||
|
||||
static void wsprintfWTest(void)
|
||||
{
|
||||
static const WCHAR fmt[] = {'%','0','1','0','l','d','\0'};
|
||||
static const WCHAR target[] = {'-','0','0','0','0','0','0','0','0','1', '\0'};
|
||||
WCHAR buf[25];
|
||||
int rc;
|
||||
|
||||
rc=wsprintfW(buf, fmt, -1);
|
||||
if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return;
|
||||
ok(rc == 10, "wsPrintfW length failure: rc=%d error=%ld\n",rc,GetLastError());
|
||||
ok((lstrcmpW(buf, target) == 0),
|
||||
"wsprintfW zero padded negative value failure\n");
|
||||
}
|
||||
|
||||
START_TEST(wsprintf)
|
||||
{
|
||||
wsprintfATest();
|
||||
wsprintfWTest();
|
||||
}
|
Loading…
Reference in a new issue