sync rostests to r44455
[reactos.git] / reactos / dll / win32 / user32 / windows / class.c
1 /*
2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/user32/windows/class.c
5 * PURPOSE: Window classes
6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * UPDATE HISTORY:
8 * 09-05-2001 CSH Created
9 */
10
11 #include <user32.h>
12
13 #include <wine/debug.h>
14 WINE_DEFAULT_DEBUG_CHANNEL(user32);
15
16 /*
17 * @implemented
18 */
19 BOOL
20 WINAPI
21 GetClassInfoExA(
22 HINSTANCE hInstance,
23 LPCSTR lpszClass,
24 LPWNDCLASSEXA lpwcx)
25 {
26 UNICODE_STRING ClassName = {0};
27 BOOL Ret;
28 LPCSTR pszMenuName;
29
30 TRACE("%p class/atom: %s/%04x %p\n", hInstance,
31 IS_ATOM(lpszClass) ? NULL : lpszClass,
32 IS_ATOM(lpszClass) ? lpszClass : 0,
33 lpwcx);
34
35 //HACKHACK: This is ROS-specific and should go away
36 lpwcx->cbSize = sizeof(*lpwcx);
37
38 if (hInstance == User32Instance)
39 {
40 hInstance = NULL;
41 }
42
43 if (lpszClass == NULL)
44 {
45 SetLastError(ERROR_INVALID_PARAMETER);
46 return FALSE;
47 }
48
49 if (!RegisterDefaultClasses)
50 {
51 ERR("GetClassInfoExA RegisterSystemControls\n");
52 RegisterSystemControls();
53 }
54
55 if (IS_ATOM(lpszClass))
56 {
57 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
58 }
59 else
60 {
61 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
62 lpszClass))
63 {
64 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
65 return FALSE;
66 }
67 }
68
69 Ret = NtUserGetClassInfo(hInstance,
70 &ClassName,
71 (LPWNDCLASSEXW)lpwcx,
72 (LPWSTR *)&pszMenuName,
73 TRUE);
74 if (Ret)
75 {
76 lpwcx->lpszClassName = lpszClass;
77 // lpwcx->lpszMenuName = pszMenuName;
78 }
79
80 if (!IS_ATOM(lpszClass))
81 {
82 RtlFreeUnicodeString(&ClassName);
83 }
84
85 return Ret;
86 }
87
88
89 /*
90 * @implemented
91 */
92 BOOL
93 WINAPI
94 GetClassInfoExW(
95 HINSTANCE hInstance,
96 LPCWSTR lpszClass,
97 LPWNDCLASSEXW lpwcx)
98 {
99 UNICODE_STRING ClassName = {0};
100 BOOL Ret;
101 LPWSTR pszMenuName;
102
103 TRACE("%p class/atom: %S/%04x %p\n", hInstance,
104 IS_ATOM(lpszClass) ? NULL : lpszClass,
105 IS_ATOM(lpszClass) ? lpszClass : 0,
106 lpwcx);
107
108 //HACKHACK: This is ROS-specific and should go away
109 lpwcx->cbSize = sizeof(*lpwcx);
110
111 if (hInstance == User32Instance)
112 {
113 hInstance = NULL;
114 }
115
116 if (lpszClass == NULL)
117 {
118 SetLastError(ERROR_INVALID_PARAMETER);
119 return FALSE;
120 }
121
122 if (!RegisterDefaultClasses)
123 {
124 ERR("GetClassInfoExW RegisterSystemControls\n");
125 RegisterSystemControls();
126 }
127
128 if (IS_ATOM(lpszClass))
129 {
130 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
131 }
132 else
133 {
134 RtlInitUnicodeString(&ClassName,
135 lpszClass);
136 }
137
138 Ret = NtUserGetClassInfo( hInstance,
139 &ClassName,
140 lpwcx,
141 &pszMenuName,
142 FALSE);
143 if (Ret)
144 {
145 lpwcx->lpszClassName = lpszClass;
146 // lpwcx->lpszMenuName = pszMenuName;
147 }
148 return Ret;
149 }
150
151
152 /*
153 * @implemented
154 */
155 BOOL
156 WINAPI
157 GetClassInfoA(
158 HINSTANCE hInstance,
159 LPCSTR lpClassName,
160 LPWNDCLASSA lpWndClass)
161 {
162 WNDCLASSEXA wcex;
163 BOOL retval;
164
165 retval = GetClassInfoExA(hInstance, lpClassName, &wcex);
166 if (retval)
167 {
168 lpWndClass->style = wcex.style;
169 lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
170 lpWndClass->cbClsExtra = wcex.cbClsExtra;
171 lpWndClass->cbWndExtra = wcex.cbWndExtra;
172 lpWndClass->hInstance = wcex.hInstance;
173 lpWndClass->hIcon = wcex.hIcon;
174 lpWndClass->hCursor = wcex.hCursor;
175 lpWndClass->hbrBackground = wcex.hbrBackground;
176 lpWndClass->lpszMenuName = wcex.lpszMenuName;
177 lpWndClass->lpszClassName = wcex.lpszClassName;
178 }
179
180 return retval;
181 }
182
183 /*
184 * @implemented
185 */
186 BOOL
187 WINAPI
188 GetClassInfoW(
189 HINSTANCE hInstance,
190 LPCWSTR lpClassName,
191 LPWNDCLASSW lpWndClass)
192 {
193 WNDCLASSEXW wcex;
194 BOOL retval;
195
196 retval = GetClassInfoExW(hInstance, lpClassName, &wcex);
197 if (retval)
198 {
199 lpWndClass->style = wcex.style;
200 lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
201 lpWndClass->cbClsExtra = wcex.cbClsExtra;
202 lpWndClass->cbWndExtra = wcex.cbWndExtra;
203 lpWndClass->hInstance = wcex.hInstance;
204 lpWndClass->hIcon = wcex.hIcon;
205 lpWndClass->hCursor = wcex.hCursor;
206 lpWndClass->hbrBackground = wcex.hbrBackground;
207 lpWndClass->lpszMenuName = wcex.lpszMenuName;
208 lpWndClass->lpszClassName = wcex.lpszClassName;
209 }
210 return retval;
211 }
212
213 //
214 // Based on find_winproc... Fixes many whine tests......
215 //
216 ULONG_PTR FASTCALL
217 IntGetClsWndProc(PWND pWnd, PCLS Class, BOOL Ansi)
218 {
219 INT i;
220 ULONG_PTR gcpd, Ret = 0;
221 // If server side, sweep through proc list and return the client side proc.
222 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
223 { // Always scan through the list due to wine class "deftest".
224 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
225 {
226 if (GETPFNSERVER(i) == Class->lpfnWndProc)
227 {
228 if (Ansi)
229 Ret = (ULONG_PTR)GETPFNCLIENTA(i);
230 else
231 Ret = (ULONG_PTR)GETPFNCLIENTW(i);
232 }
233 }
234 return Ret;
235 }
236 // Set return proc.
237 Ret = (ULONG_PTR)Class->lpfnWndProc;
238 // Return the proc if one of the FnId default class type.
239 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
240 {
241 if (Ansi)
242 { // If match return the right proc by type.
243 if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
244 Ret = (ULONG_PTR)GETPFNCLIENTA(Class->fnid);
245 }
246 else
247 {
248 if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
249 Ret = (ULONG_PTR)GETPFNCLIENTW(Class->fnid);
250 }
251 }
252 // Return on change or Ansi/Unicode proc equal.
253 if ( Ret != (ULONG_PTR)Class->lpfnWndProc ||
254 Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
255 return Ret;
256
257 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
258 This will force CallWindowProc to deal with it. */
259 gcpd = NtUserGetCPD( UserHMGetHandle(pWnd),
260 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWndtoCls,
261 Ret);
262
263 return (gcpd ? gcpd : Ret);
264 }
265
266 //
267 // Based on IntGetClsWndProc
268 //
269 WNDPROC FASTCALL
270 IntGetWndProc(PWND pWnd, BOOL Ansi)
271 {
272 INT i;
273 WNDPROC gcpd, Ret = 0;
274 PCLS Class = DesktopPtrToUser(pWnd->pcls);
275
276 if (!Class) return Ret;
277
278 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
279 {
280 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
281 {
282 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
283 {
284 if (Ansi)
285 Ret = GETPFNCLIENTA(i);
286 else
287 Ret = GETPFNCLIENTW(i);
288 }
289 }
290 return Ret;
291 }
292 // Wine Class tests:
293 /* Edit controls are special - they return a wndproc handle when
294 GetWindowLongPtr is called with a different A/W.
295 On the other hand there is no W->A->W conversion so this control
296 is treated specially.
297 */
298 if (Class->fnid == FNID_EDIT)
299 Ret = pWnd->lpfnWndProc;
300 else
301 {
302 // Set return proc.
303 Ret = pWnd->lpfnWndProc;
304
305 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
306 {
307 if (Ansi)
308 {
309 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
310 Ret = GETPFNCLIENTA(Class->fnid);
311 }
312 else
313 {
314 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
315 Ret = GETPFNCLIENTW(Class->fnid);
316 }
317 }
318 // Return on the change.
319 if ( Ret != pWnd->lpfnWndProc)
320 return Ret;
321 }
322
323 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
324 return Ret;
325
326 gcpd = (WNDPROC)NtUserGetCPD( UserHMGetHandle(pWnd),
327 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
328 (ULONG_PTR)&Ret);
329
330 return (gcpd ? gcpd : Ret);
331 }
332
333 /*
334 * @implemented
335 */
336 DWORD WINAPI
337 GetClassLongA(HWND hWnd, int nIndex)
338 {
339 PWND Wnd;
340 PCLS Class;
341 ULONG_PTR Ret = 0;
342
343 TRACE("%p %d\n", hWnd, nIndex);
344
345 Wnd = ValidateHwnd(hWnd);
346 if (!Wnd)
347 return 0;
348
349 _SEH2_TRY
350 {
351 Class = DesktopPtrToUser(Wnd->pcls);
352 if (Class != NULL)
353 {
354 if (nIndex >= 0)
355 {
356 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
357 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
358 {
359 SetLastError(ERROR_INVALID_PARAMETER);
360 }
361 else
362 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
363 }
364 else
365 {
366 switch (nIndex)
367 {
368 case GCL_CBWNDEXTRA:
369 Ret = (ULONG_PTR)Class->cbwndExtra;
370 break;
371
372 case GCL_CBCLSEXTRA:
373 Ret = (ULONG_PTR)Class->cbclsExtra;
374 break;
375
376 case GCL_HBRBACKGROUND:
377 Ret = (ULONG_PTR)Class->hbrBackground;
378 if (Ret != 0 && Ret < 0x4000)
379 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
380 break;
381
382 case GCL_HMODULE:
383 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
384 Ret = (ULONG_PTR)Class->hModule;
385 break;
386
387 case GCL_MENUNAME:
388 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
389 break;
390
391 case GCL_STYLE:
392 Ret = (ULONG_PTR)Class->style;
393 break;
394
395 case GCW_ATOM:
396 Ret = (ULONG_PTR)Class->atomClassName;
397 break;
398
399 case GCLP_HCURSOR:
400 /* FIXME - get handle from pointer to CURSOR object */
401 Ret = (ULONG_PTR)Class->hCursor;
402 break;
403
404 case GCLP_HICON:
405 /* FIXME - get handle from pointer to ICON object */
406 Ret = (ULONG_PTR)Class->hIcon;
407 break;
408
409 case GCLP_HICONSM:
410 /* FIXME - get handle from pointer to ICON object */
411 Ret = (ULONG_PTR)Class->hIconSm;
412 break;
413
414 case GCLP_WNDPROC:
415 Ret = IntGetClsWndProc(Wnd, Class, TRUE);
416 break;
417
418 default:
419 SetLastError(ERROR_INVALID_INDEX);
420 break;
421 }
422 }
423 }
424 else
425 {
426 /* 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 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
662 {
663 LONG_PTR retvalue = 0;
664 WND *wndPtr;
665
666 if (offset == GWLP_HWNDPARENT)
667 {
668 HWND parent = GetAncestor( hwnd, GA_PARENT );
669 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
670 return (ULONG_PTR)parent;
671 }
672
673 if (!(wndPtr = ValidateHwnd( hwnd )))
674 {
675 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
676 return 0;
677 }
678
679 if (offset >= 0)
680 {
681 if (offset > (int)(wndPtr->cbwndExtra - size))
682 {
683 WARN("Invalid offset %d\n", offset );
684 SetLastError( ERROR_INVALID_INDEX );
685 return 0;
686 }
687 retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
688
689 /* WINE: special case for dialog window procedure */
690 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
691 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
692 return retvalue;
693 }
694
695 switch(offset)
696 {
697 case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
698 case GWL_STYLE: retvalue = wndPtr->style; break;
699 case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
700 case GWLP_ID: retvalue = wndPtr->IDMenu; break;
701 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
702 case GWLP_WNDPROC:
703 {
704 if (!TestWindowProcess(wndPtr))
705 {
706 SetLastError(ERROR_ACCESS_DENIED);
707 retvalue = 0;
708 }
709 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, unicode);
710 break;
711 }
712 default:
713 WARN("Unknown offset %d\n", offset );
714 SetLastError( ERROR_INVALID_INDEX );
715 break;
716 }
717 return retvalue;
718
719 }
720 /*
721 * @implemented
722 */
723 LONG
724 WINAPI
725 GetWindowLongA ( HWND hWnd, int nIndex )
726 {
727 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
728 }
729
730 /*
731 * @implemented
732 */
733 LONG
734 WINAPI
735 GetWindowLongW(HWND hWnd, int nIndex)
736 {
737 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
738 }
739
740 #ifdef _WIN64
741 /*
742 * @implemented
743 */
744 LONG_PTR
745 WINAPI
746 GetWindowLongPtrA(HWND hWnd,
747 INT nIndex)
748 {
749 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
750 }
751
752 /*
753 * @implemented
754 */
755 LONG_PTR
756 WINAPI
757 GetWindowLongPtrW(HWND hWnd,
758 INT nIndex)
759 {
760 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
761
762 }
763 #endif // _WIN64
764
765 /*
766 * @implemented
767 */
768 WORD
769 WINAPI
770 GetWindowWord(HWND hWnd, int nIndex)
771 {
772 switch(nIndex)
773 {
774 case GWLP_ID:
775 case GWLP_HINSTANCE:
776 case GWLP_HWNDPARENT:
777 break;
778 default:
779 if (nIndex < 0)
780 {
781 WARN("Invalid offset %d\n", nIndex );
782 SetLastError( ERROR_INVALID_INDEX );
783 return 0;
784 }
785 break;
786 }
787 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
788 }
789
790 /*
791 * @implemented
792 */
793 UINT
794 WINAPI
795 RealGetWindowClassW(
796 HWND hwnd,
797 LPWSTR pszType,
798 UINT cchType)
799 {
800 /* FIXME: Implement correct functionality of RealGetWindowClass */
801 return GetClassNameW(hwnd,pszType,cchType);
802 }
803
804
805 /*
806 * @implemented
807 */
808 UINT
809 WINAPI
810 RealGetWindowClassA(
811 HWND hwnd,
812 LPSTR pszType,
813 UINT cchType)
814 {
815 /* FIXME: Implement correct functionality of RealGetWindowClass */
816 return GetClassNameA(hwnd,pszType,cchType);
817 }
818
819 /*
820 * Create a small icon based on a standard icon
821 */
822 static HICON
823 CreateSmallIcon(HICON StdIcon)
824 {
825 HICON SmallIcon = NULL;
826 ICONINFO StdInfo;
827 int SmallIconWidth;
828 int SmallIconHeight;
829 BITMAP StdBitmapInfo;
830 HDC hInfoDc = NULL;
831 HDC hSourceDc = NULL;
832 HDC hDestDc = NULL;
833 ICONINFO SmallInfo;
834 HBITMAP OldSourceBitmap = NULL;
835 HBITMAP OldDestBitmap = NULL;
836
837 SmallInfo.hbmColor = NULL;
838 SmallInfo.hbmMask = NULL;
839
840 /* We need something to work with... */
841 if (NULL == StdIcon)
842 {
843 goto cleanup;
844 }
845
846 SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
847 SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
848 if (! GetIconInfo(StdIcon, &StdInfo))
849 {
850 ERR("Failed to get icon info for icon 0x%x\n", StdIcon);
851 goto cleanup;
852 }
853 if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
854 {
855 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
856 StdIcon, StdInfo.hbmColor);
857 goto cleanup;
858 }
859 if (StdBitmapInfo.bmWidth == SmallIconWidth &&
860 StdBitmapInfo.bmHeight == SmallIconHeight)
861 {
862 /* Icon already has the correct dimensions */
863 return StdIcon;
864 }
865
866 /* Get a handle to a info DC and handles to DCs which can be used to
867 select a bitmap into. This is done to avoid triggering a switch to
868 graphics mode (if we're currently in text/blue screen mode) */
869 hInfoDc = CreateICW(NULL, NULL, NULL, NULL);
870 if (NULL == hInfoDc)
871 {
872 ERR("Failed to create info DC\n");
873 goto cleanup;
874 }
875 hSourceDc = CreateCompatibleDC(NULL);
876 if (NULL == hSourceDc)
877 {
878 ERR("Failed to create source DC\n");
879 goto cleanup;
880 }
881 hDestDc = CreateCompatibleDC(NULL);
882 if (NULL == hDestDc)
883 {
884 ERR("Failed to create dest DC\n");
885 goto cleanup;
886 }
887
888 OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
889 if (NULL == OldSourceBitmap)
890 {
891 ERR("Failed to select source color bitmap\n");
892 goto cleanup;
893 }
894 SmallInfo.hbmColor = CreateCompatibleBitmap(hInfoDc, SmallIconWidth,
895 SmallIconHeight);
896 if (NULL == SmallInfo.hbmColor)
897 {
898 ERR("Failed to create color bitmap\n");
899 goto cleanup;
900 }
901 OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
902 if (NULL == OldDestBitmap)
903 {
904 ERR("Failed to select dest color bitmap\n");
905 goto cleanup;
906 }
907 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
908 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
909 StdBitmapInfo.bmHeight, SRCCOPY))
910 {
911 ERR("Failed to stretch color bitmap\n");
912 goto cleanup;
913 }
914
915 if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
916 {
917 ERR("Failed to select source mask bitmap\n");
918 goto cleanup;
919 }
920 SmallInfo.hbmMask = CreateBitmap(SmallIconWidth, SmallIconHeight, 1, 1,
921 NULL);
922 if (NULL == SmallInfo.hbmMask)
923 {
924 ERR("Failed to create mask bitmap\n");
925 goto cleanup;
926 }
927 if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
928 {
929 ERR("Failed to select dest mask bitmap\n");
930 goto cleanup;
931 }
932 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
933 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
934 StdBitmapInfo.bmHeight, SRCCOPY))
935 {
936 ERR("Failed to stretch mask bitmap\n");
937 goto cleanup;
938 }
939
940 SmallInfo.fIcon = TRUE;
941 SmallInfo.xHotspot = SmallIconWidth / 2;
942 SmallInfo.yHotspot = SmallIconHeight / 2;
943 SmallIcon = CreateIconIndirect(&SmallInfo);
944 if (NULL == SmallIcon)
945 {
946 ERR("Failed to create icon\n");
947 goto cleanup;
948 }
949
950 cleanup:
951 if (NULL != SmallInfo.hbmMask)
952 {
953 DeleteObject(SmallInfo.hbmMask);
954 }
955 if (NULL != OldDestBitmap)
956 {
957 SelectObject(hDestDc, OldDestBitmap);
958 }
959 if (NULL != SmallInfo.hbmColor)
960 {
961 DeleteObject(SmallInfo.hbmColor);
962 }
963 if (NULL != hDestDc)
964 {
965 DeleteDC(hDestDc);
966 }
967 if (NULL != OldSourceBitmap)
968 {
969 SelectObject(hSourceDc, OldSourceBitmap);
970 }
971 if (NULL != hSourceDc)
972 {
973 DeleteDC(hSourceDc);
974 }
975 if (NULL != hInfoDc)
976 {
977 DeleteDC(hInfoDc);
978 }
979
980 return SmallIcon;
981 }
982
983
984 ATOM WINAPI
985 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
986 LPDWORD pdwWowData,
987 WORD fnID,
988 DWORD dwFlags,
989 BOOL ChkRegCls)
990 {
991 ATOM Atom;
992 WNDCLASSEXW WndClass;
993 UNICODE_STRING ClassName;
994 UNICODE_STRING MenuName = {0};
995 CLSMENUNAME clsMenuName;
996 ANSI_STRING AnsiMenuName;
997
998 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
999 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
1000 lpwcx->lpszClassName == NULL)
1001 {
1002 ERR("RegisterClassExWOWW Invalid Parameter Error!\n");
1003 SetLastError(ERROR_INVALID_PARAMETER);
1004 return 0;
1005 }
1006
1007 if (ChkRegCls)
1008 {
1009 if (!RegisterDefaultClasses) RegisterSystemControls();
1010 }
1011 /*
1012 * On real Windows this looks more like:
1013 * if (lpwcx->hInstance == User32Instance &&
1014 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1015 * But since I have no idea what the magic field in the
1016 * TEB structure means, I rather decided to omit that.
1017 * -- Filip Navara
1018
1019 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1020 */
1021 if (lpwcx->hInstance == User32Instance)
1022 {
1023 ERR("RegisterClassExWOWW User32Instance!\n");
1024 SetLastError(ERROR_INVALID_PARAMETER);
1025 return 0;
1026 }
1027 /* Yes, this is correct. We should modify the passed structure. */
1028 if (lpwcx->hInstance == NULL)
1029 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1030
1031 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
1032
1033 if (NULL == WndClass.hIconSm)
1034 {
1035 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1036 }
1037
1038 if (WndClass.lpszMenuName != NULL)
1039 {
1040 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1041 {
1042 if (WndClass.lpszMenuName[0])
1043 {
1044 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1045 RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE);
1046 }
1047 }
1048 else
1049 {
1050 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1051 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1052 }
1053 }
1054
1055 if (IS_ATOM(WndClass.lpszClassName))
1056 {
1057 ClassName.Length =
1058 ClassName.MaximumLength = 0;
1059 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1060 }
1061 else
1062 {
1063 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1064 }
1065
1066 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1067 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1068 clsMenuName.pusMenuName = &MenuName;
1069
1070 Atom = NtUserRegisterClassExWOW( &WndClass,
1071 &ClassName,
1072 NULL, //PUNICODE_STRING ClsNVersion,
1073 &clsMenuName,
1074 fnID,
1075 dwFlags,
1076 pdwWowData);
1077
1078 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1079 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1080 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1081
1082 return Atom;
1083 }
1084
1085 /*
1086 * @implemented
1087 */
1088 ATOM WINAPI
1089 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1090 {
1091 RTL_ATOM Atom;
1092 WNDCLASSEXW WndClass;
1093 WCHAR mname[MAX_BUFFER_LEN];
1094 WCHAR cname[MAX_BUFFER_LEN];
1095
1096 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
1097
1098 if (WndClass.lpszMenuName != NULL)
1099 {
1100 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1101 {
1102 if (WndClass.lpszMenuName[0])
1103 {
1104 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0;
1105
1106 WndClass.lpszMenuName = mname;
1107 }
1108 }
1109 }
1110
1111 if (!IS_ATOM(WndClass.lpszClassName))
1112 {
1113 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0;
1114
1115 WndClass.lpszClassName = cname;
1116 }
1117
1118 Atom = RegisterClassExWOWW( &WndClass,
1119 0,
1120 0,
1121 CSF_ANSIPROC,
1122 TRUE);
1123
1124 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1125 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1126 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1127
1128 return (ATOM)Atom;
1129 }
1130
1131 /*
1132 * @implemented
1133 */
1134 ATOM WINAPI
1135 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1136 {
1137 ATOM Atom;
1138
1139 Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE);
1140
1141 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1142 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1143 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1144
1145 return Atom;
1146 }
1147
1148 /*
1149 * @implemented
1150 */
1151 ATOM WINAPI
1152 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1153 {
1154 WNDCLASSEXA Class;
1155
1156 if (lpWndClass == NULL)
1157 return 0;
1158
1159 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
1160 Class.cbSize = sizeof(WNDCLASSEXA);
1161 Class.hIconSm = NULL;
1162
1163 return RegisterClassExA(&Class);
1164 }
1165
1166 /*
1167 * @implemented
1168 */
1169 ATOM WINAPI
1170 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1171 {
1172 WNDCLASSEXW Class;
1173
1174 if (lpWndClass == NULL)
1175 return 0;
1176
1177 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
1178 Class.cbSize = sizeof(WNDCLASSEXW);
1179 Class.hIconSm = NULL;
1180
1181 return RegisterClassExW(&Class);
1182 }
1183
1184 /*
1185 * @implemented
1186 */
1187 DWORD
1188 WINAPI
1189 SetClassLongA (HWND hWnd,
1190 int nIndex,
1191 LONG dwNewLong)
1192 {
1193 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1194 UNICODE_STRING Value = {0};
1195 BOOL Allocated = FALSE;
1196 DWORD Ret;
1197
1198 /* FIXME - portability!!!! */
1199
1200 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1201 {
1202 if (!IS_INTRESOURCE(lpStr))
1203 {
1204 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1205 lpStr))
1206 {
1207 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1208 return 0;
1209 }
1210
1211 Allocated = TRUE;
1212 }
1213 else
1214 Value.Buffer = (PWSTR)lpStr;
1215
1216 dwNewLong = (LONG_PTR)&Value;
1217 }
1218 else if (nIndex == GCW_ATOM && lpStr != NULL)
1219 {
1220 if (!IS_ATOM(lpStr))
1221 {
1222 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1223 lpStr))
1224 {
1225 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1226 return 0;
1227 }
1228
1229 Allocated = TRUE;
1230 }
1231 else
1232 Value.Buffer = (PWSTR)lpStr;
1233
1234 dwNewLong = (LONG_PTR)&Value;
1235 }
1236
1237 Ret = (DWORD)NtUserSetClassLong(hWnd,
1238 nIndex,
1239 dwNewLong,
1240 TRUE);
1241
1242 if (Allocated)
1243 {
1244 RtlFreeUnicodeString(&Value);
1245 }
1246
1247 return Ret;
1248 }
1249
1250
1251 /*
1252 * @implemented
1253 */
1254 DWORD
1255 WINAPI
1256 SetClassLongW(HWND hWnd,
1257 int nIndex,
1258 LONG dwNewLong)
1259 {
1260 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1261 UNICODE_STRING Value = {0};
1262
1263 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1264
1265 /* FIXME - portability!!!! */
1266
1267 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1268 {
1269 if (!IS_INTRESOURCE(lpStr))
1270 {
1271 RtlInitUnicodeString(&Value,
1272 lpStr);
1273 }
1274 else
1275 Value.Buffer = lpStr;
1276
1277 dwNewLong = (LONG_PTR)&Value;
1278 }
1279 else if (nIndex == GCW_ATOM && lpStr != NULL)
1280 {
1281 if (!IS_ATOM(lpStr))
1282 {
1283 RtlInitUnicodeString(&Value,
1284 lpStr);
1285 }
1286 else
1287 Value.Buffer = lpStr;
1288
1289 dwNewLong = (LONG_PTR)&Value;
1290 }
1291
1292 return (DWORD)NtUserSetClassLong(hWnd,
1293 nIndex,
1294 dwNewLong,
1295 FALSE);
1296 }
1297
1298 #ifdef _WIN64
1299 /*
1300 * @unimplemented
1301 */
1302 ULONG_PTR
1303 WINAPI
1304 SetClassLongPtrA(HWND hWnd,
1305 INT nIndex,
1306 LONG_PTR dwNewLong)
1307 {
1308 UNIMPLEMENTED;
1309 return 0;
1310 }
1311
1312 /*
1313 * @unimplemented
1314 */
1315 ULONG_PTR
1316 WINAPI
1317 SetClassLongPtrW(HWND hWnd,
1318 INT nIndex,
1319 LONG_PTR dwNewLong)
1320 {
1321 UNIMPLEMENTED;
1322 return 0;
1323 }
1324 #endif // _WIN64
1325
1326 /*
1327 * @implemented
1328 */
1329 WORD
1330 WINAPI
1331 SetClassWord(
1332 HWND hWnd,
1333 int nIndex,
1334 WORD wNewWord)
1335 /*
1336 * NOTE: Obsoleted in 32-bit windows
1337 */
1338 {
1339 if ((nIndex < 0) && (nIndex != GCW_ATOM))
1340 return 0;
1341
1342 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1343 }
1344
1345 /*
1346 * @implemented
1347 */
1348 WORD
1349 WINAPI
1350 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1351 {
1352 switch(nIndex)
1353 {
1354 case GWLP_ID:
1355 case GWLP_HINSTANCE:
1356 case GWLP_HWNDPARENT:
1357 break;
1358 default:
1359 if (nIndex < 0)
1360 {
1361 WARN("Invalid offset %d\n", nIndex );
1362 SetLastError( ERROR_INVALID_INDEX );
1363 return 0;
1364 }
1365 break;
1366 }
1367 return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE );
1368 }
1369
1370 /*
1371 * @implemented
1372 */
1373 LONG
1374 WINAPI
1375 SetWindowLongA(
1376 HWND hWnd,
1377 int nIndex,
1378 LONG dwNewLong)
1379 {
1380 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1381 }
1382
1383 /*
1384 * @implemented
1385 */
1386 LONG
1387 WINAPI
1388 SetWindowLongW(
1389 HWND hWnd,
1390 int nIndex,
1391 LONG dwNewLong)
1392 {
1393 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1394 }
1395
1396 #ifdef _WIN64
1397 /*
1398 * @implemented
1399 */
1400 LONG_PTR
1401 WINAPI
1402 SetWindowLongPtrA(HWND hWnd,
1403 INT nIndex,
1404 LONG_PTR dwNewLong)
1405 {
1406 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1407 }
1408
1409 /*
1410 * @implemented
1411 */
1412 LONG_PTR
1413 WINAPI
1414 SetWindowLongPtrW(HWND hWnd,
1415 INT nIndex,
1416 LONG_PTR dwNewLong)
1417 {
1418 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1419 }
1420 #endif
1421
1422 /*
1423 * @implemented
1424 */
1425 BOOL
1426 WINAPI
1427 UnregisterClassA(
1428 LPCSTR lpClassName,
1429 HINSTANCE hInstance)
1430 {
1431 UNICODE_STRING ClassName = {0};
1432 BOOL Ret;
1433
1434 TRACE("class/atom: %s/%04x %p\n",
1435 IS_ATOM(lpClassName) ? NULL : lpClassName,
1436 IS_ATOM(lpClassName) ? lpClassName : 0,
1437 hInstance);
1438
1439 if (!IS_ATOM(lpClassName))
1440 {
1441 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
1442 lpClassName))
1443 {
1444 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1445 return 0;
1446 }
1447 }
1448 else
1449 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1450
1451 Ret = NtUserUnregisterClass(&ClassName,
1452 hInstance,
1453 0);
1454
1455 if (!IS_ATOM(lpClassName))
1456 RtlFreeUnicodeString(&ClassName);
1457
1458 return Ret;
1459 }
1460
1461
1462 /*
1463 * @implemented
1464 */
1465 BOOL
1466 WINAPI
1467 UnregisterClassW(
1468 LPCWSTR lpClassName,
1469 HINSTANCE hInstance)
1470 {
1471 UNICODE_STRING ClassName = {0};
1472
1473 TRACE("class/atom: %S/%04x %p\n",
1474 IS_ATOM(lpClassName) ? NULL : lpClassName,
1475 IS_ATOM(lpClassName) ? lpClassName : 0,
1476 hInstance);
1477
1478 if (!IS_ATOM(lpClassName))
1479 {
1480 RtlInitUnicodeString(&ClassName,
1481 lpClassName);
1482 }
1483 else
1484 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1485
1486 return NtUserUnregisterClass(&ClassName,
1487 hInstance,
1488 0);
1489 }
1490
1491 /* EOF */