[CMAKE]
[reactos.git] / dll / win32 / user32 / windows / class.c
1 /*
2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/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 #include <wine/debug.h>
14 WINE_DEFAULT_DEBUG_CHANNEL(user32);
15
16 /*
17 * @implemented
18 */
19 BOOL
20 WINAPI
21 GetClassInfoExA(
22 HINSTANCE hInstance,
23 LPCSTR lpszClass,
24 LPWNDCLASSEXA lpwcx)
25 {
26 UNICODE_STRING ClassName = {0};
27 BOOL Ret;
28 LPCSTR pszMenuName;
29
30 TRACE("%p class/atom: %s/%04x %p\n", hInstance,
31 IS_ATOM(lpszClass) ? NULL : lpszClass,
32 IS_ATOM(lpszClass) ? lpszClass : 0,
33 lpwcx);
34
35 if (!lpwcx)
36 {
37 SetLastError( ERROR_NOACCESS );
38 return FALSE;
39 }
40
41 if (hInstance == User32Instance)
42 {
43 hInstance = NULL;
44 }
45
46 if (lpszClass == NULL)
47 {
48 SetLastError(ERROR_INVALID_PARAMETER);
49 return FALSE;
50 }
51
52 if (!RegisterDefaultClasses)
53 {
54 ERR("GetClassInfoExA RegisterSystemControls\n");
55 RegisterSystemControls();
56 }
57
58 if (IS_ATOM(lpszClass))
59 {
60 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
61 }
62 else
63 {
64 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
65 lpszClass))
66 {
67 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
68 return FALSE;
69 }
70 }
71
72 Ret = NtUserGetClassInfo(hInstance,
73 &ClassName,
74 (LPWNDCLASSEXW)lpwcx,
75 (LPWSTR *)&pszMenuName,
76 TRUE);
77 if (Ret)
78 {
79 lpwcx->lpszClassName = lpszClass;
80 // lpwcx->lpszMenuName = pszMenuName;
81 }
82
83 if (!IS_ATOM(lpszClass))
84 {
85 RtlFreeUnicodeString(&ClassName);
86 }
87
88 return Ret;
89 }
90
91
92 /*
93 * @implemented
94 */
95 BOOL
96 WINAPI
97 GetClassInfoExW(
98 HINSTANCE hInstance,
99 LPCWSTR lpszClass,
100 LPWNDCLASSEXW lpwcx)
101 {
102 UNICODE_STRING ClassName = {0};
103 BOOL Ret;
104 LPWSTR pszMenuName;
105
106 TRACE("%p class/atom: %S/%04x %p\n", hInstance,
107 IS_ATOM(lpszClass) ? NULL : lpszClass,
108 IS_ATOM(lpszClass) ? lpszClass : 0,
109 lpwcx);
110
111 /* From wine, for speed only, ReactOS supports the correct return in
112 * Win32k. cbSize is ignored.
113 */
114 if (!lpwcx)
115 {
116 SetLastError( ERROR_NOACCESS );
117 return FALSE;
118 }
119
120 if (hInstance == User32Instance)
121 {
122 hInstance = NULL;
123 }
124
125 if (lpszClass == NULL)
126 {
127 SetLastError(ERROR_INVALID_PARAMETER);
128 return FALSE;
129 }
130
131 if (!RegisterDefaultClasses)
132 {
133 ERR("GetClassInfoExW RegisterSystemControls\n");
134 RegisterSystemControls();
135 }
136
137 if (IS_ATOM(lpszClass))
138 {
139 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
140 }
141 else
142 {
143 RtlInitUnicodeString(&ClassName,
144 lpszClass);
145 }
146
147 Ret = NtUserGetClassInfo( hInstance,
148 &ClassName,
149 lpwcx,
150 &pszMenuName,
151 FALSE);
152 if (Ret)
153 {
154 lpwcx->lpszClassName = lpszClass;
155 // lpwcx->lpszMenuName = pszMenuName;
156 }
157 return Ret;
158 }
159
160
161 /*
162 * @implemented
163 */
164 BOOL
165 WINAPI
166 GetClassInfoA(
167 HINSTANCE hInstance,
168 LPCSTR lpClassName,
169 LPWNDCLASSA lpWndClass)
170 {
171 WNDCLASSEXA wcex;
172 BOOL retval;
173
174 retval = GetClassInfoExA(hInstance, lpClassName, &wcex);
175 if (retval)
176 {
177 lpWndClass->style = wcex.style;
178 lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
179 lpWndClass->cbClsExtra = wcex.cbClsExtra;
180 lpWndClass->cbWndExtra = wcex.cbWndExtra;
181 lpWndClass->hInstance = wcex.hInstance;
182 lpWndClass->hIcon = wcex.hIcon;
183 lpWndClass->hCursor = wcex.hCursor;
184 lpWndClass->hbrBackground = wcex.hbrBackground;
185 lpWndClass->lpszMenuName = wcex.lpszMenuName;
186 lpWndClass->lpszClassName = wcex.lpszClassName;
187 }
188
189 return retval;
190 }
191
192 /*
193 * @implemented
194 */
195 BOOL
196 WINAPI
197 GetClassInfoW(
198 HINSTANCE hInstance,
199 LPCWSTR lpClassName,
200 LPWNDCLASSW lpWndClass)
201 {
202 WNDCLASSEXW wcex;
203 BOOL retval;
204
205 retval = GetClassInfoExW(hInstance, lpClassName, &wcex);
206 if (retval)
207 {
208 lpWndClass->style = wcex.style;
209 lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
210 lpWndClass->cbClsExtra = wcex.cbClsExtra;
211 lpWndClass->cbWndExtra = wcex.cbWndExtra;
212 lpWndClass->hInstance = wcex.hInstance;
213 lpWndClass->hIcon = wcex.hIcon;
214 lpWndClass->hCursor = wcex.hCursor;
215 lpWndClass->hbrBackground = wcex.hbrBackground;
216 lpWndClass->lpszMenuName = wcex.lpszMenuName;
217 lpWndClass->lpszClassName = wcex.lpszClassName;
218 }
219 return retval;
220 }
221
222 //
223 // Based on find_winproc... Fixes many whine tests......
224 //
225 ULONG_PTR FASTCALL
226 IntGetClsWndProc(PWND pWnd, PCLS Class, BOOL Ansi)
227 {
228 INT i;
229 ULONG_PTR gcpd, Ret = 0;
230 // If server side, sweep through proc list and return the client side proc.
231 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
232 { // Always scan through the list due to wine class "deftest".
233 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
234 {
235 if (GETPFNSERVER(i) == Class->lpfnWndProc)
236 {
237 if (Ansi)
238 Ret = (ULONG_PTR)GETPFNCLIENTA(i);
239 else
240 Ret = (ULONG_PTR)GETPFNCLIENTW(i);
241 }
242 }
243 return Ret;
244 }
245 // Set return proc.
246 Ret = (ULONG_PTR)Class->lpfnWndProc;
247 // Return the proc if one of the FnId default class type.
248 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
249 {
250 if (Ansi)
251 { // If match return the right proc by type.
252 if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
253 Ret = (ULONG_PTR)GETPFNCLIENTA(Class->fnid);
254 }
255 else
256 {
257 if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
258 Ret = (ULONG_PTR)GETPFNCLIENTW(Class->fnid);
259 }
260 }
261 // Return on change or Ansi/Unicode proc equal.
262 if ( Ret != (ULONG_PTR)Class->lpfnWndProc ||
263 Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
264 return Ret;
265
266 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
267 This will force CallWindowProc to deal with it. */
268 gcpd = NtUserGetCPD( UserHMGetHandle(pWnd),
269 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWndtoCls,
270 Ret);
271
272 return (gcpd ? gcpd : Ret);
273 }
274
275 //
276 // Based on IntGetClsWndProc
277 //
278 WNDPROC FASTCALL
279 IntGetWndProc(PWND pWnd, BOOL Ansi)
280 {
281 INT i;
282 WNDPROC gcpd, Ret = 0;
283 PCLS Class = DesktopPtrToUser(pWnd->pcls);
284
285 if (!Class) return Ret;
286
287 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
288 {
289 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
290 {
291 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
292 {
293 if (Ansi)
294 Ret = GETPFNCLIENTA(i);
295 else
296 Ret = GETPFNCLIENTW(i);
297 }
298 }
299 return Ret;
300 }
301 // Wine Class tests:
302 /* Edit controls are special - they return a wndproc handle when
303 GetWindowLongPtr is called with a different A/W.
304 On the other hand there is no W->A->W conversion so this control
305 is treated specially.
306 */
307 if (Class->fnid == FNID_EDIT)
308 Ret = pWnd->lpfnWndProc;
309 else
310 {
311 // Set return proc.
312 Ret = pWnd->lpfnWndProc;
313
314 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
315 {
316 if (Ansi)
317 {
318 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
319 Ret = GETPFNCLIENTA(Class->fnid);
320 }
321 else
322 {
323 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
324 Ret = GETPFNCLIENTW(Class->fnid);
325 }
326 }
327 // Return on the change.
328 if ( Ret != pWnd->lpfnWndProc)
329 return Ret;
330 }
331
332 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
333 return Ret;
334
335 gcpd = (WNDPROC)NtUserGetCPD( UserHMGetHandle(pWnd),
336 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
337 (ULONG_PTR)Ret);
338
339 return (gcpd ? gcpd : Ret);
340 }
341
342 static ULONG_PTR FASTCALL
343 IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex)
344 {
345 ULONG_PTR Ret = 0;
346
347 if (nIndex >= 0)
348 {
349 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
350 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
351 {
352 SetLastError(ERROR_INVALID_PARAMETER);
353 }
354 else
355 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
356 }
357 else
358 {
359 switch (nIndex)
360 {
361 case GCL_CBWNDEXTRA:
362 Ret = (ULONG_PTR)Class->cbwndExtra;
363 break;
364
365 case GCL_CBCLSEXTRA:
366 Ret = (ULONG_PTR)Class->cbclsExtra;
367 break;
368
369 case GCL_HBRBACKGROUND:
370 Ret = (ULONG_PTR)Class->hbrBackground;
371 if (Ret != 0 && Ret < 0x4000)
372 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
373 break;
374
375 case GCL_HMODULE:
376 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
377 Ret = (ULONG_PTR)Class->hModule;
378 break;
379
380 case GCL_MENUNAME:
381 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
382 break;
383
384 case GCL_STYLE:
385 Ret = (ULONG_PTR)Class->style;
386 break;
387
388 case GCW_ATOM:
389 Ret = (ULONG_PTR)Class->atomClassName;
390 break;
391
392 case GCLP_HCURSOR:
393 /* FIXME - get handle from pointer to CURSOR object */
394 Ret = (ULONG_PTR)Class->hCursor;
395 break;
396
397 case GCLP_HICON:
398 /* FIXME - get handle from pointer to ICON object */
399 Ret = (ULONG_PTR)Class->hIcon;
400 break;
401
402 case GCLP_HICONSM:
403 /* FIXME - get handle from pointer to ICON object */
404 Ret = (ULONG_PTR)Class->hIconSm;
405 break;
406
407 case GCLP_WNDPROC:
408 Ret = IntGetClsWndProc(Wnd, Class, TRUE);
409 break;
410
411 default:
412 SetLastError(ERROR_INVALID_INDEX);
413 break;
414 }
415 }
416
417 return Ret;
418 }
419
420 static ULONG_PTR FASTCALL
421 IntGetClassLongW (PWND Wnd, PCLS Class, int nIndex)
422 {
423 ULONG_PTR Ret = 0;
424
425 if (nIndex >= 0)
426 {
427 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
428 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
429 {
430 SetLastError(ERROR_INVALID_PARAMETER);
431 }
432 else
433 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
434 }
435 else
436 {
437 switch (nIndex)
438 {
439 case GCL_CBWNDEXTRA:
440 Ret = (ULONG_PTR)Class->cbwndExtra;
441 break;
442
443 case GCL_CBCLSEXTRA:
444 Ret = (ULONG_PTR)Class->cbclsExtra;
445 break;
446
447 case GCLP_HBRBACKGROUND:
448 Ret = (ULONG_PTR)Class->hbrBackground;
449 if (Ret != 0 && Ret < 0x4000)
450 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
451 break;
452
453 case GCL_HMODULE:
454 Ret = (ULONG_PTR)Class->hModule;
455 break;
456
457 case GCLP_MENUNAME:
458 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
459 break;
460
461 case GCL_STYLE:
462 Ret = (ULONG_PTR)Class->style;
463 break;
464
465 case GCW_ATOM:
466 Ret = (ULONG_PTR)Class->atomClassName;
467 break;
468
469 case GCLP_HCURSOR:
470 /* FIXME - get handle from pointer to CURSOR object */
471 Ret = (ULONG_PTR)Class->hCursor;
472 break;
473
474 case GCLP_HICON:
475 /* FIXME - get handle from pointer to ICON object */
476 Ret = (ULONG_PTR)Class->hIcon;
477 break;
478
479 case GCLP_HICONSM:
480 /* FIXME - get handle from pointer to ICON object */
481 Ret = (ULONG_PTR)Class->hIconSm;
482 break;
483
484 case GCLP_WNDPROC:
485 Ret = IntGetClsWndProc(Wnd, Class, FALSE);
486 break;
487
488 default:
489 SetLastError(ERROR_INVALID_INDEX);
490 break;
491 }
492 }
493
494 return Ret;
495 }
496
497 /*
498 * @implemented
499 */
500 DWORD WINAPI
501 GetClassLongA(HWND hWnd, int nIndex)
502 {
503 PWND Wnd;
504 PCLS Class;
505 ULONG_PTR Ret = 0;
506
507 TRACE("%p %d\n", hWnd, nIndex);
508
509 Wnd = ValidateHwnd(hWnd);
510 if (!Wnd)
511 return 0;
512
513 _SEH2_TRY
514 {
515 Class = DesktopPtrToUser(Wnd->pcls);
516 if (Class != NULL)
517 {
518 #ifdef _WIN64
519 switch (nIndex)
520 {
521 case GCLP_HBRBACKGROUND:
522 case GCLP_HCURSOR:
523 case GCLP_HICON:
524 case GCLP_HICONSM:
525 case GCLP_HMODULE:
526 case GCLP_MENUNAME:
527 case GCLP_WNDPROC:
528 SetLastError(ERROR_INVALID_INDEX);
529 break;
530
531 default:
532 Ret = IntGetClassLongA(Wnd, Class, nIndex);
533 break;
534 }
535 #else
536 Ret = IntGetClassLongA(Wnd, Class, nIndex);
537 #endif
538 }
539 else
540 {
541 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
542 }
543 }
544 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
545 {
546 Ret = 0;
547 }
548 _SEH2_END;
549
550 return (DWORD)Ret;
551 }
552
553 /*
554 * @implemented
555 */
556 DWORD WINAPI
557 GetClassLongW ( HWND hWnd, int nIndex )
558 {
559 PWND Wnd;
560 PCLS Class;
561 ULONG_PTR Ret = 0;
562
563 TRACE("%p %d\n", hWnd, nIndex);
564
565 Wnd = ValidateHwnd(hWnd);
566 if (!Wnd)
567 return 0;
568
569 _SEH2_TRY
570 {
571 Class = DesktopPtrToUser(Wnd->pcls);
572 if (Class != NULL)
573 {
574 #ifdef _WIN64
575 switch (nIndex)
576 {
577 case GCLP_HBRBACKGROUND:
578 case GCLP_HCURSOR:
579 case GCLP_HICON:
580 case GCLP_HICONSM:
581 case GCLP_HMODULE:
582 case GCLP_MENUNAME:
583 case GCLP_WNDPROC:
584 SetLastError(ERROR_INVALID_INDEX);
585 break;
586
587 default:
588 Ret = IntGetClassLongW(Wnd, Class, nIndex);
589 break;
590 }
591 #else
592 Ret = IntGetClassLongW(Wnd, Class, nIndex);
593 #endif
594 }
595 else
596 {
597 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
598 }
599 }
600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
601 {
602 Ret = 0;
603 }
604 _SEH2_END;
605
606 return (DWORD)Ret;
607 }
608
609 #ifdef _WIN64
610 /*
611 * @implemented
612 */
613 ULONG_PTR
614 WINAPI
615 GetClassLongPtrA(HWND hWnd,
616 INT nIndex)
617 {
618 PWND Wnd;
619 PCLS Class;
620 ULONG_PTR Ret = 0;
621
622 TRACE("%p %d\n", hWnd, nIndex);
623
624 Wnd = ValidateHwnd(hWnd);
625 if (!Wnd)
626 return 0;
627
628 _SEH2_TRY
629 {
630 Class = DesktopPtrToUser(Wnd->pcls);
631 if (Class != NULL)
632 {
633 Ret = IntGetClassLongA(Wnd, Class, nIndex);
634 }
635 else
636 {
637 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
638 }
639 }
640 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
641 {
642 Ret = 0;
643 }
644 _SEH2_END;
645
646 return Ret;
647 }
648
649 /*
650 * @implemented
651 */
652 ULONG_PTR
653 WINAPI
654 GetClassLongPtrW(HWND hWnd,
655 INT nIndex)
656 {
657 PWND Wnd;
658 PCLS Class;
659 ULONG_PTR Ret = 0;
660
661 TRACE("%p %d\n", hWnd, nIndex);
662
663 Wnd = ValidateHwnd(hWnd);
664 if (!Wnd)
665 return 0;
666
667 _SEH2_TRY
668 {
669 Class = DesktopPtrToUser(Wnd->pcls);
670 if (Class != NULL)
671 {
672 Ret = IntGetClassLongW(Wnd, Class, nIndex);
673 }
674 else
675 {
676 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
677 }
678 }
679 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
680 {
681 Ret = 0;
682 }
683 _SEH2_END;
684
685 return Ret;
686 }
687 #endif
688
689
690 /*
691 * @implemented
692 */
693 int WINAPI
694 GetClassNameA(
695 HWND hWnd,
696 LPSTR lpClassName,
697 int nMaxCount)
698 {
699 ANSI_STRING ClassName;
700 int Result;
701
702 ClassName.MaximumLength = nMaxCount;
703 ClassName.Buffer = lpClassName;
704
705 Result = NtUserGetClassName(hWnd,
706 (PUNICODE_STRING)&ClassName,
707 TRUE);
708
709 TRACE("%p class/atom: %s/%04x %x\n", hWnd,
710 IS_ATOM(lpClassName) ? NULL : lpClassName,
711 IS_ATOM(lpClassName) ? lpClassName : 0,
712 nMaxCount);
713
714 return Result;
715 }
716
717
718 /*
719 * @implemented
720 */
721 int
722 WINAPI
723 GetClassNameW(
724 HWND hWnd,
725 LPWSTR lpClassName,
726 int nMaxCount)
727 {
728 UNICODE_STRING ClassName;
729 int Result;
730
731 ClassName.MaximumLength = nMaxCount * sizeof(WCHAR);
732 ClassName.Buffer = lpClassName;
733
734 Result = NtUserGetClassName(hWnd,
735 &ClassName,
736 FALSE);
737
738 TRACE("%p class/atom: %S/%04x %x\n", hWnd,
739 IS_ATOM(lpClassName) ? NULL : lpClassName,
740 IS_ATOM(lpClassName) ? lpClassName : 0,
741 nMaxCount);
742
743 return Result;
744 }
745
746
747 /*
748 * @implemented
749 */
750 WORD
751 WINAPI
752 GetClassWord(
753 HWND hwnd,
754 int offset)
755 {
756 PWND Wnd;
757 PCLS class;
758 WORD retvalue = 0;
759
760 if (offset < 0) return GetClassLongA( hwnd, offset );
761
762 Wnd = ValidateHwnd(hwnd);
763 if (!Wnd)
764 return 0;
765
766 class = DesktopPtrToUser(Wnd->pcls);
767 if (class == NULL) return 0;
768
769 if (offset <= class->cbclsExtra - sizeof(WORD))
770 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
771 else
772 SetLastError( ERROR_INVALID_INDEX );
773
774 return retvalue;
775 }
776
777
778 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
779 {
780 LONG_PTR retvalue = 0;
781 WND *wndPtr;
782
783 if (offset == GWLP_HWNDPARENT)
784 {
785 HWND parent = GetAncestor( hwnd, GA_PARENT );
786 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
787 return (ULONG_PTR)parent;
788 }
789
790 if (!(wndPtr = ValidateHwnd( hwnd )))
791 {
792 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
793 return 0;
794 }
795
796 if (offset >= 0)
797 {
798 if (offset > (int)(wndPtr->cbwndExtra - size))
799 {
800 WARN("Invalid offset %d\n", offset );
801 SetLastError( ERROR_INVALID_INDEX );
802 return 0;
803 }
804 retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
805
806 /* WINE: special case for dialog window procedure */
807 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
808 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
809 return retvalue;
810 }
811
812 switch(offset)
813 {
814 case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
815 case GWL_STYLE: retvalue = wndPtr->style; break;
816 case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
817 case GWLP_ID: retvalue = wndPtr->IDMenu; break;
818 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
819 case GWLP_WNDPROC:
820 {
821 if (!TestWindowProcess(wndPtr))
822 {
823 SetLastError(ERROR_ACCESS_DENIED);
824 retvalue = 0;
825 }
826 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
827 break;
828 }
829 default:
830 WARN("Unknown offset %d\n", offset );
831 SetLastError( ERROR_INVALID_INDEX );
832 break;
833 }
834 return retvalue;
835
836 }
837 /*
838 * @implemented
839 */
840 LONG
841 WINAPI
842 GetWindowLongA ( HWND hWnd, int nIndex )
843 {
844 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
845 }
846
847 /*
848 * @implemented
849 */
850 LONG
851 WINAPI
852 GetWindowLongW(HWND hWnd, int nIndex)
853 {
854 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
855 }
856
857 #ifdef _WIN64
858 /*
859 * @implemented
860 */
861 LONG_PTR
862 WINAPI
863 GetWindowLongPtrA(HWND hWnd,
864 INT nIndex)
865 {
866 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
867 }
868
869 /*
870 * @implemented
871 */
872 LONG_PTR
873 WINAPI
874 GetWindowLongPtrW(HWND hWnd,
875 INT nIndex)
876 {
877 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
878
879 }
880 #endif // _WIN64
881
882 /*
883 * @implemented
884 */
885 WORD
886 WINAPI
887 GetWindowWord(HWND hWnd, int nIndex)
888 {
889 switch(nIndex)
890 {
891 case GWLP_ID:
892 case GWLP_HINSTANCE:
893 case GWLP_HWNDPARENT:
894 break;
895 default:
896 if (nIndex < 0)
897 {
898 WARN("Invalid offset %d\n", nIndex );
899 SetLastError( ERROR_INVALID_INDEX );
900 return 0;
901 }
902 break;
903 }
904 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
905 }
906
907 /*
908 * @implemented
909 */
910 UINT
911 WINAPI
912 RealGetWindowClassW(
913 HWND hwnd,
914 LPWSTR pszType,
915 UINT cchType)
916 {
917 /* FIXME: Implement correct functionality of RealGetWindowClass */
918 return GetClassNameW(hwnd,pszType,cchType);
919 }
920
921
922 /*
923 * @implemented
924 */
925 UINT
926 WINAPI
927 RealGetWindowClassA(
928 HWND hwnd,
929 LPSTR pszType,
930 UINT cchType)
931 {
932 /* FIXME: Implement correct functionality of RealGetWindowClass */
933 return GetClassNameA(hwnd,pszType,cchType);
934 }
935
936 /*
937 * Create a small icon based on a standard icon
938 */
939 static HICON
940 CreateSmallIcon(HICON StdIcon)
941 {
942 HICON SmallIcon = NULL;
943 ICONINFO StdInfo;
944 int SmallIconWidth;
945 int SmallIconHeight;
946 BITMAP StdBitmapInfo;
947 HDC hSourceDc = NULL;
948 HDC hDestDc = NULL;
949 ICONINFO SmallInfo;
950 HBITMAP OldSourceBitmap = NULL;
951 HBITMAP OldDestBitmap = NULL;
952
953 SmallInfo.hbmColor = NULL;
954 SmallInfo.hbmMask = NULL;
955
956 /* We need something to work with... */
957 if (NULL == StdIcon)
958 {
959 goto cleanup;
960 }
961
962 SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
963 SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
964 if (! GetIconInfo(StdIcon, &StdInfo))
965 {
966 ERR("Failed to get icon info for icon 0x%x\n", StdIcon);
967 goto cleanup;
968 }
969 if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
970 {
971 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
972 StdIcon, StdInfo.hbmColor);
973 goto cleanup;
974 }
975 if (StdBitmapInfo.bmWidth == SmallIconWidth &&
976 StdBitmapInfo.bmHeight == SmallIconHeight)
977 {
978 /* Icon already has the correct dimensions */
979 return StdIcon;
980 }
981
982 hSourceDc = CreateCompatibleDC(NULL);
983 if (NULL == hSourceDc)
984 {
985 ERR("Failed to create source DC\n");
986 goto cleanup;
987 }
988 hDestDc = CreateCompatibleDC(NULL);
989 if (NULL == hDestDc)
990 {
991 ERR("Failed to create dest DC\n");
992 goto cleanup;
993 }
994
995 OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
996 if (NULL == OldSourceBitmap)
997 {
998 ERR("Failed to select source color bitmap\n");
999 goto cleanup;
1000 }
1001 SmallInfo.hbmColor = CreateCompatibleBitmap(hSourceDc, SmallIconWidth,
1002 SmallIconHeight);
1003 if (NULL == SmallInfo.hbmColor)
1004 {
1005 ERR("Failed to create color bitmap\n");
1006 goto cleanup;
1007 }
1008 OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
1009 if (NULL == OldDestBitmap)
1010 {
1011 ERR("Failed to select dest color bitmap\n");
1012 goto cleanup;
1013 }
1014 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1015 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1016 StdBitmapInfo.bmHeight, SRCCOPY))
1017 {
1018 ERR("Failed to stretch color bitmap\n");
1019 goto cleanup;
1020 }
1021
1022 if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
1023 {
1024 ERR("Failed to select source mask bitmap\n");
1025 goto cleanup;
1026 }
1027 SmallInfo.hbmMask = CreateCompatibleBitmap(hSourceDc, SmallIconWidth, SmallIconHeight);
1028 if (NULL == SmallInfo.hbmMask)
1029 {
1030 ERR("Failed to create mask bitmap\n");
1031 goto cleanup;
1032 }
1033 if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
1034 {
1035 ERR("Failed to select dest mask bitmap\n");
1036 goto cleanup;
1037 }
1038 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1039 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1040 StdBitmapInfo.bmHeight, SRCCOPY))
1041 {
1042 ERR("Failed to stretch mask bitmap\n");
1043 goto cleanup;
1044 }
1045
1046 SmallInfo.fIcon = TRUE;
1047 SmallInfo.xHotspot = SmallIconWidth / 2;
1048 SmallInfo.yHotspot = SmallIconHeight / 2;
1049 SmallIcon = CreateIconIndirect(&SmallInfo);
1050 if (NULL == SmallIcon)
1051 {
1052 ERR("Failed to create icon\n");
1053 goto cleanup;
1054 }
1055
1056 cleanup:
1057 if (NULL != SmallInfo.hbmMask)
1058 {
1059 DeleteObject(SmallInfo.hbmMask);
1060 }
1061 if (NULL != OldDestBitmap)
1062 {
1063 SelectObject(hDestDc, OldDestBitmap);
1064 }
1065 if (NULL != SmallInfo.hbmColor)
1066 {
1067 DeleteObject(SmallInfo.hbmColor);
1068 }
1069 if (NULL != hDestDc)
1070 {
1071 DeleteDC(hDestDc);
1072 }
1073 if (NULL != OldSourceBitmap)
1074 {
1075 SelectObject(hSourceDc, OldSourceBitmap);
1076 }
1077 if (NULL != hSourceDc)
1078 {
1079 DeleteDC(hSourceDc);
1080 }
1081
1082 return SmallIcon;
1083 }
1084
1085
1086 ATOM WINAPI
1087 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
1088 LPDWORD pdwWowData,
1089 WORD fnID,
1090 DWORD dwFlags,
1091 BOOL ChkRegCls)
1092 {
1093 ATOM Atom;
1094 WNDCLASSEXW WndClass;
1095 UNICODE_STRING ClassName;
1096 UNICODE_STRING MenuName = {0};
1097 CLSMENUNAME clsMenuName;
1098 ANSI_STRING AnsiMenuName;
1099
1100 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
1101 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
1102 lpwcx->lpszClassName == NULL)
1103 {
1104 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1105 SetLastError(ERROR_INVALID_PARAMETER);
1106 return 0;
1107 }
1108
1109 if (ChkRegCls)
1110 {
1111 if (!RegisterDefaultClasses) RegisterSystemControls();
1112 }
1113 /*
1114 * On real Windows this looks more like:
1115 * if (lpwcx->hInstance == User32Instance &&
1116 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1117 * But since I have no idea what the magic field in the
1118 * TEB structure means, I rather decided to omit that.
1119 * -- Filip Navara
1120
1121 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1122 */
1123 if (lpwcx->hInstance == User32Instance)
1124 {
1125 TRACE("RegisterClassExWOWW User32Instance!\n");
1126 SetLastError(ERROR_INVALID_PARAMETER);
1127 return 0;
1128 }
1129 /* Yes, this is correct. We should modify the passed structure. */
1130 if (lpwcx->hInstance == NULL)
1131 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1132
1133 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
1134
1135 if (NULL == WndClass.hIconSm)
1136 {
1137 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1138 }
1139
1140 if (WndClass.lpszMenuName != NULL)
1141 {
1142 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1143 {
1144 if (WndClass.lpszMenuName[0])
1145 {
1146 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1147 RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE);
1148 }
1149 }
1150 else
1151 {
1152 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1153 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1154 }
1155 }
1156
1157 if (IS_ATOM(WndClass.lpszClassName))
1158 {
1159 ClassName.Length =
1160 ClassName.MaximumLength = 0;
1161 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1162 }
1163 else
1164 {
1165 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1166 }
1167
1168 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1169 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1170 clsMenuName.pusMenuName = &MenuName;
1171
1172 Atom = NtUserRegisterClassExWOW( &WndClass,
1173 &ClassName,
1174 NULL, //PUNICODE_STRING ClsNVersion,
1175 &clsMenuName,
1176 fnID,
1177 dwFlags,
1178 pdwWowData);
1179
1180 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1181 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1182 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1183
1184 return Atom;
1185 }
1186
1187 /*
1188 * @implemented
1189 */
1190 ATOM WINAPI
1191 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1192 {
1193 RTL_ATOM Atom;
1194 WNDCLASSEXW WndClass;
1195 WCHAR mname[MAX_BUFFER_LEN];
1196 WCHAR cname[MAX_BUFFER_LEN];
1197
1198 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
1199
1200 if (WndClass.lpszMenuName != NULL)
1201 {
1202 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1203 {
1204 if (WndClass.lpszMenuName[0])
1205 {
1206 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0;
1207
1208 WndClass.lpszMenuName = mname;
1209 }
1210 }
1211 }
1212
1213 if (!IS_ATOM(WndClass.lpszClassName))
1214 {
1215 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0;
1216
1217 WndClass.lpszClassName = cname;
1218 }
1219
1220 Atom = RegisterClassExWOWW( &WndClass,
1221 0,
1222 0,
1223 CSF_ANSIPROC,
1224 TRUE);
1225
1226 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1227 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1228 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1229
1230 return (ATOM)Atom;
1231 }
1232
1233 /*
1234 * @implemented
1235 */
1236 ATOM WINAPI
1237 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1238 {
1239 ATOM Atom;
1240
1241 Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE);
1242
1243 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1244 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1245 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1246
1247 return Atom;
1248 }
1249
1250 /*
1251 * @implemented
1252 */
1253 ATOM WINAPI
1254 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1255 {
1256 WNDCLASSEXA Class;
1257
1258 if (lpWndClass == NULL)
1259 return 0;
1260
1261 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
1262 Class.cbSize = sizeof(WNDCLASSEXA);
1263 Class.hIconSm = NULL;
1264
1265 return RegisterClassExA(&Class);
1266 }
1267
1268 /*
1269 * @implemented
1270 */
1271 ATOM WINAPI
1272 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1273 {
1274 WNDCLASSEXW Class;
1275
1276 if (lpWndClass == NULL)
1277 return 0;
1278
1279 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
1280 Class.cbSize = sizeof(WNDCLASSEXW);
1281 Class.hIconSm = NULL;
1282
1283 return RegisterClassExW(&Class);
1284 }
1285
1286 /*
1287 * @implemented
1288 */
1289 DWORD
1290 WINAPI
1291 SetClassLongA (HWND hWnd,
1292 int nIndex,
1293 LONG dwNewLong)
1294 {
1295 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1296 UNICODE_STRING Value = {0};
1297 BOOL Allocated = FALSE;
1298 DWORD Ret;
1299
1300 /* FIXME - portability!!!! */
1301
1302 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1303 {
1304 if (!IS_INTRESOURCE(lpStr))
1305 {
1306 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1307 lpStr))
1308 {
1309 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1310 return 0;
1311 }
1312
1313 Allocated = TRUE;
1314 }
1315 else
1316 Value.Buffer = (PWSTR)lpStr;
1317
1318 dwNewLong = (LONG_PTR)&Value;
1319 }
1320 else if (nIndex == GCW_ATOM && lpStr != NULL)
1321 {
1322 if (!IS_ATOM(lpStr))
1323 {
1324 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1325 lpStr))
1326 {
1327 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1328 return 0;
1329 }
1330
1331 Allocated = TRUE;
1332 }
1333 else
1334 Value.Buffer = (PWSTR)lpStr;
1335
1336 dwNewLong = (LONG_PTR)&Value;
1337 }
1338
1339 Ret = (DWORD)NtUserSetClassLong(hWnd,
1340 nIndex,
1341 dwNewLong,
1342 TRUE);
1343
1344 if (Allocated)
1345 {
1346 RtlFreeUnicodeString(&Value);
1347 }
1348
1349 return Ret;
1350 }
1351
1352
1353 /*
1354 * @implemented
1355 */
1356 DWORD
1357 WINAPI
1358 SetClassLongW(HWND hWnd,
1359 int nIndex,
1360 LONG dwNewLong)
1361 {
1362 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1363 UNICODE_STRING Value = {0};
1364
1365 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1366
1367 /* FIXME - portability!!!! */
1368
1369 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1370 {
1371 if (!IS_INTRESOURCE(lpStr))
1372 {
1373 RtlInitUnicodeString(&Value,
1374 lpStr);
1375 }
1376 else
1377 Value.Buffer = lpStr;
1378
1379 dwNewLong = (LONG_PTR)&Value;
1380 }
1381 else if (nIndex == GCW_ATOM && lpStr != NULL)
1382 {
1383 if (!IS_ATOM(lpStr))
1384 {
1385 RtlInitUnicodeString(&Value,
1386 lpStr);
1387 }
1388 else
1389 Value.Buffer = lpStr;
1390
1391 dwNewLong = (LONG_PTR)&Value;
1392 }
1393
1394 return (DWORD)NtUserSetClassLong(hWnd,
1395 nIndex,
1396 dwNewLong,
1397 FALSE);
1398 }
1399
1400 #ifdef _WIN64
1401 /*
1402 * @unimplemented
1403 */
1404 ULONG_PTR
1405 WINAPI
1406 SetClassLongPtrA(HWND hWnd,
1407 INT nIndex,
1408 LONG_PTR dwNewLong)
1409 {
1410 UNIMPLEMENTED;
1411 return 0;
1412 }
1413
1414 /*
1415 * @unimplemented
1416 */
1417 ULONG_PTR
1418 WINAPI
1419 SetClassLongPtrW(HWND hWnd,
1420 INT nIndex,
1421 LONG_PTR dwNewLong)
1422 {
1423 UNIMPLEMENTED;
1424 return 0;
1425 }
1426 #endif // _WIN64
1427
1428 /*
1429 * @implemented
1430 */
1431 WORD
1432 WINAPI
1433 SetClassWord(
1434 HWND hWnd,
1435 int nIndex,
1436 WORD wNewWord)
1437 /*
1438 * NOTE: Obsoleted in 32-bit windows
1439 */
1440 {
1441 if ((nIndex < 0) && (nIndex != GCW_ATOM))
1442 return 0;
1443
1444 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1445 }
1446
1447 /*
1448 * @implemented
1449 */
1450 WORD
1451 WINAPI
1452 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1453 {
1454 switch(nIndex)
1455 {
1456 case GWLP_ID:
1457 case GWLP_HINSTANCE:
1458 case GWLP_HWNDPARENT:
1459 break;
1460 default:
1461 if (nIndex < 0)
1462 {
1463 WARN("Invalid offset %d\n", nIndex );
1464 SetLastError( ERROR_INVALID_INDEX );
1465 return 0;
1466 }
1467 break;
1468 }
1469 return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE );
1470 }
1471
1472 /*
1473 * @implemented
1474 */
1475 LONG
1476 WINAPI
1477 SetWindowLongA(
1478 HWND hWnd,
1479 int nIndex,
1480 LONG dwNewLong)
1481 {
1482 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1483 }
1484
1485 /*
1486 * @implemented
1487 */
1488 LONG
1489 WINAPI
1490 SetWindowLongW(
1491 HWND hWnd,
1492 int nIndex,
1493 LONG dwNewLong)
1494 {
1495 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1496 }
1497
1498 #ifdef _WIN64
1499 /*
1500 * @implemented
1501 */
1502 LONG_PTR
1503 WINAPI
1504 SetWindowLongPtrA(HWND hWnd,
1505 INT nIndex,
1506 LONG_PTR dwNewLong)
1507 {
1508 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1509 }
1510
1511 /*
1512 * @implemented
1513 */
1514 LONG_PTR
1515 WINAPI
1516 SetWindowLongPtrW(HWND hWnd,
1517 INT nIndex,
1518 LONG_PTR dwNewLong)
1519 {
1520 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1521 }
1522 #endif
1523
1524 /*
1525 * @implemented
1526 */
1527 BOOL
1528 WINAPI
1529 UnregisterClassA(
1530 LPCSTR lpClassName,
1531 HINSTANCE hInstance)
1532 {
1533 UNICODE_STRING ClassName = {0};
1534 BOOL Ret;
1535
1536 TRACE("class/atom: %s/%04x %p\n",
1537 IS_ATOM(lpClassName) ? NULL : lpClassName,
1538 IS_ATOM(lpClassName) ? lpClassName : 0,
1539 hInstance);
1540
1541 if (!IS_ATOM(lpClassName))
1542 {
1543 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
1544 lpClassName))
1545 {
1546 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1547 return 0;
1548 }
1549 }
1550 else
1551 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1552
1553 Ret = NtUserUnregisterClass(&ClassName,
1554 hInstance,
1555 0);
1556
1557 if (!IS_ATOM(lpClassName))
1558 RtlFreeUnicodeString(&ClassName);
1559
1560 return Ret;
1561 }
1562
1563
1564 /*
1565 * @implemented
1566 */
1567 BOOL
1568 WINAPI
1569 UnregisterClassW(
1570 LPCWSTR lpClassName,
1571 HINSTANCE hInstance)
1572 {
1573 UNICODE_STRING ClassName = {0};
1574
1575 TRACE("class/atom: %S/%04x %p\n",
1576 IS_ATOM(lpClassName) ? NULL : lpClassName,
1577 IS_ATOM(lpClassName) ? lpClassName : 0,
1578 hInstance);
1579
1580 if (!IS_ATOM(lpClassName))
1581 {
1582 RtlInitUnicodeString(&ClassName,
1583 lpClassName);
1584 }
1585 else
1586 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1587
1588 return NtUserUnregisterClass(&ClassName,
1589 hInstance,
1590 0);
1591 }
1592
1593 /* EOF */