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