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