0d9ae490b693402287e1730e9190214a8da0cfab
[reactos.git] / reactos / win32ss / user / 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 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
700 int len;
701
702 if (nMaxCount <= 0) return 0;
703 if (!GetClassNameW( hWnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
704 RtlUnicodeToMultiByteN( lpClassName, nMaxCount - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
705 lpClassName[len] = 0;
706
707 TRACE("%p class/atom: %s/%04x %x\n", hWnd,
708 IS_ATOM(lpClassName) ? NULL : lpClassName,
709 IS_ATOM(lpClassName) ? lpClassName : 0,
710 nMaxCount);
711
712 return len;
713 }
714
715
716 /*
717 * @implemented
718 */
719 int
720 WINAPI
721 GetClassNameW(
722 HWND hWnd,
723 LPWSTR lpClassName,
724 int nMaxCount)
725 {
726 UNICODE_STRING ClassName;
727 int Result;
728
729 ClassName.MaximumLength = nMaxCount * sizeof(WCHAR);
730 ClassName.Buffer = lpClassName;
731
732 Result = NtUserGetClassName(hWnd,
733 FALSE,
734 &ClassName);
735
736 TRACE("%p class/atom: %S/%04x %x\n", hWnd,
737 IS_ATOM(lpClassName) ? NULL : lpClassName,
738 IS_ATOM(lpClassName) ? lpClassName : 0,
739 nMaxCount);
740
741 return Result;
742 }
743
744
745 /*
746 * @implemented
747 */
748 WORD
749 WINAPI
750 GetClassWord(
751 HWND hwnd,
752 int offset)
753 {
754 PWND Wnd;
755 PCLS class;
756 WORD retvalue = 0;
757
758 if (offset < 0) return GetClassLongA( hwnd, offset );
759
760 Wnd = ValidateHwnd(hwnd);
761 if (!Wnd)
762 return 0;
763
764 class = DesktopPtrToUser(Wnd->pcls);
765 if (class == NULL) return 0;
766
767 if (offset <= class->cbclsExtra - sizeof(WORD))
768 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
769 else
770 SetLastError( ERROR_INVALID_INDEX );
771
772 return retvalue;
773 }
774
775
776 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
777 {
778 LONG_PTR retvalue = 0;
779 WND *wndPtr;
780
781 if (offset == GWLP_HWNDPARENT)
782 {
783 HWND parent = GetAncestor( hwnd, GA_PARENT );
784 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
785 return (ULONG_PTR)parent;
786 }
787
788 if (!(wndPtr = ValidateHwnd( hwnd )))
789 {
790 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
791 return 0;
792 }
793
794 if (offset >= 0)
795 {
796 if (offset > (int)(wndPtr->cbwndExtra - size))
797 {
798 WARN("Invalid offset %d\n", offset );
799 SetLastError( ERROR_INVALID_INDEX );
800 return 0;
801 }
802 retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
803
804 /* WINE: special case for dialog window procedure */
805 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
806 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
807 return retvalue;
808 }
809
810 switch(offset)
811 {
812 case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
813 case GWL_STYLE: retvalue = wndPtr->style; break;
814 case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
815 case GWLP_ID: retvalue = wndPtr->IDMenu; break;
816 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
817 case GWLP_WNDPROC:
818 {
819 if (!TestWindowProcess(wndPtr))
820 {
821 SetLastError(ERROR_ACCESS_DENIED);
822 retvalue = 0;
823 }
824 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
825 break;
826 }
827 default:
828 WARN("Unknown offset %d\n", offset );
829 SetLastError( ERROR_INVALID_INDEX );
830 break;
831 }
832 return retvalue;
833
834 }
835 /*
836 * @implemented
837 */
838 LONG
839 WINAPI
840 GetWindowLongA ( HWND hWnd, int nIndex )
841 {
842 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
843 }
844
845 /*
846 * @implemented
847 */
848 LONG
849 WINAPI
850 GetWindowLongW(HWND hWnd, int nIndex)
851 {
852 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
853 }
854
855 #ifdef _WIN64
856 /*
857 * @implemented
858 */
859 LONG_PTR
860 WINAPI
861 GetWindowLongPtrA(HWND hWnd,
862 INT nIndex)
863 {
864 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
865 }
866
867 /*
868 * @implemented
869 */
870 LONG_PTR
871 WINAPI
872 GetWindowLongPtrW(HWND hWnd,
873 INT nIndex)
874 {
875 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
876
877 }
878 #endif // _WIN64
879
880 /*
881 * @implemented
882 */
883 WORD
884 WINAPI
885 GetWindowWord(HWND hWnd, int nIndex)
886 {
887 switch(nIndex)
888 {
889 case GWLP_ID:
890 case GWLP_HINSTANCE:
891 case GWLP_HWNDPARENT:
892 break;
893 default:
894 if (nIndex < 0)
895 {
896 WARN("Invalid offset %d\n", nIndex );
897 SetLastError( ERROR_INVALID_INDEX );
898 return 0;
899 }
900 break;
901 }
902 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
903 }
904
905 /*
906 * @implemented
907 */
908 UINT
909 WINAPI
910 RealGetWindowClassW(
911 HWND hwnd,
912 LPWSTR pszType,
913 UINT cchType)
914 {
915 UNICODE_STRING ClassName;
916 ClassName.MaximumLength = cchType * sizeof(WCHAR);
917 ClassName.Buffer = (PWSTR)pszType;
918
919 return NtUserGetClassName(hwnd,TRUE,&ClassName);
920 }
921
922
923 /*
924 * @implemented
925 */
926 UINT
927 WINAPI
928 RealGetWindowClassA(
929 HWND hwnd,
930 LPSTR pszType,
931 UINT cchType)
932 {
933 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
934 UINT len;
935
936 if ((INT)cchType <= 0) return 0;
937 if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
938 RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
939 pszType[len] = 0;
940 return len;
941 }
942
943 /*
944 * Create a small icon based on a standard icon
945 */
946 static HICON
947 CreateSmallIcon(HICON StdIcon)
948 {
949 HICON SmallIcon = NULL;
950 ICONINFO StdInfo;
951 int SmallIconWidth;
952 int SmallIconHeight;
953 BITMAP StdBitmapInfo;
954 HDC hSourceDc = NULL;
955 HDC hDestDc = NULL;
956 ICONINFO SmallInfo;
957 HBITMAP OldSourceBitmap = NULL;
958 HBITMAP OldDestBitmap = NULL;
959
960 SmallInfo.hbmColor = NULL;
961 SmallInfo.hbmMask = NULL;
962
963 /* We need something to work with... */
964 if (NULL == StdIcon)
965 {
966 goto cleanup;
967 }
968
969 SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
970 SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
971 if (! GetIconInfo(StdIcon, &StdInfo))
972 {
973 ERR("Failed to get icon info for icon 0x%x\n", StdIcon);
974 goto cleanup;
975 }
976 if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
977 {
978 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
979 StdIcon, StdInfo.hbmColor);
980 goto cleanup;
981 }
982 if (StdBitmapInfo.bmWidth == SmallIconWidth &&
983 StdBitmapInfo.bmHeight == SmallIconHeight)
984 {
985 /* Icon already has the correct dimensions */
986 return StdIcon;
987 }
988
989 hSourceDc = CreateCompatibleDC(NULL);
990 if (NULL == hSourceDc)
991 {
992 ERR("Failed to create source DC\n");
993 goto cleanup;
994 }
995 hDestDc = CreateCompatibleDC(NULL);
996 if (NULL == hDestDc)
997 {
998 ERR("Failed to create dest DC\n");
999 goto cleanup;
1000 }
1001
1002 OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
1003 if (NULL == OldSourceBitmap)
1004 {
1005 ERR("Failed to select source color bitmap\n");
1006 goto cleanup;
1007 }
1008 SmallInfo.hbmColor = CreateCompatibleBitmap(hSourceDc, SmallIconWidth,
1009 SmallIconHeight);
1010 if (NULL == SmallInfo.hbmColor)
1011 {
1012 ERR("Failed to create color bitmap\n");
1013 goto cleanup;
1014 }
1015 OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
1016 if (NULL == OldDestBitmap)
1017 {
1018 ERR("Failed to select dest color bitmap\n");
1019 goto cleanup;
1020 }
1021 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1022 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1023 StdBitmapInfo.bmHeight, SRCCOPY))
1024 {
1025 ERR("Failed to stretch color bitmap\n");
1026 goto cleanup;
1027 }
1028
1029 if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
1030 {
1031 ERR("Failed to select source mask bitmap\n");
1032 goto cleanup;
1033 }
1034 SmallInfo.hbmMask = CreateCompatibleBitmap(hSourceDc, SmallIconWidth, SmallIconHeight);
1035 if (NULL == SmallInfo.hbmMask)
1036 {
1037 ERR("Failed to create mask bitmap\n");
1038 goto cleanup;
1039 }
1040 if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
1041 {
1042 ERR("Failed to select dest mask bitmap\n");
1043 goto cleanup;
1044 }
1045 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1046 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1047 StdBitmapInfo.bmHeight, SRCCOPY))
1048 {
1049 ERR("Failed to stretch mask bitmap\n");
1050 goto cleanup;
1051 }
1052
1053 SmallInfo.fIcon = TRUE;
1054 SmallInfo.xHotspot = SmallIconWidth / 2;
1055 SmallInfo.yHotspot = SmallIconHeight / 2;
1056 SmallIcon = CreateIconIndirect(&SmallInfo);
1057 if (NULL == SmallIcon)
1058 {
1059 ERR("Failed to create icon\n");
1060 goto cleanup;
1061 }
1062
1063 cleanup:
1064 if (NULL != SmallInfo.hbmMask)
1065 {
1066 DeleteObject(SmallInfo.hbmMask);
1067 }
1068 if (NULL != OldDestBitmap)
1069 {
1070 SelectObject(hDestDc, OldDestBitmap);
1071 }
1072 if (NULL != SmallInfo.hbmColor)
1073 {
1074 DeleteObject(SmallInfo.hbmColor);
1075 }
1076 if (NULL != hDestDc)
1077 {
1078 DeleteDC(hDestDc);
1079 }
1080 if (NULL != OldSourceBitmap)
1081 {
1082 SelectObject(hSourceDc, OldSourceBitmap);
1083 }
1084 if (NULL != hSourceDc)
1085 {
1086 DeleteDC(hSourceDc);
1087 }
1088
1089 return SmallIcon;
1090 }
1091
1092
1093 ATOM WINAPI
1094 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
1095 LPDWORD pdwWowData,
1096 WORD fnID,
1097 DWORD dwFlags,
1098 BOOL ChkRegCls)
1099 {
1100 ATOM Atom;
1101 WNDCLASSEXW WndClass;
1102 UNICODE_STRING ClassName;
1103 UNICODE_STRING MenuName = {0};
1104 CLSMENUNAME clsMenuName;
1105 ANSI_STRING AnsiMenuName;
1106
1107 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
1108 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
1109 lpwcx->lpszClassName == NULL)
1110 {
1111 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1112 SetLastError(ERROR_INVALID_PARAMETER);
1113 return 0;
1114 }
1115
1116 if (ChkRegCls)
1117 {
1118 if (!RegisterDefaultClasses) RegisterSystemControls();
1119 }
1120 /*
1121 * On real Windows this looks more like:
1122 * if (lpwcx->hInstance == User32Instance &&
1123 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1124 * But since I have no idea what the magic field in the
1125 * TEB structure means, I rather decided to omit that.
1126 * -- Filip Navara
1127
1128 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1129 */
1130 if (lpwcx->hInstance == User32Instance)
1131 {
1132 TRACE("RegisterClassExWOWW User32Instance!\n");
1133 SetLastError(ERROR_INVALID_PARAMETER);
1134 return 0;
1135 }
1136 /* Yes, this is correct. We should modify the passed structure. */
1137 if (lpwcx->hInstance == NULL)
1138 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1139
1140 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
1141
1142 if (NULL == WndClass.hIconSm)
1143 {
1144 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1145 }
1146
1147 if (WndClass.lpszMenuName != NULL)
1148 {
1149 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1150 {
1151 if (WndClass.lpszMenuName[0])
1152 {
1153 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1154 RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE);
1155 }
1156 }
1157 else
1158 {
1159 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1160 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1161 }
1162 }
1163
1164 if (IS_ATOM(WndClass.lpszClassName))
1165 {
1166 ClassName.Length =
1167 ClassName.MaximumLength = 0;
1168 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1169 }
1170 else
1171 {
1172 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1173 }
1174
1175 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1176 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1177 clsMenuName.pusMenuName = &MenuName;
1178
1179 Atom = NtUserRegisterClassExWOW( &WndClass,
1180 &ClassName,
1181 NULL, //PUNICODE_STRING ClsNVersion,
1182 &clsMenuName,
1183 fnID,
1184 dwFlags,
1185 pdwWowData);
1186
1187 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1188 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1189 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1190
1191 return Atom;
1192 }
1193
1194 /*
1195 * @implemented
1196 */
1197 ATOM WINAPI
1198 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1199 {
1200 RTL_ATOM Atom;
1201 WNDCLASSEXW WndClass;
1202 WCHAR mname[MAX_BUFFER_LEN];
1203 WCHAR cname[MAX_BUFFER_LEN];
1204
1205 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
1206
1207 if (WndClass.lpszMenuName != NULL)
1208 {
1209 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1210 {
1211 if (WndClass.lpszMenuName[0])
1212 {
1213 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0;
1214
1215 WndClass.lpszMenuName = mname;
1216 }
1217 }
1218 }
1219
1220 if (!IS_ATOM(WndClass.lpszClassName))
1221 {
1222 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0;
1223
1224 WndClass.lpszClassName = cname;
1225 }
1226
1227 Atom = RegisterClassExWOWW( &WndClass,
1228 0,
1229 0,
1230 CSF_ANSIPROC,
1231 TRUE);
1232
1233 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1234 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1235 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1236
1237 return (ATOM)Atom;
1238 }
1239
1240 /*
1241 * @implemented
1242 */
1243 ATOM WINAPI
1244 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1245 {
1246 ATOM Atom;
1247
1248 Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE);
1249
1250 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1251 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1252 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1253
1254 return Atom;
1255 }
1256
1257 /*
1258 * @implemented
1259 */
1260 ATOM WINAPI
1261 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1262 {
1263 WNDCLASSEXA Class;
1264
1265 if (lpWndClass == NULL)
1266 return 0;
1267
1268 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
1269 Class.cbSize = sizeof(WNDCLASSEXA);
1270 Class.hIconSm = NULL;
1271
1272 return RegisterClassExA(&Class);
1273 }
1274
1275 /*
1276 * @implemented
1277 */
1278 ATOM WINAPI
1279 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1280 {
1281 WNDCLASSEXW Class;
1282
1283 if (lpWndClass == NULL)
1284 return 0;
1285
1286 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
1287 Class.cbSize = sizeof(WNDCLASSEXW);
1288 Class.hIconSm = NULL;
1289
1290 return RegisterClassExW(&Class);
1291 }
1292
1293 /*
1294 * @implemented
1295 */
1296 DWORD
1297 WINAPI
1298 SetClassLongA (HWND hWnd,
1299 int nIndex,
1300 LONG dwNewLong)
1301 {
1302 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1303 UNICODE_STRING Value = {0};
1304 BOOL Allocated = FALSE;
1305 DWORD Ret;
1306
1307 /* FIXME - portability!!!! */
1308
1309 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1310 {
1311 if (!IS_INTRESOURCE(lpStr))
1312 {
1313 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1314 lpStr))
1315 {
1316 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1317 return 0;
1318 }
1319
1320 Allocated = TRUE;
1321 }
1322 else
1323 Value.Buffer = (PWSTR)lpStr;
1324
1325 dwNewLong = (LONG_PTR)&Value;
1326 }
1327 else if (nIndex == GCW_ATOM && lpStr != NULL)
1328 {
1329 if (!IS_ATOM(lpStr))
1330 {
1331 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1332 lpStr))
1333 {
1334 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1335 return 0;
1336 }
1337
1338 Allocated = TRUE;
1339 }
1340 else
1341 Value.Buffer = (PWSTR)lpStr;
1342
1343 dwNewLong = (LONG_PTR)&Value;
1344 }
1345
1346 Ret = (DWORD)NtUserSetClassLong(hWnd,
1347 nIndex,
1348 dwNewLong,
1349 TRUE);
1350
1351 if (Allocated)
1352 {
1353 RtlFreeUnicodeString(&Value);
1354 }
1355
1356 return Ret;
1357 }
1358
1359
1360 /*
1361 * @implemented
1362 */
1363 DWORD
1364 WINAPI
1365 SetClassLongW(HWND hWnd,
1366 int nIndex,
1367 LONG dwNewLong)
1368 {
1369 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1370 UNICODE_STRING Value = {0};
1371
1372 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1373
1374 /* FIXME - portability!!!! */
1375
1376 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1377 {
1378 if (!IS_INTRESOURCE(lpStr))
1379 {
1380 RtlInitUnicodeString(&Value,
1381 lpStr);
1382 }
1383 else
1384 Value.Buffer = lpStr;
1385
1386 dwNewLong = (LONG_PTR)&Value;
1387 }
1388 else if (nIndex == GCW_ATOM && lpStr != NULL)
1389 {
1390 if (!IS_ATOM(lpStr))
1391 {
1392 RtlInitUnicodeString(&Value,
1393 lpStr);
1394 }
1395 else
1396 Value.Buffer = lpStr;
1397
1398 dwNewLong = (LONG_PTR)&Value;
1399 }
1400
1401 return (DWORD)NtUserSetClassLong(hWnd,
1402 nIndex,
1403 dwNewLong,
1404 FALSE);
1405 }
1406
1407 #ifdef _WIN64
1408 /*
1409 * @unimplemented
1410 */
1411 ULONG_PTR
1412 WINAPI
1413 SetClassLongPtrA(HWND hWnd,
1414 INT nIndex,
1415 LONG_PTR dwNewLong)
1416 {
1417 UNIMPLEMENTED;
1418 return 0;
1419 }
1420
1421 /*
1422 * @unimplemented
1423 */
1424 ULONG_PTR
1425 WINAPI
1426 SetClassLongPtrW(HWND hWnd,
1427 INT nIndex,
1428 LONG_PTR dwNewLong)
1429 {
1430 UNIMPLEMENTED;
1431 return 0;
1432 }
1433 #endif // _WIN64
1434
1435 /*
1436 * @implemented
1437 */
1438 WORD
1439 WINAPI
1440 SetClassWord(
1441 HWND hWnd,
1442 int nIndex,
1443 WORD wNewWord)
1444 /*
1445 * NOTE: Obsoleted in 32-bit windows
1446 */
1447 {
1448 if ((nIndex < 0) && (nIndex != GCW_ATOM))
1449 return 0;
1450
1451 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1452 }
1453
1454 /*
1455 * @implemented
1456 */
1457 WORD
1458 WINAPI
1459 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1460 {
1461 switch(nIndex)
1462 {
1463 case GWLP_ID:
1464 case GWLP_HINSTANCE:
1465 case GWLP_HWNDPARENT:
1466 break;
1467 default:
1468 if (nIndex < 0)
1469 {
1470 WARN("Invalid offset %d\n", nIndex );
1471 SetLastError( ERROR_INVALID_INDEX );
1472 return 0;
1473 }
1474 break;
1475 }
1476 return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE );
1477 }
1478
1479 /*
1480 * @implemented
1481 */
1482 LONG
1483 WINAPI
1484 SetWindowLongA(
1485 HWND hWnd,
1486 int nIndex,
1487 LONG dwNewLong)
1488 {
1489 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1490 }
1491
1492 /*
1493 * @implemented
1494 */
1495 LONG
1496 WINAPI
1497 SetWindowLongW(
1498 HWND hWnd,
1499 int nIndex,
1500 LONG dwNewLong)
1501 {
1502 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1503 }
1504
1505 #ifdef _WIN64
1506 /*
1507 * @implemented
1508 */
1509 LONG_PTR
1510 WINAPI
1511 SetWindowLongPtrA(HWND hWnd,
1512 INT nIndex,
1513 LONG_PTR dwNewLong)
1514 {
1515 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1516 }
1517
1518 /*
1519 * @implemented
1520 */
1521 LONG_PTR
1522 WINAPI
1523 SetWindowLongPtrW(HWND hWnd,
1524 INT nIndex,
1525 LONG_PTR dwNewLong)
1526 {
1527 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1528 }
1529 #endif
1530
1531 /*
1532 * @implemented
1533 */
1534 BOOL
1535 WINAPI
1536 UnregisterClassA(
1537 LPCSTR lpClassName,
1538 HINSTANCE hInstance)
1539 {
1540 UNICODE_STRING ClassName = {0};
1541 BOOL Ret;
1542
1543 TRACE("class/atom: %s/%04x %p\n",
1544 IS_ATOM(lpClassName) ? NULL : lpClassName,
1545 IS_ATOM(lpClassName) ? lpClassName : 0,
1546 hInstance);
1547
1548 if (!IS_ATOM(lpClassName))
1549 {
1550 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
1551 lpClassName))
1552 {
1553 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1554 return 0;
1555 }
1556 }
1557 else
1558 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1559
1560 Ret = NtUserUnregisterClass(&ClassName,
1561 hInstance,
1562 0);
1563
1564 if (!IS_ATOM(lpClassName))
1565 RtlFreeUnicodeString(&ClassName);
1566
1567 return Ret;
1568 }
1569
1570
1571 /*
1572 * @implemented
1573 */
1574 BOOL
1575 WINAPI
1576 UnregisterClassW(
1577 LPCWSTR lpClassName,
1578 HINSTANCE hInstance)
1579 {
1580 UNICODE_STRING ClassName = {0};
1581
1582 TRACE("class/atom: %S/%04x %p\n",
1583 IS_ATOM(lpClassName) ? NULL : lpClassName,
1584 IS_ATOM(lpClassName) ? lpClassName : 0,
1585 hInstance);
1586
1587 if (!IS_ATOM(lpClassName))
1588 {
1589 RtlInitUnicodeString(&ClassName,
1590 lpClassName);
1591 }
1592 else
1593 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1594
1595 return NtUserUnregisterClass(&ClassName,
1596 hInstance,
1597 0);
1598 }
1599
1600 /* EOF */