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