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