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