1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         Test for NtUserCreateWindowEx
5  */
6 
7 #include <win32nt.h>
8 
9 static
10 inline
11 HWND
12 CreateWnd(HINSTANCE hinst,
13           PLARGE_STRING clsName,
14           PLARGE_STRING clsVer,
15           PLARGE_STRING wndName)
16 {
17     return NtUserCreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
18                                 clsName,
19                                 clsVer,
20                                 wndName,
21                                 WS_CAPTION,
22                                 CW_USEDEFAULT,
23                                 CW_USEDEFAULT,
24                                 100,
25                                 100,
26                                 NULL,
27                                 NULL,
28                                 hinst,
29                                 0,
30                                 0,
31                                 NULL);
32 }
33 
34 /* WndProc for class1 */
35 
36 LRESULT CALLBACK wndProc1(HWND hwnd, UINT msg, WPARAM wPrm, LPARAM lPrm)
37 {
38     return DefWindowProc(hwnd, msg, wPrm, lPrm);
39 }
40 
41 /* WndProc for class2 */
42 LRESULT CALLBACK wndProc2(HWND hwnd, UINT msg, WPARAM wPrm, LPARAM lPrm)
43 {
44     return DefWindowProc(hwnd, msg, wPrm, lPrm);
45 }
46 
47 
48 START_TEST(NtUserCreateWindowEx)
49 {
50     HINSTANCE hinst = GetModuleHandle(NULL);
51     WNDCLASSEXW wclex = {0};
52     WNDCLASSEXW wclex2 = {0};
53     WNDCLASSEXW res = {0};
54 
55     /* Unicode strings for NtRegisterClassExWOW */
56     UNICODE_STRING cls = {14, 32, L"MyClass"};
57     UNICODE_STRING ver_cls = {12, 32, L"v2test"};
58     UNICODE_STRING another_cls = {10, 32, L"Dummy"};
59     UNICODE_STRING menu = {10, 10, L"MuMnu"};
60     UNICODE_STRING null_cls = {2, 2, L""};
61 
62     /* LARGE_STRING for NtUserCreateWindowEx */
63     LARGE_STRING l_dummy = {14, 32, 0, L"DummyMe"};
64     LARGE_STRING l_empty = {0, 0, 0, L""};
65     LARGE_STRING l_wndName = {32, 32, 0, L""};
66     LARGE_STRING l_cls = {cls.Length, 32, 0, cls.Buffer};
67     LARGE_STRING l_ver_cls = {ver_cls.Length, 32, 0, ver_cls.Buffer};
68     WCHAR bufMe[255] = {0};
69     UNICODE_STRING capture = {255, 255, bufMe};
70     PWSTR pwstr = NULL;
71     CLSMENUNAME clsMenuName, outClsMnu = {0};
72     ATOM atom, atom2, atom3;
73     HWND hwnd;
74 
75     clsMenuName.pszClientAnsiMenuName = "MuMnu";
76     clsMenuName.pwszClientUnicodeMenuName = menu.Buffer;
77     clsMenuName.pusMenuName = &menu;
78 
79     wclex.cbSize = sizeof(WNDCLASSEXW);
80     wclex.style = 0;
81     wclex.lpfnWndProc = wndProc1;
82     wclex.cbClsExtra = 2;
83     wclex.cbWndExtra = 4;
84     wclex.hInstance = hinst;
85     wclex.hIcon = NULL;
86     wclex.hCursor = NULL;
87     wclex.hbrBackground = CreateSolidBrush(RGB(4,7,5));
88     wclex.lpszMenuName = menu.Buffer;
89     wclex.lpszClassName = cls.Buffer;
90     wclex.hIconSm = NULL;
91     memcpy(&wclex2, &wclex, sizeof(wclex));
92     wclex2.lpfnWndProc = wndProc2;
93 
94     /* Register our first version */
95     atom = NtUserRegisterClassExWOW(&wclex,       /* wndClass */
96                                     &cls,         /* ClassName */
97                                     &cls,         /* Version */
98                                     &clsMenuName, /* MenuName */
99                                     0,
100                                     0,
101                                     NULL);
102     TEST(atom != 0);
103 
104     /* Register second version */
105     atom2 = NtUserRegisterClassExWOW(&wclex2,      /* wndClass */
106                                      &cls,         /* ClassName */
107                                      &ver_cls,     /* Version */
108                                      &clsMenuName, /* MenuName */
109                                      0,
110                                      0,
111                                      NULL);
112 
113     atom3 = NtUserRegisterClassExWOW(&wclex2,      /* wndClass */
114                                     &another_cls, /* ClassName */
115                                     &another_cls, /* Version */
116                                     &clsMenuName, /* MenuName */
117                                     0,
118                                     0,
119                                     NULL);
120 
121     TEST(NtUserRegisterClassExWOW(&wclex2,      /* wndClass */
122                                   &cls,         /* ClassName */
123                                   NULL,         /* Version */
124                                   &clsMenuName, /* MenuName */
125                                   0,
126                                   0,
127                                   NULL) == 0);
128 
129     TEST(NtUserRegisterClassExWOW(&wclex2,      /* wndClass */
130                                   &cls,         /* ClassName */
131                                   &null_cls,    /* Version */
132                                   &clsMenuName, /* MenuName */
133                                   0,
134                                   0,
135                                   NULL) == 0);
136 
137     TEST(NtUserGetWOWClass(hinst, &ver_cls) != 0);
138     TEST(NtUserGetWOWClass(hinst, &ver_cls) != NtUserGetWOWClass(hinst, &cls));    TEST(atom2 != 0);
139     TEST(atom == atom2 && (atom | atom2) != 0);
140 
141     /* Create a window without versioned class */
142     TEST(CreateWnd(hinst, &l_cls, NULL, &l_wndName) == 0);
143     TEST(CreateWnd(hinst, &l_cls, &l_wndName, &l_wndName) == 0);
144 
145     /* Now, create our first window */
146     hwnd = CreateWnd(hinst, &l_cls, &l_cls, &l_wndName);
147     TEST(hwnd != 0);
148     if(hwnd)
149     {
150         /* Test some settings about the window */
151         TEST((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == wndProc1);
152 
153         /* Check class name isn't versioned */
154         TEST(NtUserGetClassName(hwnd, TRUE, &capture) != 0);
155         TEST(wcscmp(capture.Buffer, cls.Buffer) == 0);
156         TEST(wcscmp(capture.Buffer, ver_cls.Buffer) != 0);
157         ZeroMemory(capture.Buffer, 255);
158 
159         /* Check what return GetClassLong */
160         TEST(GetClassLong(hwnd, GCW_ATOM) == atom);
161         TEST(NtUserSetClassLong(hwnd, GCW_ATOM, atom3, FALSE) == atom);
162         NtUserGetClassName(hwnd, TRUE, &capture);
163         TEST(wcscmp(capture.Buffer, another_cls.Buffer) == 0);
164 
165         /* Finally destroy it */
166         DestroyWindow(hwnd);
167     }
168 
169     /* Create our second version */
170     hwnd = CreateWnd(hinst, &l_cls, &l_ver_cls, &l_wndName);
171     TEST(hwnd != 0);
172     if (hwnd)
173     {
174         /* Test settings about window */
175         TEST((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == wndProc2);
176 
177         /* Check class name isn't versioned */
178         TEST(NtUserGetClassName(hwnd, TRUE, &capture) != 0);
179         TEST(wcscmp(capture.Buffer, cls.Buffer) == 0);
180         TEST(wcscmp(capture.Buffer, ver_cls.Buffer) != 0);
181         ZeroMemory(capture.Buffer, 255);
182 
183         /* Check what return GetClassLong */
184         TEST(GetClassLong(hwnd, GCW_ATOM) == atom);
185 
186         TEST(NtUserFindWindowEx(NULL, NULL, &cls, (UNICODE_STRING*)&l_empty, 0) == hwnd);
187 
188         /* Finally destroy it */
189         DestroyWindow(hwnd);
190     }
191 
192     /* Create a nonexistent window */
193     hwnd = CreateWnd(hinst, &l_cls, &l_dummy, &l_wndName);
194     TEST(hwnd == 0);
195     if (hwnd) DestroyWindow(hwnd);
196 
197     /* Get non-versioned class info */
198     res.cbSize = sizeof(res);
199     SetLastError(0);
200     TEST(NtUserGetClassInfo(hinst, &cls, &res, &pwstr, 0) != 0);
201     TEST(GetLastError() == 0);
202     TEST(res.cbSize == wclex.cbSize);
203     TEST(res.style == wclex.style);
204     TEST(res.lpfnWndProc == wclex.lpfnWndProc);
205     TEST(res.cbClsExtra == wclex.cbClsExtra);
206     TEST(res.cbWndExtra == wclex.cbWndExtra);
207     TEST(res.hInstance == wclex.hInstance);
208     TEST(res.hIcon == wclex.hIcon);
209     TEST(res.hCursor == wclex.hCursor);
210     TEST(res.hbrBackground == wclex.hbrBackground);
211     TEST(res.lpszMenuName == 0);
212     TEST(res.lpszClassName == 0);
213     TEST(res.hIconSm == wclex.hIconSm);
214 
215     /* Get versioned class info */
216     TEST(NtUserGetClassInfo(hinst, &ver_cls, &res, &pwstr, 0) == atom2);
217     TEST(GetLastError() == 0);
218     TEST(res.cbSize == wclex2.cbSize);
219     TEST(res.style == wclex2.style);
220     TEST(res.lpfnWndProc == wclex2.lpfnWndProc);
221     TEST(res.cbClsExtra == wclex2.cbClsExtra);
222     TEST(res.cbWndExtra == wclex2.cbWndExtra);
223     TEST(res.hInstance == wclex2.hInstance);
224     TEST(res.hIcon == wclex2.hIcon);
225     TEST(res.hCursor == wclex2.hCursor);
226     TEST(res.hbrBackground == wclex2.hbrBackground);
227     TEST(res.lpszMenuName == 0);
228     TEST(res.lpszClassName == 0);
229     TEST(res.hIconSm == wclex2.hIconSm);
230 
231     /* Create a new window from our old class. Since we set a new class atom,
232      * it should be set to our new atom
233      */
234     hwnd = NULL;
235     hwnd = CreateWnd(hinst, &l_cls, &l_cls, &l_wndName);
236     TEST(hwnd != NULL);
237     if (hwnd)
238     {
239         TEST(GetClassLong(hwnd, GCW_ATOM) == atom3);
240         TEST(NtUserGetClassName(hwnd, TRUE, &capture) != 0);
241         TEST(wcscmp(capture.Buffer, another_cls.Buffer) == 0);
242         DestroyWindow(hwnd);
243     }
244 
245     /* Test class destruction */
246     TEST(NtUserUnregisterClass(&cls, hinst, (PCLSMENUNAME)0xbad) != 0);
247     TEST(NtUserUnregisterClass(&ver_cls, hinst, &outClsMnu) != 0);
248     TEST(NtUserUnregisterClass(&another_cls, hinst, &outClsMnu) != 0);
249     TEST(NtUserUnregisterClass(&menu, hinst, &outClsMnu) == 0);
250 
251     /* Make sure that the classes got destroyed */
252     TEST(NtUserGetWOWClass(hinst, &cls) == 0);
253     TEST(NtUserGetWOWClass(hinst, &ver_cls) == 0);
254     TEST(NtUserGetWOWClass(hinst, &another_cls) == 0);
255 }
256