added user32 wine regression test

svn path=/trunk/; revision=17125
This commit is contained in:
Steven Edwards 2005-08-06 23:41:45 +00:00
parent 68cfd5b234
commit bf046096f1
19 changed files with 16283 additions and 0 deletions

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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);
}

View 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();
}

View 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();
}

File diff suppressed because it is too large Load diff

View 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();
}

View 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
}

File diff suppressed because it is too large Load diff

View 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"

View 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();
}

View 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>

File diff suppressed because it is too large Load diff

View 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();
}

View 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();
}