- Fixed Window Class menu handling that I broke with my last patch.
[reactos.git] / reactos / lib / user32 / windows / class.c
1 /* $Id: class.c,v 1.49 2004/05/17 16:38:57 navaraf Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS user32.dll
5 * FILE: lib/user32/windows/class.c
6 * PURPOSE: Window classes
7 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * UPDATE HISTORY:
9 * 09-05-2001 CSH Created
10 */
11 #include <windows.h>
12 #include <user32.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <debug.h>
16 #include <window.h>
17 #include <strpool.h>
18 #include <user32/regcontrol.h>
19 #define NTOS_MODE_USER
20 #include <ntos.h>
21
22
23
24 static BOOL GetClassInfoExCommon(
25 HINSTANCE hInst,
26 LPCWSTR lpszClass,
27 LPWNDCLASSEXW lpwcx,
28 BOOL unicode)
29 {
30 LPWSTR str;
31 UNICODE_STRING str2, str3;
32 WNDCLASSEXW w;
33 BOOL retval;
34 NTSTATUS Status;
35
36 if ( !lpszClass || !lpwcx )
37 {
38 SetLastError(ERROR_INVALID_PARAMETER);
39 return FALSE;
40 }
41
42 if(IS_ATOM(lpszClass))
43 str = (LPWSTR)lpszClass;
44 else
45 {
46 extern BOOL ControlsInitialized;
47
48 if (unicode)
49 {
50 str = HEAP_strdupW ( lpszClass, wcslen(lpszClass) );
51
52 if ( !str )
53 {
54 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
55 return FALSE;
56 }
57 }
58
59 else
60 {
61 Status = HEAP_strdupAtoW(&str, (LPCSTR)lpszClass, NULL);
62
63 if (! NT_SUCCESS(Status))
64 {
65 SetLastError(RtlNtStatusToDosError(Status));
66 return FALSE;
67 }
68 }
69
70 /* Register built-in controls if not already done */
71 if ( !ControlsInitialized )
72 {
73 ControlsInitialized = ControlsInit(str);
74 }
75 }
76
77 str2.Length = str3.Length = 0;
78 str2.MaximumLength = str3.MaximumLength = 255;
79 str2.Buffer = (PWSTR)HEAP_alloc ( str2.MaximumLength * sizeof(WCHAR) );
80 if ( !str2.Buffer )
81 {
82 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
83 if ( !IS_ATOM(str) )
84 HEAP_free ( str );
85 return FALSE;
86 }
87
88 str3.Buffer = (PWSTR)HEAP_alloc ( str3.MaximumLength * sizeof(WCHAR) );
89 if ( !str3.Buffer )
90 {
91 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
92 if ( !IS_ATOM(str) )
93 HEAP_free ( str );
94 return FALSE;
95 }
96
97 w.lpszMenuName = (LPCWSTR)&str2;
98 w.lpszClassName = (LPCWSTR)&str3;
99 retval = (BOOL)NtUserGetClassInfo(hInst, str, &w, TRUE, 0);
100 if ( !IS_ATOM(str) )
101 HEAP_free(str);
102
103 RtlCopyMemory ( lpwcx, &w, sizeof(WNDCLASSEXW) );
104
105 if ( !IS_INTRESOURCE(w.lpszMenuName) && w.lpszMenuName )
106 {
107 if (unicode)
108 lpwcx->lpszMenuName = heap_string_poolW ( str2.Buffer, str2.Length );
109 else
110 ((LPWNDCLASSEXA) lpwcx)->lpszMenuName = heap_string_poolA ( str2.Buffer, str2.Length );
111 }
112
113 if ( !IS_ATOM(w.lpszClassName) && w.lpszClassName )
114 {
115 if (unicode)
116 lpwcx->lpszClassName = heap_string_poolW ( str3.Buffer, str3.Length );
117 else
118 ((LPWNDCLASSEXA) lpwcx)->lpszClassName = heap_string_poolA ( str3.Buffer, str3.Length );
119 }
120
121 HEAP_free ( str2.Buffer );
122 HEAP_free ( str3.Buffer );
123
124 return retval;
125 }
126
127
128 /*
129 * @implemented
130 */
131 BOOL
132 STDCALL
133 GetClassInfoExA(
134 HINSTANCE hinst,
135 LPCSTR lpszClass,
136 LPWNDCLASSEXA lpwcx)
137 {
138 return GetClassInfoExCommon(hinst, (LPWSTR)lpszClass, (LPWNDCLASSEXW)lpwcx, FALSE);
139 }
140
141
142 /*
143 * @implemented
144 */
145 BOOL
146 STDCALL
147 GetClassInfoExW(
148 HINSTANCE hinst,
149 LPCWSTR lpszClass,
150 LPWNDCLASSEXW lpwcx)
151 {
152 return GetClassInfoExCommon(hinst, lpszClass, lpwcx, TRUE);
153 }
154
155
156 /*
157 * @implemented
158 */
159 BOOL
160 STDCALL
161 GetClassInfoA(
162 HINSTANCE hInstance,
163 LPCSTR lpClassName,
164 LPWNDCLASSA lpWndClass)
165 {
166 WNDCLASSEXA w;
167 BOOL retval;
168
169 if ( !lpClassName || !lpWndClass )
170 {
171 SetLastError(ERROR_INVALID_PARAMETER);
172 return FALSE;
173 }
174
175 retval = GetClassInfoExA(hInstance,lpClassName,&w);
176 RtlCopyMemory ( lpWndClass, &w.style, sizeof(WNDCLASSA) );
177 return retval;
178 }
179
180 /*
181 * @implemented
182 */
183 BOOL
184 STDCALL
185 GetClassInfoW(
186 HINSTANCE hInstance,
187 LPCWSTR lpClassName,
188 LPWNDCLASSW lpWndClass)
189 {
190 WNDCLASSEXW w;
191 BOOL retval;
192
193 if(!lpClassName || !lpWndClass)
194 {
195 SetLastError(ERROR_INVALID_PARAMETER);
196 return FALSE;
197 }
198
199 retval = GetClassInfoExW(hInstance,lpClassName,&w);
200 RtlCopyMemory (lpWndClass,&w.style,sizeof(WNDCLASSW));
201 return retval;
202 }
203
204
205 /*
206 * @implemented
207 */
208 DWORD STDCALL
209 GetClassLongA(HWND hWnd, int nIndex)
210 {
211 switch (nIndex)
212 {
213 case GCL_HBRBACKGROUND:
214 {
215 DWORD hBrush = NtUserGetClassLong(hWnd, GCL_HBRBACKGROUND, TRUE);
216 if (hBrush != 0 && hBrush < 0x4000)
217 hBrush = (DWORD)GetSysColorBrush((ULONG)hBrush - 1);
218 return hBrush;
219 }
220
221 case GCL_MENUNAME:
222 {
223 PUNICODE_STRING Name;
224 Name = (PUNICODE_STRING)NtUserGetClassLong(hWnd, nIndex, TRUE);
225 if (IS_INTRESOURCE(Name))
226 return (DWORD)Name;
227 else
228 return (DWORD)heap_string_poolA(Name->Buffer, Name->Length);
229 }
230
231 default:
232 return NtUserGetClassLong(hWnd, nIndex, TRUE);
233 }
234 }
235
236 /*
237 * @implemented
238 */
239 DWORD STDCALL
240 GetClassLongW ( HWND hWnd, int nIndex )
241 {
242 switch (nIndex)
243 {
244 case GCL_HBRBACKGROUND:
245 {
246 DWORD hBrush = NtUserGetClassLong(hWnd, GCL_HBRBACKGROUND, TRUE);
247 if (hBrush != 0 && hBrush < 0x4000)
248 hBrush = (DWORD)GetSysColorBrush((ULONG)hBrush - 1);
249 return hBrush;
250 }
251
252 case GCL_MENUNAME:
253 {
254 PUNICODE_STRING Name;
255 Name = (PUNICODE_STRING)NtUserGetClassLong(hWnd, nIndex, FALSE);
256 if (IS_INTRESOURCE(Name))
257 return (DWORD)Name;
258 else
259 return (DWORD)heap_string_poolW(Name->Buffer, Name->Length);
260 }
261
262 default:
263 return NtUserGetClassLong(hWnd, nIndex, FALSE);
264 }
265 }
266
267
268 /*
269 * @implemented
270 */
271 int STDCALL
272 GetClassNameA(
273 HWND hWnd,
274 LPSTR lpClassName,
275 int nMaxCount)
276 {
277 int result;
278 LPWSTR ClassNameW;
279 NTSTATUS Status;
280
281 if(!lpClassName)
282 return 0;
283
284 ClassNameW = HEAP_alloc ( (nMaxCount+1)*sizeof(WCHAR) );
285
286 result = NtUserGetClassName ( hWnd, ClassNameW, nMaxCount );
287
288 Status = HEAP_strcpyWtoA ( lpClassName, ClassNameW, result );
289
290 HEAP_free ( ClassNameW );
291
292 if ( !NT_SUCCESS(Status) )
293 return 0;
294
295 return result;
296 }
297
298
299 /*
300 * @implemented
301 */
302 int
303 STDCALL
304 GetClassNameW(
305 HWND hWnd,
306 LPWSTR lpClassName,
307 int nMaxCount)
308 {
309 return NtUserGetClassName(hWnd, lpClassName, nMaxCount);
310 }
311
312
313 /*
314 * @implemented
315 */
316 WORD
317 STDCALL
318 GetClassWord(
319 HWND hWnd,
320 int nIndex)
321 /*
322 * NOTE: Obsoleted in 32-bit windows
323 */
324 {
325 if ((nIndex < 0) && (nIndex != GCW_ATOM))
326 return 0;
327
328 return (WORD) NtUserGetClassLong ( hWnd, nIndex, TRUE );
329 }
330
331
332 /*
333 * @implemented
334 */
335 LONG
336 STDCALL
337 GetWindowLongA ( HWND hWnd, int nIndex )
338 {
339 return NtUserGetWindowLong(hWnd, nIndex, TRUE);
340 }
341
342
343 /*
344 * @implemented
345 */
346 LONG
347 STDCALL
348 GetWindowLongW(HWND hWnd, int nIndex)
349 {
350 return NtUserGetWindowLong(hWnd, nIndex, FALSE);
351 }
352
353 /*
354 * @implemented
355 */
356 WORD
357 STDCALL
358 GetWindowWord(HWND hWnd, int nIndex)
359 {
360 return (WORD)NtUserGetWindowLong(hWnd, nIndex, TRUE);
361 }
362
363 /*
364 * @implemented
365 */
366 WORD
367 STDCALL
368 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
369 {
370 return (WORD)NtUserSetWindowLong ( hWnd, nIndex, (LONG)wNewWord, TRUE );
371 }
372
373 /*
374 * @implemented
375 */
376 UINT
377 STDCALL
378 RealGetWindowClassW(
379 HWND hwnd,
380 LPWSTR pszType,
381 UINT cchType)
382 {
383 /* FIXME: Implement correct functionality of RealGetWindowClass */
384 return GetClassNameW(hwnd,pszType,cchType);
385 }
386
387
388 /*
389 * @implemented
390 */
391 UINT
392 STDCALL
393 RealGetWindowClassA(
394 HWND hwnd,
395 LPSTR pszType,
396 UINT cchType)
397 {
398 /* FIXME: Implement correct functionality of RealGetWindowClass */
399 return GetClassNameA(hwnd,pszType,cchType);
400 }
401
402 /*
403 * @implemented
404 */
405 ATOM STDCALL
406 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
407 {
408 RTL_ATOM Atom;
409 WNDCLASSEXA WndClass;
410 UNICODE_STRING ClassName;
411 UNICODE_STRING MenuName;
412
413 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
414 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
415 lpwcx->lpszClassName == NULL)
416 {
417 SetLastError(ERROR_INVALID_PARAMETER);
418 return 0;
419 }
420
421 /*
422 * On real Windows this looks more like:
423 * if (lpwcx->hInstance == User32Instance &&
424 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
425 * But since I have no idea what the magic field in the
426 * TEB structure means, I rather decided to omit that.
427 * -- Filip Navara
428 */
429 if (lpwcx->hInstance == User32Instance)
430 {
431 SetLastError(ERROR_INVALID_PARAMETER);
432 return 0;
433 }
434
435 /* Yes, this is correct. We should modify the passed structure. */
436 if (lpwcx->hInstance == NULL)
437 ((WNDCLASSEXA*)lpwcx)->hInstance = GetModuleHandleW(NULL);
438
439 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
440
441 if (IS_ATOM(lpwcx->lpszMenuName))
442 {
443 MenuName.Length =
444 MenuName.MaximumLength = 0;
445 MenuName.Buffer = (LPWSTR)lpwcx->lpszMenuName;
446 } else
447 {
448 RtlCreateUnicodeStringFromAsciiz(&MenuName, lpwcx->lpszMenuName);
449 }
450
451 if (IS_ATOM(lpwcx->lpszClassName))
452 {
453 ClassName.Length =
454 ClassName.MaximumLength = 0;
455 ClassName.Buffer = (LPWSTR)lpwcx->lpszClassName;
456 } else
457 {
458 RtlCreateUnicodeStringFromAsciiz(&ClassName, lpwcx->lpszClassName);
459 }
460
461 Atom = NtUserRegisterClassExWOW(
462 (WNDCLASSEXW*)&WndClass,
463 &ClassName,
464 &ClassName,
465 &MenuName,
466 NULL,
467 REGISTERCLASS_ANSI,
468 0);
469
470 RtlFreeUnicodeString(&MenuName);
471 RtlFreeUnicodeString(&ClassName);
472
473 return (ATOM)Atom;
474 }
475
476 /*
477 * @implemented
478 */
479 ATOM STDCALL
480 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
481 {
482 WNDCLASSEXW WndClass;
483 UNICODE_STRING ClassName;
484 UNICODE_STRING MenuName;
485
486 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
487 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
488 lpwcx->lpszClassName == NULL)
489 {
490 SetLastError(ERROR_INVALID_PARAMETER);
491 return 0;
492 }
493
494 /*
495 * On real Windows this looks more like:
496 * if (lpwcx->hInstance == User32Instance &&
497 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
498 * But since I have no idea what the magic field in the
499 * TEB structure means, I rather decided to omit that.
500 * -- Filip Navara
501 */
502 if (lpwcx->hInstance == User32Instance)
503 {
504 SetLastError(ERROR_INVALID_PARAMETER);
505 return 0;
506 }
507
508 /* Yes, this is correct. We should modify the passed structure. */
509 if (lpwcx->hInstance == NULL)
510 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
511
512 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
513
514 if (IS_ATOM(lpwcx->lpszMenuName))
515 {
516 MenuName.Length =
517 MenuName.MaximumLength = 0;
518 MenuName.Buffer = (LPWSTR)lpwcx->lpszMenuName;
519 } else
520 {
521 RtlInitUnicodeString(&MenuName, lpwcx->lpszMenuName);
522 }
523
524 if (IS_ATOM(lpwcx->lpszClassName))
525 {
526 ClassName.Length =
527 ClassName.MaximumLength = 0;
528 ClassName.Buffer = (LPWSTR)lpwcx->lpszClassName;
529 } else
530 {
531 RtlInitUnicodeString(&ClassName, lpwcx->lpszClassName);
532 }
533
534 return (ATOM)NtUserRegisterClassExWOW(
535 &WndClass,
536 &ClassName,
537 &ClassName,
538 &MenuName,
539 NULL,
540 0,
541 0);
542 }
543
544 /*
545 * @implemented
546 */
547 ATOM STDCALL
548 RegisterClassA(CONST WNDCLASSA *lpWndClass)
549 {
550 WNDCLASSEXA Class;
551
552 if (lpWndClass == NULL)
553 return 0;
554
555 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
556 Class.cbSize = sizeof(WNDCLASSEXA);
557 Class.hIconSm = NULL;
558
559 return RegisterClassExA(&Class);
560 }
561
562 /*
563 * @implemented
564 */
565 ATOM STDCALL
566 RegisterClassW(CONST WNDCLASSW *lpWndClass)
567 {
568 WNDCLASSEXW Class;
569
570 if (lpWndClass == NULL)
571 return 0;
572
573 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
574 Class.cbSize = sizeof(WNDCLASSEXW);
575 Class.hIconSm = NULL;
576
577 return RegisterClassExW(&Class);
578 }
579
580 /*
581 * @implemented
582 */
583 DWORD
584 STDCALL
585 SetClassLongA (
586 HWND hWnd,
587 int nIndex,
588 LONG dwNewLong)
589 {
590 PUNICODE_STRING str;
591 PUNICODE_STRING str2;
592
593 if ( nIndex != GCL_MENUNAME )
594 {
595 return NtUserSetClassLong ( hWnd, nIndex, dwNewLong, TRUE );
596 }
597 if ( IS_INTRESOURCE(dwNewLong) )
598 {
599 str2 = (PUNICODE_STRING)dwNewLong;
600 }
601 else
602 {
603 RtlCreateUnicodeString ( str2, (LPWSTR)dwNewLong );
604 }
605
606 str = (PUNICODE_STRING)NtUserSetClassLong(hWnd, nIndex, (DWORD)str2, TRUE);
607
608 if ( !IS_INTRESOURCE(dwNewLong) )
609 {
610 RtlFreeUnicodeString ( str2 );
611 }
612 if ( IS_INTRESOURCE(str) )
613 {
614 return (DWORD)str;
615 }
616 else
617 {
618 return (DWORD)heap_string_poolA ( str->Buffer, str->Length );
619 }
620 }
621
622
623 /*
624 * @implemented
625 */
626 DWORD
627 STDCALL
628 SetClassLongW(
629 HWND hWnd,
630 int nIndex,
631 LONG dwNewLong)
632 {
633 PUNICODE_STRING str;
634 PUNICODE_STRING str2;
635
636 if (nIndex != GCL_MENUNAME )
637 {
638 return NtUserSetClassLong ( hWnd, nIndex, dwNewLong, FALSE );
639 }
640 if ( IS_INTRESOURCE(dwNewLong) )
641 {
642 str2 = (PUNICODE_STRING)dwNewLong;
643 }
644 else
645 {
646 RtlCreateUnicodeStringFromAsciiz ( str2,(LPSTR)dwNewLong );
647 }
648
649 str = (PUNICODE_STRING)NtUserSetClassLong(hWnd, nIndex, (DWORD)str2, TRUE);
650
651 if ( !IS_INTRESOURCE(dwNewLong) )
652 {
653 RtlFreeUnicodeString(str2);
654 }
655 if ( IS_INTRESOURCE(str) )
656 {
657 return (DWORD)str;
658 }
659 else
660 {
661 return (DWORD)heap_string_poolW ( str->Buffer, str->Length );
662 }
663 }
664
665
666 /*
667 * @implemented
668 */
669 WORD
670 STDCALL
671 SetClassWord(
672 HWND hWnd,
673 int nIndex,
674 WORD wNewWord)
675 /*
676 * NOTE: Obsoleted in 32-bit windows
677 */
678 {
679 if ((nIndex < 0) && (nIndex != GCW_ATOM))
680 return 0;
681
682 return (WORD) NtUserSetClassLong ( hWnd, nIndex, wNewWord, TRUE );
683 }
684
685
686 /*
687 * @implemented
688 */
689 LONG
690 STDCALL
691 SetWindowLongA(
692 HWND hWnd,
693 int nIndex,
694 LONG dwNewLong)
695 {
696 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
697 }
698
699
700 /*
701 * @implemented
702 */
703 LONG
704 STDCALL
705 SetWindowLongW(
706 HWND hWnd,
707 int nIndex,
708 LONG dwNewLong)
709 {
710 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
711 }
712
713
714 /*
715 * @implemented
716 */
717 BOOL
718 STDCALL
719 UnregisterClassA(
720 LPCSTR lpClassName,
721 HINSTANCE hInstance)
722 {
723 LPWSTR ClassName;
724 NTSTATUS Status;
725 BOOL Result;
726
727 if(!IS_ATOM(lpClassName))
728 {
729 Status = HEAP_strdupAtoW(&ClassName, lpClassName, NULL);
730 if(!NT_SUCCESS(Status))
731 {
732 SetLastError(RtlNtStatusToDosError(Status));
733 return FALSE;
734 }
735 }
736 else
737 ClassName = (LPWSTR)lpClassName;
738
739 Result = (BOOL)NtUserUnregisterClass((LPCWSTR)ClassName, hInstance, 0);
740
741 if(ClassName && !IS_ATOM(lpClassName))
742 HEAP_free(ClassName);
743
744 return Result;
745 }
746
747
748 /*
749 * @implemented
750 */
751 BOOL
752 STDCALL
753 UnregisterClassW(
754 LPCWSTR lpClassName,
755 HINSTANCE hInstance)
756 {
757 return (BOOL)NtUserUnregisterClass(lpClassName, hInstance, 0);
758 }
759
760 /* EOF */