1 /*
2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: win32ss/user/user32/windows/class.c
5 * PURPOSE: Window classes
6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * UPDATE HISTORY:
8 * 09-05-2001 CSH Created
9 */
10
11 #include <user32.h>
12
13 WINE_DEFAULT_DEBUG_CHANNEL(user32);
14
15 #define USE_VERSIONED_CLASSES
16
17 /* From rtl/actctx.c and must match! */
18 struct strsection_header
19 {
20 DWORD magic;
21 ULONG size;
22 DWORD unk1[3];
23 ULONG count;
24 ULONG index_offset;
25 DWORD unk2[2];
26 ULONG global_offset;
27 ULONG global_len;
28 };
29
30 struct wndclass_redirect_data
31 {
32 ULONG size;
33 DWORD res;
34 ULONG name_len;
35 ULONG name_offset; /* versioned name offset */
36 ULONG module_len;
37 ULONG module_offset;/* container name offset */
38 };
39
40 //
41 // Use wine hack to process extended context classes.
42 //
43 /***********************************************************************
44 * is_comctl32_class
45 */
is_comctl32_class(const WCHAR * name)46 LPCWSTR is_comctl32_class( const WCHAR *name )
47 {
48 static const WCHAR classesW[][20] =
49 {
50 {'C','o','m','b','o','B','o','x','E','x','3','2',0},
51 {'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
52 {'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
53 {'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
54 {'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
55 {'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
56 {'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
57 {'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
58 {'S','y','s','A','n','i','m','a','t','e','3','2',0},
59 {'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
60 {'S','y','s','H','e','a','d','e','r','3','2',0},
61 {'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
62 {'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
63 {'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
64 {'S','y','s','P','a','g','e','r',0},
65 {'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
66 {'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
67 {'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
68 {'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
69 };
70
71 int min = 0, max = (sizeof(classesW) / sizeof(classesW[0])) - 1;
72
73 while (min <= max)
74 {
75 int res, pos = (min + max) / 2;
76 if (!(res = strcmpiW( name, classesW[pos] ))) return classesW[pos];
77 if (res < 0) max = pos - 1;
78 else min = pos + 1;
79 }
80 return NULL;
81 }
82
83 LPCWSTR
84 FASTCALL
ClassNameToVersion(const void * lpszClass,LPCWSTR lpszMenuName,LPCWSTR * plpLibFileName,HANDLE * pContext,BOOL bAnsi)85 ClassNameToVersion(
86 const void* lpszClass,
87 LPCWSTR lpszMenuName,
88 LPCWSTR *plpLibFileName,
89 HANDLE *pContext,
90 BOOL bAnsi)
91 {
92 LPCWSTR VersionedClass = NULL;
93 #ifdef USE_VERSIONED_CLASSES
94 NTSTATUS Status;
95 #endif
96 UNICODE_STRING SectionName;
97 WCHAR SectionNameBuf[MAX_PATH] = {0};
98 ACTCTX_SECTION_KEYED_DATA KeyedData = { sizeof(KeyedData) };
99
100 if (!lpszClass)
101 {
102 ERR("Null class given !\n");
103 return NULL;
104 }
105
106 if (IS_ATOM(lpszClass))
107 {
108 RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf));
109 if(!NtUserGetAtomName(LOWORD((DWORD_PTR)lpszClass), &SectionName))
110 {
111 ERR("Couldn't get atom name for atom %x !\n", LOWORD((DWORD_PTR)lpszClass));
112 return NULL;
113 }
114 SectionName.Length = (USHORT)wcslen(SectionNameBuf) * sizeof(WCHAR);
115 TRACE("ClassNameToVersion got name %wZ from atom\n", &SectionName);
116 }
117 else
118 {
119 if (bAnsi)
120 {
121 ANSI_STRING AnsiString;
122 RtlInitAnsiString(&AnsiString, lpszClass);
123 RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf));
124 RtlAnsiStringToUnicodeString(&SectionName, &AnsiString, FALSE);
125 }
126 else
127 {
128 RtlInitUnicodeString(&SectionName, lpszClass);
129 }
130 }
131 #ifdef USE_VERSIONED_CLASSES
132 Status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
133 NULL,
134 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
135 &SectionName,
136 &KeyedData );
137
138 if (NT_SUCCESS(Status) && KeyedData.ulDataFormatVersion == 1)
139 {
140 struct strsection_header *SectionHeader = KeyedData.lpSectionBase;
141
142 /* Find activation context */
143 if(SectionHeader && SectionHeader->count > 0)
144 {
145 struct wndclass_redirect_data *WindowRedirectionData = KeyedData.lpData;
146 if(WindowRedirectionData && WindowRedirectionData->module_len)
147 {
148 LPCWSTR lpLibFileName;
149
150 VersionedClass = (WCHAR*)((BYTE*)WindowRedirectionData + WindowRedirectionData->name_offset);
151 lpLibFileName = (WCHAR*)((BYTE*)KeyedData.lpSectionBase + WindowRedirectionData->module_offset);
152 TRACE("Returning VersionedClass=%S, plpLibFileName=%S for class %S\n", VersionedClass, lpLibFileName, SectionName.Buffer);
153
154 if (pContext) *pContext = KeyedData.hActCtx;
155 if (plpLibFileName) *plpLibFileName = lpLibFileName;
156
157 }
158 }
159 }
160
161 if (KeyedData.hActCtx)
162 RtlReleaseActivationContext(KeyedData.hActCtx);
163 #endif
164
165 #ifndef DEFAULT_ACTIVATION_CONTEXTS_SUPPORTED
166 /* This block is a hack! */
167 if (!VersionedClass)
168 {
169 /*
170 * In windows the default activation context always contains comctl32v5
171 * In reactos we don't have a default activation context so we
172 * mimic wine here.
173 */
174 VersionedClass = is_comctl32_class(SectionName.Buffer);
175 if (VersionedClass)
176 {
177 if (pContext) *pContext = 0;
178 if (plpLibFileName) *plpLibFileName = L"comctl32";
179 }
180 }
181 #endif
182
183 /*
184 * The returned strings are pointers in the activation context and
185 * will get freed when the activation context gets freed
186 */
187 return VersionedClass;
188 }
189
190 //
191 // Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html
192 //
193 BOOL
194 FASTCALL
VersionRegisterClass(PCWSTR pszClass,LPCWSTR lpLibFileName,HANDLE Contex,HMODULE * phLibModule)195 VersionRegisterClass(
196 PCWSTR pszClass,
197 LPCWSTR lpLibFileName,
198 HANDLE Contex,
199 HMODULE * phLibModule)
200 {
201 BOOL Ret = FALSE;
202 HMODULE hLibModule = NULL;
203 PREGISTERCLASSNAMEW pRegisterClassNameW;
204 UNICODE_STRING ClassName;
205 WCHAR ClassNameBuf[MAX_PATH] = {0};
206 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame = { sizeof(Frame), 1 };
207
208 ERR("VersionRegisterClass: Attempting to call RegisterClassNameW in %S.\n", lpLibFileName);
209
210 RtlActivateActivationContextUnsafeFast(&Frame, Contex);
211
212 _SEH2_TRY
213 {
214 hLibModule = LoadLibraryW(lpLibFileName);
215 if (hLibModule)
216 {
217 if ((pRegisterClassNameW = (void*)GetProcAddress(hLibModule, "RegisterClassNameW")))
218 {
219 if (IS_ATOM(pszClass))
220 {
221 RtlInitEmptyUnicodeString(&ClassName, ClassNameBuf, sizeof(ClassNameBuf));
222 if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName))
223 {
224 ERR("Error while verifying ATOM\n");
225 _SEH2_YIELD(goto Error_Exit);
226 }
227 pszClass = ClassName.Buffer;
228 }
229 Ret = pRegisterClassNameW(pszClass);
230 }
231 else
232 {
233 WARN("No RegisterClassNameW PROC\n");
234 }
235 }
236 }
237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
238 {
239 ERR("Got exception while trying to call RegisterClassNameW!\n");
240 }
241 _SEH2_END
242
243 Error_Exit:
244 if (Ret || !hLibModule)
245 {
246 if (phLibModule) *phLibModule = hLibModule;
247 }
248 else
249 {
250 DWORD dwLastError = GetLastError();
251 FreeLibrary(hLibModule);
252 SetLastError(dwLastError);
253 }
254
255 RtlDeactivateActivationContextUnsafeFast(&Frame);
256 return Ret;
257 }
258
259 /*
260 * @implemented
261 */
262 BOOL
263 WINAPI
GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx)264 GetClassInfoExA(
265 HINSTANCE hInstance,
266 LPCSTR lpszClass,
267 LPWNDCLASSEXA lpwcx)
268 {
269 UNICODE_STRING ClassName = {0};
270 LPCSTR pszMenuName;
271 HMODULE hLibModule = NULL;
272 DWORD dwLastError;
273 BOOL Ret, ClassFound = FALSE, ConvertedString = FALSE;
274 LPCWSTR lpszClsVersion;
275 HANDLE pCtx = NULL;
276 LPCWSTR lpLibFileName = NULL;
277
278 TRACE("%p class/atom: %s/%04x %p\n", hInstance,
279 IS_ATOM(lpszClass) ? NULL : lpszClass,
280 IS_ATOM(lpszClass) ? lpszClass : 0,
281 lpwcx);
282
283 if (!lpwcx)
284 {
285 SetLastError(ERROR_NOACCESS);
286 return FALSE;
287 }
288
289 if (hInstance == User32Instance)
290 {
291 hInstance = NULL;
292 }
293
294 if (lpszClass == NULL)
295 {
296 SetLastError(ERROR_INVALID_PARAMETER);
297 return FALSE;
298 }
299
300 lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, TRUE);
301 if (lpszClsVersion)
302 {
303 RtlInitUnicodeString(&ClassName, lpszClsVersion);
304 }
305 else if (IS_ATOM(lpszClass))
306 {
307 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
308 }
309 else
310 {
311 ConvertedString = TRUE;
312 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpszClass))
313 {
314 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
315 return FALSE;
316 }
317 }
318
319 if (!RegisterDefaultClasses)
320 {
321 TRACE("RegisterSystemControls\n");
322 RegisterSystemControls();
323 }
324
325 for(;;)
326 {
327 Ret = NtUserGetClassInfo(hInstance,
328 &ClassName,
329 (LPWNDCLASSEXW)lpwcx,
330 (LPWSTR *)&pszMenuName,
331 TRUE);
332 if (Ret) break;
333 if (!lpLibFileName) break;
334 if (!ClassFound)
335 {
336 dwLastError = GetLastError();
337 if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS ||
338 dwLastError == ERROR_CLASS_DOES_NOT_EXIST )
339 {
340 ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
341 if (ClassFound) continue;
342 }
343 }
344 if (hLibModule)
345 {
346 dwLastError = GetLastError();
347 FreeLibrary(hLibModule);
348 SetLastError(dwLastError);
349 hLibModule = 0;
350 }
351 break;
352 }
353
354 if (Ret)
355 {
356 lpwcx->lpszClassName = lpszClass;
357 // lpwcx->lpszMenuName = pszMenuName;
358 }
359
360 if (ConvertedString)
361 {
362 RtlFreeUnicodeString(&ClassName);
363 }
364
365 return Ret;
366 }
367
368
369 /*
370 * @implemented
371 */
372 BOOL
373 WINAPI
GetClassInfoExW(HINSTANCE hInstance,LPCWSTR lpszClass,LPWNDCLASSEXW lpwcx)374 GetClassInfoExW(
375 HINSTANCE hInstance,
376 LPCWSTR lpszClass,
377 LPWNDCLASSEXW lpwcx)
378 {
379 UNICODE_STRING ClassName = {0};
380 LPWSTR pszMenuName;
381 HMODULE hLibModule = NULL;
382 DWORD dwLastError;
383 BOOL Ret, ClassFound = FALSE;
384 LPCWSTR lpszClsVersion;
385 HANDLE pCtx = NULL;
386 LPCWSTR lpLibFileName = NULL;
387
388 TRACE("%p class/atom: %S/%04x %p\n", hInstance,
389 IS_ATOM(lpszClass) ? NULL : lpszClass,
390 IS_ATOM(lpszClass) ? lpszClass : 0,
391 lpwcx);
392
393 /* From wine, for speed only, ReactOS supports the correct return in
394 * Win32k. cbSize is ignored.
395 */
396 if (!lpwcx)
397 {
398 SetLastError( ERROR_NOACCESS );
399 return FALSE;
400 }
401
402 if (hInstance == User32Instance)
403 {
404 hInstance = NULL;
405 }
406
407 if (lpszClass == NULL)
408 {
409 SetLastError(ERROR_INVALID_PARAMETER);
410 return FALSE;
411 }
412
413 lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, FALSE);
414 if (lpszClsVersion)
415 {
416 RtlInitUnicodeString(&ClassName, lpszClsVersion);
417 }
418 else if (IS_ATOM(lpszClass))
419 {
420 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
421 }
422 else
423 {
424 RtlInitUnicodeString(&ClassName, lpszClass);
425 }
426
427 if (!RegisterDefaultClasses)
428 {
429 TRACE("RegisterSystemControls\n");
430 RegisterSystemControls();
431 }
432
433 for(;;)
434 {
435 Ret = NtUserGetClassInfo( hInstance,
436 &ClassName,
437 lpwcx,
438 &pszMenuName,
439 FALSE);
440 if (Ret) break;
441 if (!lpLibFileName) break;
442 if (!ClassFound)
443 {
444 dwLastError = GetLastError();
445 if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS ||
446 dwLastError == ERROR_CLASS_DOES_NOT_EXIST )
447 {
448 ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
449 if (ClassFound) continue;
450 }
451 }
452 if (hLibModule)
453 {
454 dwLastError = GetLastError();
455 FreeLibrary(hLibModule);
456 SetLastError(dwLastError);
457 hLibModule = 0;
458 }
459 break;
460 }
461
462 if (Ret)
463 {
464 lpwcx->lpszClassName = lpszClass;
465 // lpwcx->lpszMenuName = pszMenuName;
466 }
467 return Ret;
468 }
469
470
471 /*
472 * @implemented
473 */
474 BOOL
475 WINAPI
GetClassInfoA(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass)476 GetClassInfoA(
477 HINSTANCE hInstance,
478 LPCSTR lpClassName,
479 LPWNDCLASSA lpWndClass)
480 {
481 WNDCLASSEXA wcex;
482 BOOL retval;
483
484 retval = GetClassInfoExA(hInstance, lpClassName, &wcex);
485 if (retval)
486 {
487 lpWndClass->style = wcex.style;
488 lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
489 lpWndClass->cbClsExtra = wcex.cbClsExtra;
490 lpWndClass->cbWndExtra = wcex.cbWndExtra;
491 lpWndClass->hInstance = wcex.hInstance;
492 lpWndClass->hIcon = wcex.hIcon;
493 lpWndClass->hCursor = wcex.hCursor;
494 lpWndClass->hbrBackground = wcex.hbrBackground;
495 lpWndClass->lpszMenuName = wcex.lpszMenuName;
496 lpWndClass->lpszClassName = wcex.lpszClassName;
497 }
498
499 return retval;
500 }
501
502 /*
503 * @implemented
504 */
505 BOOL
506 WINAPI
GetClassInfoW(HINSTANCE hInstance,LPCWSTR lpClassName,LPWNDCLASSW lpWndClass)507 GetClassInfoW(
508 HINSTANCE hInstance,
509 LPCWSTR lpClassName,
510 LPWNDCLASSW lpWndClass)
511 {
512 WNDCLASSEXW wcex;
513 BOOL retval;
514
515 retval = GetClassInfoExW(hInstance, lpClassName, &wcex);
516 if (retval)
517 {
518 lpWndClass->style = wcex.style;
519 lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
520 lpWndClass->cbClsExtra = wcex.cbClsExtra;
521 lpWndClass->cbWndExtra = wcex.cbWndExtra;
522 lpWndClass->hInstance = wcex.hInstance;
523 lpWndClass->hIcon = wcex.hIcon;
524 lpWndClass->hCursor = wcex.hCursor;
525 lpWndClass->hbrBackground = wcex.hbrBackground;
526 lpWndClass->lpszMenuName = wcex.lpszMenuName;
527 lpWndClass->lpszClassName = wcex.lpszClassName;
528 }
529 return retval;
530 }
531
532 //
533 // Based on find_winproc... Fixes many whine tests......
534 //
535 ULONG_PTR FASTCALL
IntGetClsWndProc(PWND pWnd,PCLS Class,BOOL Ansi)536 IntGetClsWndProc(PWND pWnd, PCLS Class, BOOL Ansi)
537 {
538 INT i;
539 ULONG_PTR gcpd, Ret = 0;
540 // If server side, sweep through proc list and return the client side proc.
541 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
542 { // Always scan through the list due to wine class "deftest".
543 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
544 {
545 if (GETPFNSERVER(i) == Class->lpfnWndProc)
546 {
547 if (Ansi)
548 Ret = (ULONG_PTR)GETPFNCLIENTA(i);
549 else
550 Ret = (ULONG_PTR)GETPFNCLIENTW(i);
551 }
552 }
553 return Ret;
554 }
555 // Set return proc.
556 Ret = (ULONG_PTR)Class->lpfnWndProc;
557 // Return the proc if one of the FnId default class type.
558 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
559 {
560 if (Ansi)
561 { // If match return the right proc by type.
562 if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
563 Ret = (ULONG_PTR)GETPFNCLIENTA(Class->fnid);
564 }
565 else
566 {
567 if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
568 Ret = (ULONG_PTR)GETPFNCLIENTW(Class->fnid);
569 }
570 }
571 // Return on change or Ansi/Unicode proc equal.
572 if ( Ret != (ULONG_PTR)Class->lpfnWndProc ||
573 Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
574 return Ret;
575
576 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
577 This will force CallWindowProc to deal with it. */
578 gcpd = NtUserGetCPD( UserHMGetHandle(pWnd),
579 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWndtoCls,
580 Ret);
581
582 return (gcpd ? gcpd : Ret);
583 }
584
585 //
586 // Based on IntGetClsWndProc
587 //
588 WNDPROC FASTCALL
IntGetWndProc(PWND pWnd,BOOL Ansi)589 IntGetWndProc(PWND pWnd, BOOL Ansi)
590 {
591 INT i;
592 WNDPROC gcpd, Ret = 0;
593 PCLS Class = DesktopPtrToUser(pWnd->pcls);
594
595 if (!Class) return Ret;
596
597 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
598 {
599 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
600 {
601 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
602 {
603 if (Ansi)
604 Ret = GETPFNCLIENTA(i);
605 else
606 Ret = GETPFNCLIENTW(i);
607 }
608 }
609 return Ret;
610 }
611 // Wine Class tests:
612 /* Edit controls are special - they return a wndproc handle when
613 GetWindowLongPtr is called with a different A/W.
614 On the other hand there is no W->A->W conversion so this control
615 is treated specially.
616 */
617 if (Class->fnid == FNID_EDIT)
618 Ret = pWnd->lpfnWndProc;
619 else
620 {
621 // Set return proc.
622 Ret = pWnd->lpfnWndProc;
623
624 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
625 {
626 if (Ansi)
627 {
628 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
629 Ret = GETPFNCLIENTA(Class->fnid);
630 }
631 else
632 {
633 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
634 Ret = GETPFNCLIENTW(Class->fnid);
635 }
636 }
637 // Return on the change.
638 if ( Ret != pWnd->lpfnWndProc)
639 return Ret;
640 }
641
642 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
643 return Ret;
644
645 gcpd = (WNDPROC)NtUserGetCPD( UserHMGetHandle(pWnd),
646 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
647 (ULONG_PTR)Ret);
648
649 return (gcpd ? gcpd : Ret);
650 }
651
652 static ULONG_PTR FASTCALL
IntGetClassLongA(PWND Wnd,PCLS Class,int nIndex)653 IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex)
654 {
655 ULONG_PTR Ret = 0;
656
657 if (nIndex >= 0)
658 {
659 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
660 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
661 {
662 SetLastError(ERROR_INVALID_PARAMETER);
663 }
664 else
665 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
666 }
667 else
668 {
669 switch (nIndex)
670 {
671 case GCL_CBWNDEXTRA:
672 Ret = (ULONG_PTR)Class->cbwndExtra;
673 break;
674
675 case GCL_CBCLSEXTRA:
676 Ret = (ULONG_PTR)Class->cbclsExtra;
677 break;
678
679 case GCL_HBRBACKGROUND:
680 Ret = (ULONG_PTR)Class->hbrBackground;
681 if (Ret != 0 && Ret < 0x4000)
682 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
683 break;
684
685 case GCL_HMODULE:
686 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
687 Ret = (ULONG_PTR)Class->hModule;
688 break;
689
690 case GCL_MENUNAME:
691 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
692 break;
693
694 case GCL_STYLE:
695 Ret = (ULONG_PTR)Class->style;
696 break;
697
698 case GCW_ATOM:
699 Ret = (ULONG_PTR)Class->atomNVClassName;
700 break;
701
702 case GCLP_HCURSOR:
703 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
704 break;
705
706 case GCLP_HICON:
707 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
708 break;
709
710 case GCLP_HICONSM:
711 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
712 break;
713
714 case GCLP_WNDPROC:
715 Ret = IntGetClsWndProc(Wnd, Class, TRUE);
716 break;
717
718 default:
719 SetLastError(ERROR_INVALID_INDEX);
720 break;
721 }
722 }
723
724 return Ret;
725 }
726
727 static ULONG_PTR FASTCALL
IntGetClassLongW(PWND Wnd,PCLS Class,int nIndex)728 IntGetClassLongW(PWND Wnd, PCLS Class, int nIndex)
729 {
730 ULONG_PTR Ret = 0;
731
732 if (nIndex >= 0)
733 {
734 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
735 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
736 {
737 SetLastError(ERROR_INVALID_PARAMETER);
738 }
739 else
740 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
741 }
742 else
743 {
744 switch (nIndex)
745 {
746 case GCL_CBWNDEXTRA:
747 Ret = (ULONG_PTR)Class->cbwndExtra;
748 break;
749
750 case GCL_CBCLSEXTRA:
751 Ret = (ULONG_PTR)Class->cbclsExtra;
752 break;
753
754 case GCLP_HBRBACKGROUND:
755 Ret = (ULONG_PTR)Class->hbrBackground;
756 if (Ret != 0 && Ret < 0x4000)
757 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
758 break;
759
760 case GCL_HMODULE:
761 Ret = (ULONG_PTR)Class->hModule;
762 break;
763
764 case GCLP_MENUNAME:
765 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
766 break;
767
768 case GCL_STYLE:
769 Ret = (ULONG_PTR)Class->style;
770 break;
771
772 case GCW_ATOM:
773 Ret = (ULONG_PTR)Class->atomNVClassName;
774 break;
775
776 case GCLP_HCURSOR:
777 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
778 break;
779
780 case GCLP_HICON:
781 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
782 break;
783
784 case GCLP_HICONSM:
785 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
786 break;
787
788 case GCLP_WNDPROC:
789 Ret = IntGetClsWndProc(Wnd, Class, FALSE);
790 break;
791
792 default:
793 SetLastError(ERROR_INVALID_INDEX);
794 break;
795 }
796 }
797
798 return Ret;
799 }
800
801 /*
802 * @implemented
803 */
804 DWORD WINAPI
GetClassLongA(HWND hWnd,int nIndex)805 GetClassLongA(HWND hWnd, int nIndex)
806 {
807 PWND Wnd;
808 PCLS Class;
809 ULONG_PTR Ret = 0;
810
811 TRACE("%p %d\n", hWnd, nIndex);
812
813 Wnd = ValidateHwnd(hWnd);
814 if (!Wnd)
815 return 0;
816
817 _SEH2_TRY
818 {
819 Class = DesktopPtrToUser(Wnd->pcls);
820 if (Class != NULL)
821 {
822 #ifdef _WIN64
823 switch (nIndex)
824 {
825 case GCLP_HBRBACKGROUND:
826 case GCLP_HCURSOR:
827 case GCLP_HICON:
828 case GCLP_HICONSM:
829 case GCLP_HMODULE:
830 case GCLP_MENUNAME:
831 case GCLP_WNDPROC:
832 SetLastError(ERROR_INVALID_INDEX);
833 break;
834
835 default:
836 Ret = IntGetClassLongA(Wnd, Class, nIndex);
837 break;
838 }
839 #else
840 Ret = IntGetClassLongA(Wnd, Class, nIndex);
841 #endif
842 }
843 else
844 {
845 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
846 }
847 }
848 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
849 {
850 Ret = 0;
851 }
852 _SEH2_END;
853
854 return (DWORD)Ret;
855 }
856
857 /*
858 * @implemented
859 */
860 DWORD WINAPI
GetClassLongW(HWND hWnd,int nIndex)861 GetClassLongW(HWND hWnd, int nIndex)
862 {
863 PWND Wnd;
864 PCLS Class;
865 ULONG_PTR Ret = 0;
866
867 TRACE("%p %d\n", hWnd, nIndex);
868
869 Wnd = ValidateHwnd(hWnd);
870 if (!Wnd)
871 return 0;
872
873 _SEH2_TRY
874 {
875 Class = DesktopPtrToUser(Wnd->pcls);
876 if (Class != NULL)
877 {
878 #ifdef _WIN64
879 switch (nIndex)
880 {
881 case GCLP_HBRBACKGROUND:
882 case GCLP_HCURSOR:
883 case GCLP_HICON:
884 case GCLP_HICONSM:
885 case GCLP_HMODULE:
886 case GCLP_MENUNAME:
887 case GCLP_WNDPROC:
888 SetLastError(ERROR_INVALID_INDEX);
889 break;
890
891 default:
892 Ret = IntGetClassLongW(Wnd, Class, nIndex);
893 break;
894 }
895 #else
896 Ret = IntGetClassLongW(Wnd, Class, nIndex);
897 #endif
898 }
899 else
900 {
901 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
902 }
903 }
904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
905 {
906 Ret = 0;
907 }
908 _SEH2_END;
909
910 return (DWORD)Ret;
911 }
912
913 #ifdef _WIN64
914 /*
915 * @implemented
916 */
917 ULONG_PTR
918 WINAPI
GetClassLongPtrA(HWND hWnd,INT nIndex)919 GetClassLongPtrA(HWND hWnd,
920 INT nIndex)
921 {
922 PWND Wnd;
923 PCLS Class;
924 ULONG_PTR Ret = 0;
925
926 TRACE("%p %d\n", hWnd, nIndex);
927
928 Wnd = ValidateHwnd(hWnd);
929 if (!Wnd)
930 return 0;
931
932 _SEH2_TRY
933 {
934 Class = DesktopPtrToUser(Wnd->pcls);
935 if (Class != NULL)
936 {
937 Ret = IntGetClassLongA(Wnd, Class, nIndex);
938 }
939 else
940 {
941 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
942 }
943 }
944 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
945 {
946 Ret = 0;
947 }
948 _SEH2_END;
949
950 return Ret;
951 }
952
953 /*
954 * @implemented
955 */
956 ULONG_PTR
957 WINAPI
GetClassLongPtrW(HWND hWnd,INT nIndex)958 GetClassLongPtrW(HWND hWnd,
959 INT nIndex)
960 {
961 PWND Wnd;
962 PCLS Class;
963 ULONG_PTR Ret = 0;
964
965 TRACE("%p %d\n", hWnd, nIndex);
966
967 Wnd = ValidateHwnd(hWnd);
968 if (!Wnd)
969 return 0;
970
971 _SEH2_TRY
972 {
973 Class = DesktopPtrToUser(Wnd->pcls);
974 if (Class != NULL)
975 {
976 Ret = IntGetClassLongW(Wnd, Class, nIndex);
977 }
978 else
979 {
980 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
981 }
982 }
983 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
984 {
985 Ret = 0;
986 }
987 _SEH2_END;
988
989 return Ret;
990 }
991 #endif
992
993
994 /*
995 * @implemented
996 */
997 int WINAPI
GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount)998 GetClassNameA(
999 HWND hWnd,
1000 LPSTR lpClassName,
1001 int nMaxCount)
1002 {
1003 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1004 int len;
1005
1006 if (nMaxCount <= 0) return 0;
1007 if (!GetClassNameW( hWnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
1008 RtlUnicodeToMultiByteN( lpClassName, nMaxCount - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
1009 lpClassName[len] = 0;
1010
1011 TRACE("%p class/atom: %s/%04x %x\n", hWnd,
1012 IS_ATOM(lpClassName) ? NULL : lpClassName,
1013 IS_ATOM(lpClassName) ? lpClassName : 0,
1014 nMaxCount);
1015
1016 return len;
1017 }
1018
1019
1020 /*
1021 * @implemented
1022 */
1023 int
1024 WINAPI
GetClassNameW(HWND hWnd,LPWSTR lpClassName,int nMaxCount)1025 GetClassNameW(
1026 HWND hWnd,
1027 LPWSTR lpClassName,
1028 int nMaxCount)
1029 {
1030 UNICODE_STRING ClassName;
1031 int Result;
1032
1033 RtlInitEmptyUnicodeString(&ClassName,
1034 lpClassName,
1035 nMaxCount * sizeof(WCHAR));
1036
1037 Result = NtUserGetClassName(hWnd,
1038 FALSE,
1039 &ClassName);
1040
1041 TRACE("%p class/atom: %S/%04x %x\n", hWnd,
1042 IS_ATOM(lpClassName) ? NULL : lpClassName,
1043 IS_ATOM(lpClassName) ? lpClassName : 0,
1044 nMaxCount);
1045
1046 return Result;
1047 }
1048
1049
1050 /*
1051 * @implemented
1052 */
1053 WORD
1054 WINAPI
GetClassWord(HWND hwnd,int offset)1055 GetClassWord(
1056 HWND hwnd,
1057 int offset)
1058 {
1059 PWND Wnd;
1060 PCLS class;
1061 WORD retvalue = 0;
1062
1063 if (offset < 0) return GetClassLongA( hwnd, offset );
1064
1065 Wnd = ValidateHwnd(hwnd);
1066 if (!Wnd)
1067 return 0;
1068
1069 class = DesktopPtrToUser(Wnd->pcls);
1070 if (class == NULL) return 0;
1071
1072 if (offset <= class->cbclsExtra - sizeof(WORD))
1073 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
1074 else
1075 SetLastError( ERROR_INVALID_INDEX );
1076
1077 return retvalue;
1078 }
1079
1080
IntGetWindowLong(HWND hwnd,INT offset,UINT size,BOOL unicode)1081 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1082 {
1083 LONG_PTR retvalue = 0;
1084 WND *wndPtr;
1085
1086 if (offset == GWLP_HWNDPARENT)
1087 {
1088 HWND parent = GetAncestor( hwnd, GA_PARENT );
1089 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1090 return (ULONG_PTR)parent;
1091 }
1092
1093 if (!(wndPtr = ValidateHwnd( hwnd )))
1094 {
1095 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1096 return 0;
1097 }
1098
1099 if (offset >= 0 && wndPtr->fnid != FNID_DESKTOP)
1100 {
1101 if (offset > (int)(wndPtr->cbwndExtra - size))
1102 {
1103 WARN("Invalid offset %d\n", offset );
1104 SetLastError( ERROR_INVALID_INDEX );
1105 return 0;
1106 }
1107 retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
1108
1109 /* WINE: special case for dialog window procedure */
1110 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1111 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
1112 return retvalue;
1113 }
1114
1115 switch(offset)
1116 {
1117 case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
1118 case GWL_STYLE: retvalue = wndPtr->style; break;
1119 case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
1120 case GWLP_ID: retvalue = wndPtr->IDMenu; break;
1121 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
1122 #if 0
1123 /* -1 is an undocumented case which returns WW* */
1124 /* source: http://www.geoffchappell.com/studies/windows/win32/user32/structs/wnd/index.htm*/
1125 case -1: retvalue = (ULONG_PTR)&wndPtr->ww; break;
1126 #else
1127 /* We don't have a WW but WND already contains the same fields in the right order, */
1128 /* so we can return a pointer to its first field */
1129 case -1: retvalue = (ULONG_PTR)&wndPtr->state; break;
1130 #endif
1131 case GWLP_WNDPROC:
1132 {
1133 if (!TestWindowProcess(wndPtr))
1134 {
1135 SetLastError(ERROR_ACCESS_DENIED);
1136 retvalue = 0;
1137 ERR("Outside Access and Denied!\n");
1138 break;
1139 }
1140 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
1141 break;
1142 }
1143 default:
1144 WARN("Unknown offset %d\n", offset );
1145 SetLastError( ERROR_INVALID_INDEX );
1146 break;
1147 }
1148 return retvalue;
1149
1150 }
1151 /*
1152 * @implemented
1153 */
1154 LONG
1155 WINAPI
GetWindowLongA(HWND hWnd,int nIndex)1156 GetWindowLongA ( HWND hWnd, int nIndex )
1157 {
1158 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
1159 }
1160
1161 /*
1162 * @implemented
1163 */
1164 LONG
1165 WINAPI
GetWindowLongW(HWND hWnd,int nIndex)1166 GetWindowLongW(HWND hWnd, int nIndex)
1167 {
1168 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
1169 }
1170
1171 #ifdef _WIN64
1172 /*
1173 * @implemented
1174 */
1175 LONG_PTR
1176 WINAPI
GetWindowLongPtrA(HWND hWnd,INT nIndex)1177 GetWindowLongPtrA(HWND hWnd,
1178 INT nIndex)
1179 {
1180 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
1181 }
1182
1183 /*
1184 * @implemented
1185 */
1186 LONG_PTR
1187 WINAPI
GetWindowLongPtrW(HWND hWnd,INT nIndex)1188 GetWindowLongPtrW(HWND hWnd,
1189 INT nIndex)
1190 {
1191 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
1192
1193 }
1194 #endif // _WIN64
1195
1196 /*
1197 * @implemented
1198 */
1199 WORD
1200 WINAPI
GetWindowWord(HWND hWnd,int nIndex)1201 GetWindowWord(HWND hWnd, int nIndex)
1202 {
1203 switch(nIndex)
1204 {
1205 case GWLP_ID:
1206 case GWLP_HINSTANCE:
1207 case GWLP_HWNDPARENT:
1208 break;
1209 default:
1210 if (nIndex < 0)
1211 {
1212 WARN("Invalid offset %d\n", nIndex );
1213 SetLastError( ERROR_INVALID_INDEX );
1214 return 0;
1215 }
1216 break;
1217 }
1218 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
1219 }
1220
1221 /*
1222 * @implemented
1223 */
1224 UINT
1225 WINAPI
RealGetWindowClassW(HWND hwnd,LPWSTR pszType,UINT cchType)1226 RealGetWindowClassW(
1227 HWND hwnd,
1228 LPWSTR pszType,
1229 UINT cchType)
1230 {
1231 UNICODE_STRING ClassName;
1232
1233 RtlInitEmptyUnicodeString(&ClassName,
1234 pszType,
1235 cchType * sizeof(WCHAR));
1236
1237 return NtUserGetClassName(hwnd,TRUE,&ClassName);
1238 }
1239
1240
1241 /*
1242 * @implemented
1243 */
1244 UINT
1245 WINAPI
RealGetWindowClassA(HWND hwnd,LPSTR pszType,UINT cchType)1246 RealGetWindowClassA(
1247 HWND hwnd,
1248 LPSTR pszType,
1249 UINT cchType)
1250 {
1251 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1252 UINT len;
1253
1254 if ((INT)cchType <= 0) return 0;
1255 if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
1256 RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
1257 pszType[len] = 0;
1258 return len;
1259 }
1260
1261 ATOM WINAPI
RegisterClassExWOWW(WNDCLASSEXW * lpwcx,LPDWORD pdwWowData,WORD fnID,DWORD dwFlags,BOOL ChkRegCls)1262 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
1263 LPDWORD pdwWowData,
1264 WORD fnID,
1265 DWORD dwFlags,
1266 BOOL ChkRegCls)
1267 {
1268 ATOM Atom;
1269 WNDCLASSEXW WndClass;
1270 UNICODE_STRING ClassName;
1271 UNICODE_STRING ClassVersion;
1272 UNICODE_STRING MenuName = {0};
1273 CLSMENUNAME clsMenuName;
1274 ANSI_STRING AnsiMenuName;
1275 LPCWSTR lpszClsVersion;
1276
1277 if (lpwcx == NULL || lpwcx->cbSize != sizeof(*lpwcx) ||
1278 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
1279 lpwcx->lpszClassName == NULL)
1280 {
1281 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1282 SetLastError(ERROR_INVALID_PARAMETER);
1283 return 0;
1284 }
1285
1286 if (ChkRegCls)
1287 {
1288 if (!RegisterDefaultClasses) RegisterSystemControls();
1289 }
1290 /*
1291 * On real Windows this looks more like:
1292 * if (lpwcx->hInstance == User32Instance &&
1293 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1294 * But since I have no idea what the magic field in the
1295 * TEB structure means, I rather decided to omit that.
1296 * -- Filip Navara
1297
1298 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1299 */
1300 if (lpwcx->hInstance == User32Instance)
1301 {
1302 TRACE("RegisterClassExWOWW User32Instance!\n");
1303 SetLastError(ERROR_INVALID_PARAMETER);
1304 return 0;
1305 }
1306 /* Yes, this is correct. We should modify the passed structure. */
1307 if (lpwcx->hInstance == NULL)
1308 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1309
1310 RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx));
1311
1312 RtlInitEmptyAnsiString(&AnsiMenuName, NULL, 0);
1313 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1314 {
1315 if (WndClass.lpszMenuName[0])
1316 {
1317 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1318 RtlUnicodeStringToAnsiString(&AnsiMenuName, &MenuName, TRUE);
1319 }
1320 }
1321 else
1322 {
1323 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1324 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1325 }
1326
1327 if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName))
1328 {
1329 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1330 }
1331 else
1332 {
1333 ClassName.Length = ClassName.MaximumLength = 0;
1334 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1335 }
1336
1337 ClassVersion = ClassName;
1338 if (fnID == 0)
1339 {
1340 lpszClsVersion = ClassNameToVersion(lpwcx->lpszClassName, NULL, NULL, NULL, FALSE);
1341 if (lpszClsVersion)
1342 {
1343 RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
1344 }
1345 }
1346
1347 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1348 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1349 clsMenuName.pusMenuName = &MenuName;
1350
1351 Atom = NtUserRegisterClassExWOW(&WndClass,
1352 &ClassName,
1353 &ClassVersion,
1354 &clsMenuName,
1355 fnID,
1356 dwFlags,
1357 pdwWowData);
1358
1359 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1360 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1361 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1362
1363 return Atom;
1364 }
1365
1366 /*
1367 * @implemented
1368 */
1369 ATOM WINAPI
RegisterClassExA(CONST WNDCLASSEXA * lpwcx)1370 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1371 {
1372 ATOM Atom;
1373 WNDCLASSEXW WndClass;
1374 WCHAR mname[MAX_BUFFER_LEN];
1375 WCHAR cname[MAX_BUFFER_LEN];
1376
1377 C_ASSERT(sizeof(WndClass) == sizeof(*lpwcx));
1378
1379 RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx));
1380
1381 if (WndClass.lpszMenuName && !IS_INTRESOURCE(WndClass.lpszMenuName))
1382 {
1383 if (WndClass.lpszMenuName[0])
1384 {
1385 if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 ))
1386 return 0;
1387
1388 WndClass.lpszMenuName = mname;
1389 }
1390 }
1391
1392 if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName))
1393 {
1394 if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 ))
1395 return 0;
1396
1397 WndClass.lpszClassName = cname;
1398 }
1399
1400 Atom = RegisterClassExWOWW(&WndClass,
1401 NULL,
1402 0,
1403 CSF_ANSIPROC,
1404 TRUE);
1405
1406 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1407 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1408 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1409
1410 return Atom;
1411 }
1412
1413 /*
1414 * @implemented
1415 */
1416 ATOM WINAPI
RegisterClassExW(CONST WNDCLASSEXW * lpwcx)1417 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1418 {
1419 ATOM Atom;
1420
1421 Atom = RegisterClassExWOWW((WNDCLASSEXW *)lpwcx, NULL, 0, 0, TRUE);
1422
1423 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1424 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1425 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1426
1427 return Atom;
1428 }
1429
1430 /*
1431 * @implemented
1432 */
1433 ATOM WINAPI
RegisterClassA(CONST WNDCLASSA * lpWndClass)1434 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1435 {
1436 WNDCLASSEXA Class;
1437
1438 if (lpWndClass == NULL)
1439 return 0;
1440
1441 /* These MUST be copied manually, since on 64 bit architectures the
1442 alignment of the members is different between the 2 structs! */
1443 Class.style = lpWndClass->style;
1444 Class.lpfnWndProc = lpWndClass->lpfnWndProc;
1445 Class.cbClsExtra = lpWndClass->cbClsExtra;
1446 Class.cbWndExtra = lpWndClass->cbWndExtra;
1447 Class.hInstance = lpWndClass->hInstance;
1448 Class.hIcon = lpWndClass->hIcon;
1449 Class.hCursor = lpWndClass->hCursor;
1450 Class.hbrBackground = lpWndClass->hbrBackground;
1451 Class.lpszMenuName = lpWndClass->lpszMenuName;
1452 Class.lpszClassName = lpWndClass->lpszClassName;
1453
1454 Class.cbSize = sizeof(Class);
1455 Class.hIconSm = NULL;
1456
1457 return RegisterClassExA(&Class);
1458 }
1459
1460 /*
1461 * @implemented
1462 */
1463 ATOM WINAPI
RegisterClassW(CONST WNDCLASSW * lpWndClass)1464 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1465 {
1466 WNDCLASSEXW Class;
1467
1468 if (lpWndClass == NULL)
1469 return 0;
1470
1471 /* These MUST be copied manually, since on 64 bit architectures the
1472 alignment of the members is different between the 2 structs! */
1473 Class.style = lpWndClass->style;
1474 Class.lpfnWndProc = lpWndClass->lpfnWndProc;
1475 Class.cbClsExtra = lpWndClass->cbClsExtra;
1476 Class.cbWndExtra = lpWndClass->cbWndExtra;
1477 Class.hInstance = lpWndClass->hInstance;
1478 Class.hIcon = lpWndClass->hIcon;
1479 Class.hCursor = lpWndClass->hCursor;
1480 Class.hbrBackground = lpWndClass->hbrBackground;
1481 Class.lpszMenuName = lpWndClass->lpszMenuName;
1482 Class.lpszClassName = lpWndClass->lpszClassName;
1483
1484 Class.cbSize = sizeof(Class);
1485 Class.hIconSm = NULL;
1486
1487 return RegisterClassExW(&Class);
1488 }
1489
1490 /*
1491 * @implemented
1492 */
1493 DWORD
1494 WINAPI
SetClassLongA(HWND hWnd,int nIndex,LONG dwNewLong)1495 SetClassLongA(HWND hWnd,
1496 int nIndex,
1497 LONG dwNewLong)
1498 {
1499 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1500 UNICODE_STRING Value = {0};
1501 BOOL Allocated = FALSE;
1502 DWORD Ret;
1503
1504 /* FIXME - portability!!!! */
1505
1506 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1507 {
1508 if (!IS_INTRESOURCE(lpStr))
1509 {
1510 if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr))
1511 {
1512 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1513 return 0;
1514 }
1515
1516 Allocated = TRUE;
1517 }
1518 else
1519 {
1520 Value.Buffer = (PWSTR)lpStr;
1521 }
1522
1523 dwNewLong = (LONG_PTR)&Value;
1524 }
1525 else if (nIndex == GCW_ATOM && lpStr != NULL)
1526 {
1527 if (!IS_ATOM(lpStr))
1528 {
1529 if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr))
1530 {
1531 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1532 return 0;
1533 }
1534
1535 Allocated = TRUE;
1536 }
1537 else
1538 {
1539 Value.Buffer = (PWSTR)lpStr;
1540 }
1541
1542 dwNewLong = (LONG_PTR)&Value;
1543 }
1544
1545 Ret = (DWORD)NtUserSetClassLong(hWnd,
1546 nIndex,
1547 dwNewLong,
1548 TRUE);
1549
1550 if (Allocated)
1551 {
1552 RtlFreeUnicodeString(&Value);
1553 }
1554
1555 return Ret;
1556 }
1557
1558
1559 /*
1560 * @implemented
1561 */
1562 DWORD
1563 WINAPI
SetClassLongW(HWND hWnd,int nIndex,LONG dwNewLong)1564 SetClassLongW(HWND hWnd,
1565 int nIndex,
1566 LONG dwNewLong)
1567 {
1568 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1569 UNICODE_STRING Value = {0};
1570
1571 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1572
1573 /* FIXME - portability!!!! */
1574
1575 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1576 {
1577 if (!IS_INTRESOURCE(lpStr))
1578 RtlInitUnicodeString(&Value, lpStr);
1579 else
1580 Value.Buffer = lpStr;
1581
1582 dwNewLong = (LONG_PTR)&Value;
1583 }
1584 else if (nIndex == GCW_ATOM && lpStr != NULL)
1585 {
1586 if (!IS_ATOM(lpStr))
1587 RtlInitUnicodeString(&Value, lpStr);
1588 else
1589 Value.Buffer = lpStr;
1590
1591 dwNewLong = (LONG_PTR)&Value;
1592 }
1593
1594 return (DWORD)NtUserSetClassLong(hWnd,
1595 nIndex,
1596 dwNewLong,
1597 FALSE);
1598 }
1599
1600 #ifdef _WIN64
1601 /*
1602 * @unimplemented
1603 */
1604 ULONG_PTR
1605 WINAPI
SetClassLongPtrA(HWND hWnd,INT nIndex,LONG_PTR dwNewLong)1606 SetClassLongPtrA(HWND hWnd,
1607 INT nIndex,
1608 LONG_PTR dwNewLong)
1609 {
1610 return NtUserSetClassLongPtr(hWnd,
1611 nIndex,
1612 dwNewLong,
1613 TRUE);
1614 }
1615
1616 /*
1617 * @unimplemented
1618 */
1619 ULONG_PTR
1620 WINAPI
SetClassLongPtrW(HWND hWnd,INT nIndex,LONG_PTR dwNewLong)1621 SetClassLongPtrW(HWND hWnd,
1622 INT nIndex,
1623 LONG_PTR dwNewLong)
1624 {
1625 return NtUserSetClassLongPtr(hWnd,
1626 nIndex,
1627 dwNewLong,
1628 FALSE);
1629 }
1630 #endif // _WIN64
1631
1632 /*
1633 * @implemented
1634 */
1635 WORD
1636 WINAPI
SetClassWord(HWND hWnd,int nIndex,WORD wNewWord)1637 SetClassWord(
1638 HWND hWnd,
1639 int nIndex,
1640 WORD wNewWord)
1641 /*
1642 * NOTE: Obsoleted in 32-bit windows
1643 */
1644 {
1645 if ((nIndex < 0) && (nIndex != GCW_ATOM))
1646 return 0;
1647
1648 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1649 }
1650
1651 /*
1652 * @implemented
1653 */
1654 WORD
1655 WINAPI
SetWindowWord(HWND hWnd,int nIndex,WORD wNewWord)1656 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1657 {
1658 switch(nIndex)
1659 {
1660 case GWLP_ID:
1661 case GWLP_HINSTANCE:
1662 case GWLP_HWNDPARENT:
1663 break;
1664 default:
1665 if (nIndex < 0)
1666 {
1667 WARN("Invalid offset %d\n", nIndex );
1668 SetLastError( ERROR_INVALID_INDEX );
1669 return 0;
1670 }
1671 break;
1672 }
1673 /* DO NOT USE NtUserSetWindowLong(Ptr)! */
1674 return NtUserSetWindowWord(hWnd, nIndex, wNewWord);
1675 }
1676
1677 /*
1678 * @implemented
1679 */
1680 LONG
1681 WINAPI
1682 DECLSPEC_HOTPATCH
SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong)1683 SetWindowLongA(
1684 HWND hWnd,
1685 int nIndex,
1686 LONG dwNewLong)
1687 {
1688 /* DO NOT USE NtUserSetWindowLongPtr! */
1689 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1690 }
1691
1692 /*
1693 * @implemented
1694 */
1695 LONG
1696 WINAPI
SetWindowLongW(HWND hWnd,int nIndex,LONG dwNewLong)1697 SetWindowLongW(
1698 HWND hWnd,
1699 int nIndex,
1700 LONG dwNewLong)
1701 {
1702 /* DO NOT USE NtUserSetWindowLongPtr! */
1703 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1704 }
1705
1706 #ifdef _WIN64
1707 /*
1708 * @implemented
1709 */
1710 LONG_PTR
1711 WINAPI
SetWindowLongPtrA(HWND hWnd,INT nIndex,LONG_PTR dwNewLong)1712 SetWindowLongPtrA(HWND hWnd,
1713 INT nIndex,
1714 LONG_PTR dwNewLong)
1715 {
1716 return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, TRUE);
1717 }
1718
1719 /*
1720 * @implemented
1721 */
1722 LONG_PTR
1723 WINAPI
SetWindowLongPtrW(HWND hWnd,INT nIndex,LONG_PTR dwNewLong)1724 SetWindowLongPtrW(HWND hWnd,
1725 INT nIndex,
1726 LONG_PTR dwNewLong)
1727 {
1728 return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, FALSE);
1729 }
1730 #endif
1731
1732 /*
1733 * @implemented
1734 */
1735 BOOL
1736 WINAPI
UnregisterClassA(LPCSTR lpClassName,HINSTANCE hInstance)1737 UnregisterClassA(
1738 LPCSTR lpClassName,
1739 HINSTANCE hInstance)
1740 {
1741 UNICODE_STRING ClassName = {0};
1742 BOOL Ret;
1743 LPCWSTR lpszClsVersion;
1744 BOOL ConvertedString = FALSE;
1745
1746 TRACE("class/atom: %s/%04x %p\n",
1747 IS_ATOM(lpClassName) ? NULL : lpClassName,
1748 IS_ATOM(lpClassName) ? lpClassName : 0,
1749 hInstance);
1750
1751 lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE);
1752 if (lpszClsVersion)
1753 {
1754 RtlInitUnicodeString(&ClassName, lpszClsVersion);
1755 }
1756 else if (!IS_ATOM(lpClassName))
1757 {
1758 ConvertedString = TRUE;
1759 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpClassName))
1760 {
1761 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1762 return 0;
1763 }
1764 }
1765 else
1766 {
1767 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1768 }
1769
1770 Ret = NtUserUnregisterClass(&ClassName, hInstance, 0);
1771
1772 if (ConvertedString)
1773 RtlFreeUnicodeString(&ClassName);
1774
1775 return Ret;
1776 }
1777
1778 /*
1779 * @implemented
1780 */
1781 BOOL
1782 WINAPI
UnregisterClassW(LPCWSTR lpClassName,HINSTANCE hInstance)1783 UnregisterClassW(
1784 LPCWSTR lpClassName,
1785 HINSTANCE hInstance)
1786 {
1787 UNICODE_STRING ClassName = {0};
1788 LPCWSTR lpszClsVersion;
1789
1790 TRACE("class/atom: %S/%04x %p\n",
1791 IS_ATOM(lpClassName) ? NULL : lpClassName,
1792 IS_ATOM(lpClassName) ? lpClassName : 0,
1793 hInstance);
1794
1795 lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE);
1796 if (lpszClsVersion)
1797 {
1798 RtlInitUnicodeString(&ClassName, lpszClsVersion);
1799 }
1800 else if (!IS_ATOM(lpClassName))
1801 {
1802 RtlInitUnicodeString(&ClassName, lpClassName);
1803 }
1804 else
1805 {
1806 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1807 }
1808
1809 return NtUserUnregisterClass(&ClassName, hInstance, 0);
1810 }
1811
1812 /* EOF */
1813