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