[USER32]
[reactos.git] / reactos / 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 hInfoDc = NULL;
826 HDC hSourceDc = NULL;
827 HDC hDestDc = NULL;
828 ICONINFO SmallInfo;
829 HBITMAP OldSourceBitmap = NULL;
830 HBITMAP OldDestBitmap = NULL;
831
832 SmallInfo.hbmColor = NULL;
833 SmallInfo.hbmMask = NULL;
834
835 /* We need something to work with... */
836 if (NULL == StdIcon)
837 {
838 goto cleanup;
839 }
840
841 SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
842 SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
843 if (! GetIconInfo(StdIcon, &StdInfo))
844 {
845 ERR("Failed to get icon info for icon 0x%x\n", StdIcon);
846 goto cleanup;
847 }
848 if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
849 {
850 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
851 StdIcon, StdInfo.hbmColor);
852 goto cleanup;
853 }
854 if (StdBitmapInfo.bmWidth == SmallIconWidth &&
855 StdBitmapInfo.bmHeight == SmallIconHeight)
856 {
857 /* Icon already has the correct dimensions */
858 return StdIcon;
859 }
860
861 /* Get a handle to a info DC and handles to DCs which can be used to
862 select a bitmap into. This is done to avoid triggering a switch to
863 graphics mode (if we're currently in text/blue screen mode) */
864 hInfoDc = CreateICW(NULL, NULL, NULL, NULL);
865 if (NULL == hInfoDc)
866 {
867 ERR("Failed to create info DC\n");
868 goto cleanup;
869 }
870 hSourceDc = CreateCompatibleDC(NULL);
871 if (NULL == hSourceDc)
872 {
873 ERR("Failed to create source DC\n");
874 goto cleanup;
875 }
876 hDestDc = CreateCompatibleDC(NULL);
877 if (NULL == hDestDc)
878 {
879 ERR("Failed to create dest DC\n");
880 goto cleanup;
881 }
882
883 OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
884 if (NULL == OldSourceBitmap)
885 {
886 ERR("Failed to select source color bitmap\n");
887 goto cleanup;
888 }
889 SmallInfo.hbmColor = CreateCompatibleBitmap(hInfoDc, SmallIconWidth,
890 SmallIconHeight);
891 if (NULL == SmallInfo.hbmColor)
892 {
893 ERR("Failed to create color bitmap\n");
894 goto cleanup;
895 }
896 OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
897 if (NULL == OldDestBitmap)
898 {
899 ERR("Failed to select dest color bitmap\n");
900 goto cleanup;
901 }
902 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
903 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
904 StdBitmapInfo.bmHeight, SRCCOPY))
905 {
906 ERR("Failed to stretch color bitmap\n");
907 goto cleanup;
908 }
909
910 if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
911 {
912 ERR("Failed to select source mask bitmap\n");
913 goto cleanup;
914 }
915 SmallInfo.hbmMask = CreateBitmap(SmallIconWidth, SmallIconHeight, 1, 1,
916 NULL);
917 if (NULL == SmallInfo.hbmMask)
918 {
919 ERR("Failed to create mask bitmap\n");
920 goto cleanup;
921 }
922 if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
923 {
924 ERR("Failed to select dest mask bitmap\n");
925 goto cleanup;
926 }
927 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
928 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
929 StdBitmapInfo.bmHeight, SRCCOPY))
930 {
931 ERR("Failed to stretch mask bitmap\n");
932 goto cleanup;
933 }
934
935 SmallInfo.fIcon = TRUE;
936 SmallInfo.xHotspot = SmallIconWidth / 2;
937 SmallInfo.yHotspot = SmallIconHeight / 2;
938 SmallIcon = CreateIconIndirect(&SmallInfo);
939 if (NULL == SmallIcon)
940 {
941 ERR("Failed to create icon\n");
942 goto cleanup;
943 }
944
945 cleanup:
946 if (NULL != SmallInfo.hbmMask)
947 {
948 DeleteObject(SmallInfo.hbmMask);
949 }
950 if (NULL != OldDestBitmap)
951 {
952 SelectObject(hDestDc, OldDestBitmap);
953 }
954 if (NULL != SmallInfo.hbmColor)
955 {
956 DeleteObject(SmallInfo.hbmColor);
957 }
958 if (NULL != hDestDc)
959 {
960 DeleteDC(hDestDc);
961 }
962 if (NULL != OldSourceBitmap)
963 {
964 SelectObject(hSourceDc, OldSourceBitmap);
965 }
966 if (NULL != hSourceDc)
967 {
968 DeleteDC(hSourceDc);
969 }
970 if (NULL != hInfoDc)
971 {
972 DeleteDC(hInfoDc);
973 }
974
975 return SmallIcon;
976 }
977
978
979 ATOM WINAPI
980 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
981 LPDWORD pdwWowData,
982 WORD fnID,
983 DWORD dwFlags,
984 BOOL ChkRegCls)
985 {
986 ATOM Atom;
987 WNDCLASSEXW WndClass;
988 UNICODE_STRING ClassName;
989 UNICODE_STRING MenuName = {0};
990 CLSMENUNAME clsMenuName;
991 ANSI_STRING AnsiMenuName;
992
993 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
994 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
995 lpwcx->lpszClassName == NULL)
996 {
997 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
998 SetLastError(ERROR_INVALID_PARAMETER);
999 return 0;
1000 }
1001
1002 if (ChkRegCls)
1003 {
1004 if (!RegisterDefaultClasses) RegisterSystemControls();
1005 }
1006 /*
1007 * On real Windows this looks more like:
1008 * if (lpwcx->hInstance == User32Instance &&
1009 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1010 * But since I have no idea what the magic field in the
1011 * TEB structure means, I rather decided to omit that.
1012 * -- Filip Navara
1013
1014 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1015 */
1016 if (lpwcx->hInstance == User32Instance)
1017 {
1018 TRACE("RegisterClassExWOWW User32Instance!\n");
1019 SetLastError(ERROR_INVALID_PARAMETER);
1020 return 0;
1021 }
1022 /* Yes, this is correct. We should modify the passed structure. */
1023 if (lpwcx->hInstance == NULL)
1024 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1025
1026 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
1027
1028 if (NULL == WndClass.hIconSm)
1029 {
1030 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1031 }
1032
1033 if (WndClass.lpszMenuName != NULL)
1034 {
1035 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1036 {
1037 if (WndClass.lpszMenuName[0])
1038 {
1039 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1040 RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE);
1041 }
1042 }
1043 else
1044 {
1045 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1046 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1047 }
1048 }
1049
1050 if (IS_ATOM(WndClass.lpszClassName))
1051 {
1052 ClassName.Length =
1053 ClassName.MaximumLength = 0;
1054 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1055 }
1056 else
1057 {
1058 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1059 }
1060
1061 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1062 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1063 clsMenuName.pusMenuName = &MenuName;
1064
1065 Atom = NtUserRegisterClassExWOW( &WndClass,
1066 &ClassName,
1067 NULL, //PUNICODE_STRING ClsNVersion,
1068 &clsMenuName,
1069 fnID,
1070 dwFlags,
1071 pdwWowData);
1072
1073 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1074 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1075 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1076
1077 return Atom;
1078 }
1079
1080 /*
1081 * @implemented
1082 */
1083 ATOM WINAPI
1084 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1085 {
1086 RTL_ATOM Atom;
1087 WNDCLASSEXW WndClass;
1088 WCHAR mname[MAX_BUFFER_LEN];
1089 WCHAR cname[MAX_BUFFER_LEN];
1090
1091 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
1092
1093 if (WndClass.lpszMenuName != NULL)
1094 {
1095 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1096 {
1097 if (WndClass.lpszMenuName[0])
1098 {
1099 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0;
1100
1101 WndClass.lpszMenuName = mname;
1102 }
1103 }
1104 }
1105
1106 if (!IS_ATOM(WndClass.lpszClassName))
1107 {
1108 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0;
1109
1110 WndClass.lpszClassName = cname;
1111 }
1112
1113 Atom = RegisterClassExWOWW( &WndClass,
1114 0,
1115 0,
1116 CSF_ANSIPROC,
1117 TRUE);
1118
1119 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1120 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1121 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1122
1123 return (ATOM)Atom;
1124 }
1125
1126 /*
1127 * @implemented
1128 */
1129 ATOM WINAPI
1130 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1131 {
1132 ATOM Atom;
1133
1134 Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE);
1135
1136 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1137 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1138 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1139
1140 return Atom;
1141 }
1142
1143 /*
1144 * @implemented
1145 */
1146 ATOM WINAPI
1147 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1148 {
1149 WNDCLASSEXA Class;
1150
1151 if (lpWndClass == NULL)
1152 return 0;
1153
1154 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
1155 Class.cbSize = sizeof(WNDCLASSEXA);
1156 Class.hIconSm = NULL;
1157
1158 return RegisterClassExA(&Class);
1159 }
1160
1161 /*
1162 * @implemented
1163 */
1164 ATOM WINAPI
1165 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1166 {
1167 WNDCLASSEXW Class;
1168
1169 if (lpWndClass == NULL)
1170 return 0;
1171
1172 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
1173 Class.cbSize = sizeof(WNDCLASSEXW);
1174 Class.hIconSm = NULL;
1175
1176 return RegisterClassExW(&Class);
1177 }
1178
1179 /*
1180 * @implemented
1181 */
1182 DWORD
1183 WINAPI
1184 SetClassLongA (HWND hWnd,
1185 int nIndex,
1186 LONG dwNewLong)
1187 {
1188 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1189 UNICODE_STRING Value = {0};
1190 BOOL Allocated = FALSE;
1191 DWORD Ret;
1192
1193 /* FIXME - portability!!!! */
1194
1195 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1196 {
1197 if (!IS_INTRESOURCE(lpStr))
1198 {
1199 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1200 lpStr))
1201 {
1202 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1203 return 0;
1204 }
1205
1206 Allocated = TRUE;
1207 }
1208 else
1209 Value.Buffer = (PWSTR)lpStr;
1210
1211 dwNewLong = (LONG_PTR)&Value;
1212 }
1213 else if (nIndex == GCW_ATOM && lpStr != NULL)
1214 {
1215 if (!IS_ATOM(lpStr))
1216 {
1217 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1218 lpStr))
1219 {
1220 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1221 return 0;
1222 }
1223
1224 Allocated = TRUE;
1225 }
1226 else
1227 Value.Buffer = (PWSTR)lpStr;
1228
1229 dwNewLong = (LONG_PTR)&Value;
1230 }
1231
1232 Ret = (DWORD)NtUserSetClassLong(hWnd,
1233 nIndex,
1234 dwNewLong,
1235 TRUE);
1236
1237 if (Allocated)
1238 {
1239 RtlFreeUnicodeString(&Value);
1240 }
1241
1242 return Ret;
1243 }
1244
1245
1246 /*
1247 * @implemented
1248 */
1249 DWORD
1250 WINAPI
1251 SetClassLongW(HWND hWnd,
1252 int nIndex,
1253 LONG dwNewLong)
1254 {
1255 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1256 UNICODE_STRING Value = {0};
1257
1258 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1259
1260 /* FIXME - portability!!!! */
1261
1262 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1263 {
1264 if (!IS_INTRESOURCE(lpStr))
1265 {
1266 RtlInitUnicodeString(&Value,
1267 lpStr);
1268 }
1269 else
1270 Value.Buffer = lpStr;
1271
1272 dwNewLong = (LONG_PTR)&Value;
1273 }
1274 else if (nIndex == GCW_ATOM && lpStr != NULL)
1275 {
1276 if (!IS_ATOM(lpStr))
1277 {
1278 RtlInitUnicodeString(&Value,
1279 lpStr);
1280 }
1281 else
1282 Value.Buffer = lpStr;
1283
1284 dwNewLong = (LONG_PTR)&Value;
1285 }
1286
1287 return (DWORD)NtUserSetClassLong(hWnd,
1288 nIndex,
1289 dwNewLong,
1290 FALSE);
1291 }
1292
1293 #ifdef _WIN64
1294 /*
1295 * @unimplemented
1296 */
1297 ULONG_PTR
1298 WINAPI
1299 SetClassLongPtrA(HWND hWnd,
1300 INT nIndex,
1301 LONG_PTR dwNewLong)
1302 {
1303 UNIMPLEMENTED;
1304 return 0;
1305 }
1306
1307 /*
1308 * @unimplemented
1309 */
1310 ULONG_PTR
1311 WINAPI
1312 SetClassLongPtrW(HWND hWnd,
1313 INT nIndex,
1314 LONG_PTR dwNewLong)
1315 {
1316 UNIMPLEMENTED;
1317 return 0;
1318 }
1319 #endif // _WIN64
1320
1321 /*
1322 * @implemented
1323 */
1324 WORD
1325 WINAPI
1326 SetClassWord(
1327 HWND hWnd,
1328 int nIndex,
1329 WORD wNewWord)
1330 /*
1331 * NOTE: Obsoleted in 32-bit windows
1332 */
1333 {
1334 if ((nIndex < 0) && (nIndex != GCW_ATOM))
1335 return 0;
1336
1337 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1338 }
1339
1340 /*
1341 * @implemented
1342 */
1343 WORD
1344 WINAPI
1345 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1346 {
1347 switch(nIndex)
1348 {
1349 case GWLP_ID:
1350 case GWLP_HINSTANCE:
1351 case GWLP_HWNDPARENT:
1352 break;
1353 default:
1354 if (nIndex < 0)
1355 {
1356 WARN("Invalid offset %d\n", nIndex );
1357 SetLastError( ERROR_INVALID_INDEX );
1358 return 0;
1359 }
1360 break;
1361 }
1362 return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE );
1363 }
1364
1365 /*
1366 * @implemented
1367 */
1368 LONG
1369 WINAPI
1370 SetWindowLongA(
1371 HWND hWnd,
1372 int nIndex,
1373 LONG dwNewLong)
1374 {
1375 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1376 }
1377
1378 /*
1379 * @implemented
1380 */
1381 LONG
1382 WINAPI
1383 SetWindowLongW(
1384 HWND hWnd,
1385 int nIndex,
1386 LONG dwNewLong)
1387 {
1388 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1389 }
1390
1391 #ifdef _WIN64
1392 /*
1393 * @implemented
1394 */
1395 LONG_PTR
1396 WINAPI
1397 SetWindowLongPtrA(HWND hWnd,
1398 INT nIndex,
1399 LONG_PTR dwNewLong)
1400 {
1401 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1402 }
1403
1404 /*
1405 * @implemented
1406 */
1407 LONG_PTR
1408 WINAPI
1409 SetWindowLongPtrW(HWND hWnd,
1410 INT nIndex,
1411 LONG_PTR dwNewLong)
1412 {
1413 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1414 }
1415 #endif
1416
1417 /*
1418 * @implemented
1419 */
1420 BOOL
1421 WINAPI
1422 UnregisterClassA(
1423 LPCSTR lpClassName,
1424 HINSTANCE hInstance)
1425 {
1426 UNICODE_STRING ClassName = {0};
1427 BOOL Ret;
1428
1429 TRACE("class/atom: %s/%04x %p\n",
1430 IS_ATOM(lpClassName) ? NULL : lpClassName,
1431 IS_ATOM(lpClassName) ? lpClassName : 0,
1432 hInstance);
1433
1434 if (!IS_ATOM(lpClassName))
1435 {
1436 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
1437 lpClassName))
1438 {
1439 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1440 return 0;
1441 }
1442 }
1443 else
1444 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1445
1446 Ret = NtUserUnregisterClass(&ClassName,
1447 hInstance,
1448 0);
1449
1450 if (!IS_ATOM(lpClassName))
1451 RtlFreeUnicodeString(&ClassName);
1452
1453 return Ret;
1454 }
1455
1456
1457 /*
1458 * @implemented
1459 */
1460 BOOL
1461 WINAPI
1462 UnregisterClassW(
1463 LPCWSTR lpClassName,
1464 HINSTANCE hInstance)
1465 {
1466 UNICODE_STRING ClassName = {0};
1467
1468 TRACE("class/atom: %S/%04x %p\n",
1469 IS_ATOM(lpClassName) ? NULL : lpClassName,
1470 IS_ATOM(lpClassName) ? lpClassName : 0,
1471 hInstance);
1472
1473 if (!IS_ATOM(lpClassName))
1474 {
1475 RtlInitUnicodeString(&ClassName,
1476 lpClassName);
1477 }
1478 else
1479 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1480
1481 return NtUserUnregisterClass(&ClassName,
1482 hInstance,
1483 0);
1484 }
1485
1486 /* EOF */