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