[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 /*
343 * @implemented
344 */
345 DWORD WINAPI
346 GetClassLongA(HWND hWnd, int nIndex)
347 {
348 PWND Wnd;
349 PCLS Class;
350 ULONG_PTR Ret = 0;
351
352 TRACE("%p %d\n", hWnd, nIndex);
353
354 Wnd = ValidateHwnd(hWnd);
355 if (!Wnd)
356 return 0;
357
358 _SEH2_TRY
359 {
360 Class = DesktopPtrToUser(Wnd->pcls);
361 if (Class != NULL)
362 {
363 if (nIndex >= 0)
364 {
365 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
366 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
367 {
368 SetLastError(ERROR_INVALID_PARAMETER);
369 }
370 else
371 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
372 }
373 else
374 {
375 switch (nIndex)
376 {
377 case GCL_CBWNDEXTRA:
378 Ret = (ULONG_PTR)Class->cbwndExtra;
379 break;
380
381 case GCL_CBCLSEXTRA:
382 Ret = (ULONG_PTR)Class->cbclsExtra;
383 break;
384
385 case GCL_HBRBACKGROUND:
386 Ret = (ULONG_PTR)Class->hbrBackground;
387 if (Ret != 0 && Ret < 0x4000)
388 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
389 break;
390
391 case GCL_HMODULE:
392 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
393 Ret = (ULONG_PTR)Class->hModule;
394 break;
395
396 case GCL_MENUNAME:
397 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
398 break;
399
400 case GCL_STYLE:
401 Ret = (ULONG_PTR)Class->style;
402 break;
403
404 case GCW_ATOM:
405 Ret = (ULONG_PTR)Class->atomClassName;
406 break;
407
408 case GCLP_HCURSOR:
409 /* FIXME - get handle from pointer to CURSOR object */
410 Ret = (ULONG_PTR)Class->hCursor;
411 break;
412
413 case GCLP_HICON:
414 /* FIXME - get handle from pointer to ICON object */
415 Ret = (ULONG_PTR)Class->hIcon;
416 break;
417
418 case GCLP_HICONSM:
419 /* FIXME - get handle from pointer to ICON object */
420 Ret = (ULONG_PTR)Class->hIconSm;
421 break;
422
423 case GCLP_WNDPROC:
424 Ret = IntGetClsWndProc(Wnd, Class, TRUE);
425 break;
426
427 default:
428 SetLastError(ERROR_INVALID_INDEX);
429 break;
430 }
431 }
432 }
433 else
434 {
435 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
436 }
437 }
438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
439 {
440 Ret = 0;
441 }
442 _SEH2_END;
443
444 return Ret;
445 }
446
447 /*
448 * @implemented
449 */
450 DWORD WINAPI
451 GetClassLongW ( HWND hWnd, int nIndex )
452 {
453 PWND Wnd;
454 PCLS Class;
455 ULONG_PTR Ret = 0;
456
457 TRACE("%p %d\n", hWnd, nIndex);
458
459 Wnd = ValidateHwnd(hWnd);
460 if (!Wnd)
461 return 0;
462
463 _SEH2_TRY
464 {
465 Class = DesktopPtrToUser(Wnd->pcls);
466 if (Class != NULL)
467 {
468 if (nIndex >= 0)
469 {
470 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
471 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
472 {
473 SetLastError(ERROR_INVALID_PARAMETER);
474 }
475 else
476 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
477 }
478 else
479 {
480 switch (nIndex)
481 {
482 case GCL_CBWNDEXTRA:
483 Ret = (ULONG_PTR)Class->cbwndExtra;
484 break;
485
486 case GCL_CBCLSEXTRA:
487 Ret = (ULONG_PTR)Class->cbclsExtra;
488 break;
489
490 case GCL_HBRBACKGROUND:
491 Ret = (ULONG_PTR)Class->hbrBackground;
492 if (Ret != 0 && Ret < 0x4000)
493 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
494 break;
495
496 case GCL_HMODULE:
497 Ret = (ULONG_PTR)Class->hModule;
498 break;
499
500 case GCL_MENUNAME:
501 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
502 break;
503
504 case GCL_STYLE:
505 Ret = (ULONG_PTR)Class->style;
506 break;
507
508 case GCW_ATOM:
509 Ret = (ULONG_PTR)Class->atomClassName;
510 break;
511
512 case GCLP_HCURSOR:
513 /* FIXME - get handle from pointer to CURSOR object */
514 Ret = (ULONG_PTR)Class->hCursor;
515 break;
516
517 case GCLP_HICON:
518 /* FIXME - get handle from pointer to ICON object */
519 Ret = (ULONG_PTR)Class->hIcon;
520 break;
521
522 case GCLP_HICONSM:
523 /* FIXME - get handle from pointer to ICON object */
524 Ret = (ULONG_PTR)Class->hIconSm;
525 break;
526
527 case GCLP_WNDPROC:
528 Ret = IntGetClsWndProc(Wnd, Class, FALSE);
529 break;
530
531 default:
532 SetLastError(ERROR_INVALID_INDEX);
533 break;
534 }
535 }
536 }
537 else
538 {
539 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
540 }
541 }
542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
543 {
544 }
545 _SEH2_END;
546
547 return Ret;
548 }
549
550 #ifdef _WIN64
551 /*
552 * @unimplemented
553 */
554 ULONG_PTR
555 WINAPI
556 GetClassLongPtrA(HWND hWnd,
557 INT nIndex)
558 {
559 UNIMPLEMENTED;
560 return 0;
561 }
562
563 /*
564 * @unimplemented
565 */
566 ULONG_PTR
567 WINAPI
568 GetClassLongPtrW(HWND hWnd,
569 INT nIndex)
570 {
571 UNIMPLEMENTED;
572 return 0;
573 }
574 #endif
575
576
577 /*
578 * @implemented
579 */
580 int WINAPI
581 GetClassNameA(
582 HWND hWnd,
583 LPSTR lpClassName,
584 int nMaxCount)
585 {
586 ANSI_STRING ClassName;
587 int Result;
588
589 ClassName.MaximumLength = nMaxCount;
590 ClassName.Buffer = lpClassName;
591
592 Result = NtUserGetClassName(hWnd,
593 (PUNICODE_STRING)&ClassName,
594 TRUE);
595
596 TRACE("%p class/atom: %s/%04x %x\n", hWnd,
597 IS_ATOM(lpClassName) ? NULL : lpClassName,
598 IS_ATOM(lpClassName) ? lpClassName : 0,
599 nMaxCount);
600
601 return Result;
602 }
603
604
605 /*
606 * @implemented
607 */
608 int
609 WINAPI
610 GetClassNameW(
611 HWND hWnd,
612 LPWSTR lpClassName,
613 int nMaxCount)
614 {
615 UNICODE_STRING ClassName;
616 int Result;
617
618 ClassName.MaximumLength = nMaxCount * sizeof(WCHAR);
619 ClassName.Buffer = lpClassName;
620
621 Result = NtUserGetClassName(hWnd,
622 &ClassName,
623 FALSE);
624
625 TRACE("%p class/atom: %S/%04x %x\n", hWnd,
626 IS_ATOM(lpClassName) ? NULL : lpClassName,
627 IS_ATOM(lpClassName) ? lpClassName : 0,
628 nMaxCount);
629
630 return Result;
631 }
632
633
634 /*
635 * @implemented
636 */
637 WORD
638 WINAPI
639 GetClassWord(
640 HWND hwnd,
641 int offset)
642 {
643 PWND Wnd;
644 PCLS class;
645 WORD retvalue = 0;
646
647 if (offset < 0) return GetClassLongA( hwnd, offset );
648
649 Wnd = ValidateHwnd(hwnd);
650 if (!Wnd)
651 return 0;
652
653 class = DesktopPtrToUser(Wnd->pcls);
654 if (class == NULL) return 0;
655
656 if (offset <= class->cbclsExtra - sizeof(WORD))
657 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
658 else
659 SetLastError( ERROR_INVALID_INDEX );
660
661 return retvalue;
662 }
663
664
665 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
666 {
667 LONG_PTR retvalue = 0;
668 WND *wndPtr;
669
670 if (offset == GWLP_HWNDPARENT)
671 {
672 HWND parent = GetAncestor( hwnd, GA_PARENT );
673 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
674 return (ULONG_PTR)parent;
675 }
676
677 if (!(wndPtr = ValidateHwnd( hwnd )))
678 {
679 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
680 return 0;
681 }
682
683 if (offset >= 0)
684 {
685 if (offset > (int)(wndPtr->cbwndExtra - size))
686 {
687 WARN("Invalid offset %d\n", offset );
688 SetLastError( ERROR_INVALID_INDEX );
689 return 0;
690 }
691 retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
692
693 /* WINE: special case for dialog window procedure */
694 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
695 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
696 return retvalue;
697 }
698
699 switch(offset)
700 {
701 case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
702 case GWL_STYLE: retvalue = wndPtr->style; break;
703 case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
704 case GWLP_ID: retvalue = wndPtr->IDMenu; break;
705 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
706 case GWLP_WNDPROC:
707 {
708 if (!TestWindowProcess(wndPtr))
709 {
710 SetLastError(ERROR_ACCESS_DENIED);
711 retvalue = 0;
712 }
713 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
714 break;
715 }
716 default:
717 WARN("Unknown offset %d\n", offset );
718 SetLastError( ERROR_INVALID_INDEX );
719 break;
720 }
721 return retvalue;
722
723 }
724 /*
725 * @implemented
726 */
727 LONG
728 WINAPI
729 GetWindowLongA ( HWND hWnd, int nIndex )
730 {
731 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
732 }
733
734 /*
735 * @implemented
736 */
737 LONG
738 WINAPI
739 GetWindowLongW(HWND hWnd, int nIndex)
740 {
741 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
742 }
743
744 #ifdef _WIN64
745 /*
746 * @implemented
747 */
748 LONG_PTR
749 WINAPI
750 GetWindowLongPtrA(HWND hWnd,
751 INT nIndex)
752 {
753 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
754 }
755
756 /*
757 * @implemented
758 */
759 LONG_PTR
760 WINAPI
761 GetWindowLongPtrW(HWND hWnd,
762 INT nIndex)
763 {
764 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
765
766 }
767 #endif // _WIN64
768
769 /*
770 * @implemented
771 */
772 WORD
773 WINAPI
774 GetWindowWord(HWND hWnd, int nIndex)
775 {
776 switch(nIndex)
777 {
778 case GWLP_ID:
779 case GWLP_HINSTANCE:
780 case GWLP_HWNDPARENT:
781 break;
782 default:
783 if (nIndex < 0)
784 {
785 WARN("Invalid offset %d\n", nIndex );
786 SetLastError( ERROR_INVALID_INDEX );
787 return 0;
788 }
789 break;
790 }
791 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
792 }
793
794 /*
795 * @implemented
796 */
797 UINT
798 WINAPI
799 RealGetWindowClassW(
800 HWND hwnd,
801 LPWSTR pszType,
802 UINT cchType)
803 {
804 /* FIXME: Implement correct functionality of RealGetWindowClass */
805 return GetClassNameW(hwnd,pszType,cchType);
806 }
807
808
809 /*
810 * @implemented
811 */
812 UINT
813 WINAPI
814 RealGetWindowClassA(
815 HWND hwnd,
816 LPSTR pszType,
817 UINT cchType)
818 {
819 /* FIXME: Implement correct functionality of RealGetWindowClass */
820 return GetClassNameA(hwnd,pszType,cchType);
821 }
822
823 /*
824 * Create a small icon based on a standard icon
825 */
826 static HICON
827 CreateSmallIcon(HICON StdIcon)
828 {
829 HICON SmallIcon = NULL;
830 ICONINFO StdInfo;
831 int SmallIconWidth;
832 int SmallIconHeight;
833 BITMAP StdBitmapInfo;
834 HDC hSourceDc = NULL;
835 HDC hDestDc = NULL;
836 ICONINFO SmallInfo;
837 HBITMAP OldSourceBitmap = NULL;
838 HBITMAP OldDestBitmap = NULL;
839
840 SmallInfo.hbmColor = NULL;
841 SmallInfo.hbmMask = NULL;
842
843 /* We need something to work with... */
844 if (NULL == StdIcon)
845 {
846 goto cleanup;
847 }
848
849 SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
850 SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
851 if (! GetIconInfo(StdIcon, &StdInfo))
852 {
853 ERR("Failed to get icon info for icon 0x%x\n", StdIcon);
854 goto cleanup;
855 }
856 if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
857 {
858 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
859 StdIcon, StdInfo.hbmColor);
860 goto cleanup;
861 }
862 if (StdBitmapInfo.bmWidth == SmallIconWidth &&
863 StdBitmapInfo.bmHeight == SmallIconHeight)
864 {
865 /* Icon already has the correct dimensions */
866 return StdIcon;
867 }
868
869 hSourceDc = CreateCompatibleDC(NULL);
870 if (NULL == hSourceDc)
871 {
872 ERR("Failed to create source DC\n");
873 goto cleanup;
874 }
875 hDestDc = CreateCompatibleDC(NULL);
876 if (NULL == hDestDc)
877 {
878 ERR("Failed to create dest DC\n");
879 goto cleanup;
880 }
881
882 OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
883 if (NULL == OldSourceBitmap)
884 {
885 ERR("Failed to select source color bitmap\n");
886 goto cleanup;
887 }
888 SmallInfo.hbmColor = CreateCompatibleBitmap(hSourceDc, SmallIconWidth,
889 SmallIconHeight);
890 if (NULL == SmallInfo.hbmColor)
891 {
892 ERR("Failed to create color bitmap\n");
893 goto cleanup;
894 }
895 OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
896 if (NULL == OldDestBitmap)
897 {
898 ERR("Failed to select dest color bitmap\n");
899 goto cleanup;
900 }
901 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
902 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
903 StdBitmapInfo.bmHeight, SRCCOPY))
904 {
905 ERR("Failed to stretch color bitmap\n");
906 goto cleanup;
907 }
908
909 if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
910 {
911 ERR("Failed to select source mask bitmap\n");
912 goto cleanup;
913 }
914 SmallInfo.hbmMask = CreateCompatibleBitmap(hSourceDc, SmallIconWidth, SmallIconHeight);
915 if (NULL == SmallInfo.hbmMask)
916 {
917 ERR("Failed to create mask bitmap\n");
918 goto cleanup;
919 }
920 if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
921 {
922 ERR("Failed to select dest mask bitmap\n");
923 goto cleanup;
924 }
925 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
926 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
927 StdBitmapInfo.bmHeight, SRCCOPY))
928 {
929 ERR("Failed to stretch mask bitmap\n");
930 goto cleanup;
931 }
932
933 SmallInfo.fIcon = TRUE;
934 SmallInfo.xHotspot = SmallIconWidth / 2;
935 SmallInfo.yHotspot = SmallIconHeight / 2;
936 SmallIcon = CreateIconIndirect(&SmallInfo);
937 if (NULL == SmallIcon)
938 {
939 ERR("Failed to create icon\n");
940 goto cleanup;
941 }
942
943 cleanup:
944 if (NULL != SmallInfo.hbmMask)
945 {
946 DeleteObject(SmallInfo.hbmMask);
947 }
948 if (NULL != OldDestBitmap)
949 {
950 SelectObject(hDestDc, OldDestBitmap);
951 }
952 if (NULL != SmallInfo.hbmColor)
953 {
954 DeleteObject(SmallInfo.hbmColor);
955 }
956 if (NULL != hDestDc)
957 {
958 DeleteDC(hDestDc);
959 }
960 if (NULL != OldSourceBitmap)
961 {
962 SelectObject(hSourceDc, OldSourceBitmap);
963 }
964 if (NULL != hSourceDc)
965 {
966 DeleteDC(hSourceDc);
967 }
968
969 return SmallIcon;
970 }
971
972
973 ATOM WINAPI
974 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
975 LPDWORD pdwWowData,
976 WORD fnID,
977 DWORD dwFlags,
978 BOOL ChkRegCls)
979 {
980 ATOM Atom;
981 WNDCLASSEXW WndClass;
982 UNICODE_STRING ClassName;
983 UNICODE_STRING MenuName = {0};
984 CLSMENUNAME clsMenuName;
985 ANSI_STRING AnsiMenuName;
986
987 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
988 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
989 lpwcx->lpszClassName == NULL)
990 {
991 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
992 SetLastError(ERROR_INVALID_PARAMETER);
993 return 0;
994 }
995
996 if (ChkRegCls)
997 {
998 if (!RegisterDefaultClasses) RegisterSystemControls();
999 }
1000 /*
1001 * On real Windows this looks more like:
1002 * if (lpwcx->hInstance == User32Instance &&
1003 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1004 * But since I have no idea what the magic field in the
1005 * TEB structure means, I rather decided to omit that.
1006 * -- Filip Navara
1007
1008 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1009 */
1010 if (lpwcx->hInstance == User32Instance)
1011 {
1012 TRACE("RegisterClassExWOWW User32Instance!\n");
1013 SetLastError(ERROR_INVALID_PARAMETER);
1014 return 0;
1015 }
1016 /* Yes, this is correct. We should modify the passed structure. */
1017 if (lpwcx->hInstance == NULL)
1018 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1019
1020 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
1021
1022 if (NULL == WndClass.hIconSm)
1023 {
1024 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1025 }
1026
1027 if (WndClass.lpszMenuName != NULL)
1028 {
1029 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1030 {
1031 if (WndClass.lpszMenuName[0])
1032 {
1033 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1034 RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE);
1035 }
1036 }
1037 else
1038 {
1039 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1040 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1041 }
1042 }
1043
1044 if (IS_ATOM(WndClass.lpszClassName))
1045 {
1046 ClassName.Length =
1047 ClassName.MaximumLength = 0;
1048 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1049 }
1050 else
1051 {
1052 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1053 }
1054
1055 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1056 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1057 clsMenuName.pusMenuName = &MenuName;
1058
1059 Atom = NtUserRegisterClassExWOW( &WndClass,
1060 &ClassName,
1061 NULL, //PUNICODE_STRING ClsNVersion,
1062 &clsMenuName,
1063 fnID,
1064 dwFlags,
1065 pdwWowData);
1066
1067 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1068 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1069 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1070
1071 return Atom;
1072 }
1073
1074 /*
1075 * @implemented
1076 */
1077 ATOM WINAPI
1078 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1079 {
1080 RTL_ATOM Atom;
1081 WNDCLASSEXW WndClass;
1082 WCHAR mname[MAX_BUFFER_LEN];
1083 WCHAR cname[MAX_BUFFER_LEN];
1084
1085 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
1086
1087 if (WndClass.lpszMenuName != NULL)
1088 {
1089 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1090 {
1091 if (WndClass.lpszMenuName[0])
1092 {
1093 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0;
1094
1095 WndClass.lpszMenuName = mname;
1096 }
1097 }
1098 }
1099
1100 if (!IS_ATOM(WndClass.lpszClassName))
1101 {
1102 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0;
1103
1104 WndClass.lpszClassName = cname;
1105 }
1106
1107 Atom = RegisterClassExWOWW( &WndClass,
1108 0,
1109 0,
1110 CSF_ANSIPROC,
1111 TRUE);
1112
1113 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1114 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1115 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1116
1117 return (ATOM)Atom;
1118 }
1119
1120 /*
1121 * @implemented
1122 */
1123 ATOM WINAPI
1124 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1125 {
1126 ATOM Atom;
1127
1128 Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE);
1129
1130 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1131 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1132 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1133
1134 return Atom;
1135 }
1136
1137 /*
1138 * @implemented
1139 */
1140 ATOM WINAPI
1141 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1142 {
1143 WNDCLASSEXA Class;
1144
1145 if (lpWndClass == NULL)
1146 return 0;
1147
1148 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
1149 Class.cbSize = sizeof(WNDCLASSEXA);
1150 Class.hIconSm = NULL;
1151
1152 return RegisterClassExA(&Class);
1153 }
1154
1155 /*
1156 * @implemented
1157 */
1158 ATOM WINAPI
1159 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1160 {
1161 WNDCLASSEXW Class;
1162
1163 if (lpWndClass == NULL)
1164 return 0;
1165
1166 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
1167 Class.cbSize = sizeof(WNDCLASSEXW);
1168 Class.hIconSm = NULL;
1169
1170 return RegisterClassExW(&Class);
1171 }
1172
1173 /*
1174 * @implemented
1175 */
1176 DWORD
1177 WINAPI
1178 SetClassLongA (HWND hWnd,
1179 int nIndex,
1180 LONG dwNewLong)
1181 {
1182 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1183 UNICODE_STRING Value = {0};
1184 BOOL Allocated = FALSE;
1185 DWORD Ret;
1186
1187 /* FIXME - portability!!!! */
1188
1189 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1190 {
1191 if (!IS_INTRESOURCE(lpStr))
1192 {
1193 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1194 lpStr))
1195 {
1196 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1197 return 0;
1198 }
1199
1200 Allocated = TRUE;
1201 }
1202 else
1203 Value.Buffer = (PWSTR)lpStr;
1204
1205 dwNewLong = (LONG_PTR)&Value;
1206 }
1207 else if (nIndex == GCW_ATOM && lpStr != NULL)
1208 {
1209 if (!IS_ATOM(lpStr))
1210 {
1211 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1212 lpStr))
1213 {
1214 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1215 return 0;
1216 }
1217
1218 Allocated = TRUE;
1219 }
1220 else
1221 Value.Buffer = (PWSTR)lpStr;
1222
1223 dwNewLong = (LONG_PTR)&Value;
1224 }
1225
1226 Ret = (DWORD)NtUserSetClassLong(hWnd,
1227 nIndex,
1228 dwNewLong,
1229 TRUE);
1230
1231 if (Allocated)
1232 {
1233 RtlFreeUnicodeString(&Value);
1234 }
1235
1236 return Ret;
1237 }
1238
1239
1240 /*
1241 * @implemented
1242 */
1243 DWORD
1244 WINAPI
1245 SetClassLongW(HWND hWnd,
1246 int nIndex,
1247 LONG dwNewLong)
1248 {
1249 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1250 UNICODE_STRING Value = {0};
1251
1252 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1253
1254 /* FIXME - portability!!!! */
1255
1256 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1257 {
1258 if (!IS_INTRESOURCE(lpStr))
1259 {
1260 RtlInitUnicodeString(&Value,
1261 lpStr);
1262 }
1263 else
1264 Value.Buffer = lpStr;
1265
1266 dwNewLong = (LONG_PTR)&Value;
1267 }
1268 else if (nIndex == GCW_ATOM && lpStr != NULL)
1269 {
1270 if (!IS_ATOM(lpStr))
1271 {
1272 RtlInitUnicodeString(&Value,
1273 lpStr);
1274 }
1275 else
1276 Value.Buffer = lpStr;
1277
1278 dwNewLong = (LONG_PTR)&Value;
1279 }
1280
1281 return (DWORD)NtUserSetClassLong(hWnd,
1282 nIndex,
1283 dwNewLong,
1284 FALSE);
1285 }
1286
1287 #ifdef _WIN64
1288 /*
1289 * @unimplemented
1290 */
1291 ULONG_PTR
1292 WINAPI
1293 SetClassLongPtrA(HWND hWnd,
1294 INT nIndex,
1295 LONG_PTR dwNewLong)
1296 {
1297 UNIMPLEMENTED;
1298 return 0;
1299 }
1300
1301 /*
1302 * @unimplemented
1303 */
1304 ULONG_PTR
1305 WINAPI
1306 SetClassLongPtrW(HWND hWnd,
1307 INT nIndex,
1308 LONG_PTR dwNewLong)
1309 {
1310 UNIMPLEMENTED;
1311 return 0;
1312 }
1313 #endif // _WIN64
1314
1315 /*
1316 * @implemented
1317 */
1318 WORD
1319 WINAPI
1320 SetClassWord(
1321 HWND hWnd,
1322 int nIndex,
1323 WORD wNewWord)
1324 /*
1325 * NOTE: Obsoleted in 32-bit windows
1326 */
1327 {
1328 if ((nIndex < 0) && (nIndex != GCW_ATOM))
1329 return 0;
1330
1331 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1332 }
1333
1334 /*
1335 * @implemented
1336 */
1337 WORD
1338 WINAPI
1339 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1340 {
1341 switch(nIndex)
1342 {
1343 case GWLP_ID:
1344 case GWLP_HINSTANCE:
1345 case GWLP_HWNDPARENT:
1346 break;
1347 default:
1348 if (nIndex < 0)
1349 {
1350 WARN("Invalid offset %d\n", nIndex );
1351 SetLastError( ERROR_INVALID_INDEX );
1352 return 0;
1353 }
1354 break;
1355 }
1356 return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE );
1357 }
1358
1359 /*
1360 * @implemented
1361 */
1362 LONG
1363 WINAPI
1364 SetWindowLongA(
1365 HWND hWnd,
1366 int nIndex,
1367 LONG dwNewLong)
1368 {
1369 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1370 }
1371
1372 /*
1373 * @implemented
1374 */
1375 LONG
1376 WINAPI
1377 SetWindowLongW(
1378 HWND hWnd,
1379 int nIndex,
1380 LONG dwNewLong)
1381 {
1382 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1383 }
1384
1385 #ifdef _WIN64
1386 /*
1387 * @implemented
1388 */
1389 LONG_PTR
1390 WINAPI
1391 SetWindowLongPtrA(HWND hWnd,
1392 INT nIndex,
1393 LONG_PTR dwNewLong)
1394 {
1395 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1396 }
1397
1398 /*
1399 * @implemented
1400 */
1401 LONG_PTR
1402 WINAPI
1403 SetWindowLongPtrW(HWND hWnd,
1404 INT nIndex,
1405 LONG_PTR dwNewLong)
1406 {
1407 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1408 }
1409 #endif
1410
1411 /*
1412 * @implemented
1413 */
1414 BOOL
1415 WINAPI
1416 UnregisterClassA(
1417 LPCSTR lpClassName,
1418 HINSTANCE hInstance)
1419 {
1420 UNICODE_STRING ClassName = {0};
1421 BOOL Ret;
1422
1423 TRACE("class/atom: %s/%04x %p\n",
1424 IS_ATOM(lpClassName) ? NULL : lpClassName,
1425 IS_ATOM(lpClassName) ? lpClassName : 0,
1426 hInstance);
1427
1428 if (!IS_ATOM(lpClassName))
1429 {
1430 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
1431 lpClassName))
1432 {
1433 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1434 return 0;
1435 }
1436 }
1437 else
1438 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1439
1440 Ret = NtUserUnregisterClass(&ClassName,
1441 hInstance,
1442 0);
1443
1444 if (!IS_ATOM(lpClassName))
1445 RtlFreeUnicodeString(&ClassName);
1446
1447 return Ret;
1448 }
1449
1450
1451 /*
1452 * @implemented
1453 */
1454 BOOL
1455 WINAPI
1456 UnregisterClassW(
1457 LPCWSTR lpClassName,
1458 HINSTANCE hInstance)
1459 {
1460 UNICODE_STRING ClassName = {0};
1461
1462 TRACE("class/atom: %S/%04x %p\n",
1463 IS_ATOM(lpClassName) ? NULL : lpClassName,
1464 IS_ATOM(lpClassName) ? lpClassName : 0,
1465 hInstance);
1466
1467 if (!IS_ATOM(lpClassName))
1468 {
1469 RtlInitUnicodeString(&ClassName,
1470 lpClassName);
1471 }
1472 else
1473 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1474
1475 return NtUserUnregisterClass(&ClassName,
1476 hInstance,
1477 0);
1478 }
1479
1480 /* EOF */