Fix RtlQueryAtomInAtomTable and add regression tests
[reactos.git] / reactos / subsys / win32k / ntuser / class.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30
31 #include <w32k.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 /* FUNCTIONS *****************************************************************/
37
38 NTSTATUS FASTCALL
39 InitClassImpl(VOID)
40 {
41 return(STATUS_SUCCESS);
42 }
43
44 NTSTATUS FASTCALL
45 CleanupClassImpl(VOID)
46 {
47 return(STATUS_SUCCESS);
48 }
49
50 BOOL FASTCALL
51 ClassReferenceClassByAtom(
52 PWNDCLASS_OBJECT* Class,
53 RTL_ATOM Atom,
54 HINSTANCE hInstance)
55 {
56 PWNDCLASS_OBJECT Current, BestMatch = NULL;
57 PLIST_ENTRY CurrentEntry;
58 PW32PROCESS Process = PsGetWin32Process();
59
60 CurrentEntry = Process->ClassListHead.Flink;
61 while (CurrentEntry != &Process->ClassListHead)
62 {
63 Current = CONTAINING_RECORD(CurrentEntry, WNDCLASS_OBJECT, ListEntry);
64
65 if (Current->Atom == Atom && (hInstance == NULL || Current->hInstance == hInstance))
66 {
67 *Class = Current;
68 ObmReferenceObject(Current);
69 return TRUE;
70 }
71
72 if (Current->Atom == Atom && Current->Global)
73 BestMatch = Current;
74
75 CurrentEntry = CurrentEntry->Flink;
76 }
77
78 if (BestMatch != NULL)
79 {
80 *Class = BestMatch;
81 ObmReferenceObject(BestMatch);
82 return TRUE;
83 }
84
85 return FALSE;
86 }
87
88 BOOL FASTCALL
89 ClassReferenceClassByName(
90 PWNDCLASS_OBJECT *Class,
91 LPCWSTR ClassName,
92 HINSTANCE hInstance)
93 {
94 PWINSTATION_OBJECT WinStaObject;
95 NTSTATUS Status;
96 BOOL Found;
97 RTL_ATOM ClassAtom;
98
99 if (!ClassName || !PsGetWin32Thread()->Desktop)
100 return FALSE;
101
102 WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
103
104 Status = RtlLookupAtomInAtomTable(
105 WinStaObject->AtomTable,
106 (LPWSTR)ClassName,
107 &ClassAtom);
108
109 if (!NT_SUCCESS(Status))
110 {
111 DPRINT1("Failed to lookup class atom!\n");
112 return FALSE;
113 }
114
115 Found = ClassReferenceClassByAtom(Class, ClassAtom, hInstance);
116
117 return Found;
118 }
119
120 BOOL FASTCALL
121 ClassReferenceClassByNameOrAtom(
122 PWNDCLASS_OBJECT *Class,
123 LPCWSTR ClassNameOrAtom,
124 HINSTANCE hInstance)
125 {
126 BOOL Found;
127
128 if (IS_ATOM(ClassNameOrAtom))
129 Found = ClassReferenceClassByAtom(Class, (RTL_ATOM)((ULONG_PTR)ClassNameOrAtom), hInstance);
130 else
131 Found = ClassReferenceClassByName(Class, ClassNameOrAtom, hInstance);
132
133 return Found;
134 }
135
136 DWORD STDCALL
137 NtUserGetClassInfo(
138 HINSTANCE hInstance,
139 LPCWSTR lpClassName,
140 LPWNDCLASSEXW lpWndClassEx,
141 BOOL Ansi,
142 DWORD unknown3)
143 {
144 PWNDCLASS_OBJECT Class;
145 RTL_ATOM Atom;
146 DECLARE_RETURN(DWORD);
147
148 if (IS_ATOM(lpClassName))
149 DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName, hInstance);
150 else
151 DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName, hInstance);
152
153 UserEnterExclusive();
154
155 if (!ClassReferenceClassByNameOrAtom(&Class, lpClassName, hInstance))
156 {
157 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
158 RETURN(0);
159 }
160
161 lpWndClassEx->cbSize = sizeof(WNDCLASSEXW);
162 lpWndClassEx->style = Class->style;
163 if (Ansi)
164 lpWndClassEx->lpfnWndProc = Class->lpfnWndProcA;
165 else
166 lpWndClassEx->lpfnWndProc = Class->lpfnWndProcW;
167 lpWndClassEx->cbClsExtra = Class->cbClsExtra;
168 lpWndClassEx->cbWndExtra = Class->cbWndExtra;
169 /* This is not typo, we're really not going to use Class->hInstance here. */
170 lpWndClassEx->hInstance = hInstance;
171 lpWndClassEx->hIcon = Class->hIcon;
172 lpWndClassEx->hCursor = Class->hCursor;
173 lpWndClassEx->hbrBackground = Class->hbrBackground;
174 if (Class->lpszMenuName.MaximumLength)
175 RtlCopyUnicodeString((PUNICODE_STRING)lpWndClassEx->lpszMenuName, &Class->lpszMenuName);
176 else
177 lpWndClassEx->lpszMenuName = Class->lpszMenuName.Buffer;
178 lpWndClassEx->lpszClassName = lpClassName;
179 lpWndClassEx->hIconSm = Class->hIconSm;
180 Atom = Class->Atom;
181
182 ObmDereferenceObject(Class);
183
184 RETURN(Atom);
185
186 CLEANUP:
187 DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_);
188 UserLeave();
189 END_CLEANUP;
190 }
191
192 ULONG FASTCALL
193 IntGetClassName(struct _WINDOW_OBJECT *WindowObject, LPWSTR lpClassName,
194 ULONG nMaxCount)
195 {
196 ULONG Length;
197 LPWSTR Name;
198 PWINSTATION_OBJECT WinStaObject;
199 NTSTATUS Status;
200
201 if(!PsGetWin32Thread()->Desktop)
202 {
203 return 0;
204 }
205
206 WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
207
208 Length = 0;
209 Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,
210 WindowObject->Class->Atom, NULL, NULL,
211 NULL, &Length);
212 Length += sizeof(WCHAR);
213 Name = ExAllocatePoolWithTag(PagedPool, Length, TAG_STRING);
214 Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,
215 WindowObject->Class->Atom, NULL, NULL,
216 Name, &Length);
217 if (!NT_SUCCESS(Status))
218 {
219 DPRINT("IntGetClassName: RtlQueryAtomInAtomTable failed\n");
220 return 0;
221 }
222 Length /= sizeof(WCHAR);
223 if (Length > nMaxCount)
224 {
225 Length = nMaxCount;
226 }
227 wcsncpy(lpClassName, Name, Length);
228 /* FIXME: Check buffer size before doing this! */
229 *(lpClassName + Length) = 0;
230 ExFreePool(Name);
231
232 return Length;
233 }
234
235 DWORD STDCALL
236 NtUserGetClassName (
237 HWND hWnd,
238 LPWSTR lpClassName,
239 ULONG nMaxCount)
240 {
241 PWINDOW_OBJECT Window;
242 DECLARE_RETURN(DWORD);
243
244 UserEnterShared();
245 DPRINT("Enter NtUserGetClassName\n");
246
247 if (!(Window = UserGetWindowObject(hWnd)))
248 {
249 RETURN(0);
250 }
251
252 RETURN( IntGetClassName(Window, lpClassName, nMaxCount));
253
254 CLEANUP:
255 DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_);
256 UserLeave();
257 END_CLEANUP;
258 }
259
260 DWORD STDCALL
261 NtUserGetWOWClass(DWORD Unknown0,
262 DWORD Unknown1)
263 {
264 UNIMPLEMENTED;
265 return(0);
266 }
267
268 PWNDCLASS_OBJECT FASTCALL
269 IntCreateClass(
270 CONST WNDCLASSEXW *lpwcx,
271 DWORD Flags,
272 WNDPROC wpExtra,
273 PUNICODE_STRING MenuName,
274 RTL_ATOM Atom)
275 {
276 PWNDCLASS_OBJECT ClassObject;
277 ULONG objectSize;
278 BOOL Global;
279
280 Global = (Flags & REGISTERCLASS_SYSTEM) || (lpwcx->style & CS_GLOBALCLASS) ? TRUE : FALSE;
281
282 /* Check for double registration of the class. */
283 if (PsGetWin32Process() != NULL)
284 {
285 if (ClassReferenceClassByAtom(&ClassObject, Atom, lpwcx->hInstance))
286 {
287 /*
288 * NOTE: We may also get a global class from
289 * ClassReferenceClassByAtom. This simple check
290 * prevents that we fail valid request.
291 */
292 if (ClassObject->hInstance == lpwcx->hInstance)
293 {
294 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
295 ObmDereferenceObject(ClassObject);
296 return(NULL);
297 }
298 }
299 }
300
301 objectSize = sizeof(WNDCLASS_OBJECT) + lpwcx->cbClsExtra;
302 ClassObject = ObmCreateObject(&gHandleTable, NULL, otClass, objectSize);
303 if (ClassObject == 0)
304 {
305 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
306 return(NULL);
307 }
308
309 ClassObject->cbSize = lpwcx->cbSize;
310 ClassObject->style = lpwcx->style;
311 ClassObject->cbClsExtra = lpwcx->cbClsExtra;
312 ClassObject->cbWndExtra = lpwcx->cbWndExtra;
313 ClassObject->hInstance = lpwcx->hInstance;
314 ClassObject->hIcon = lpwcx->hIcon;
315 ClassObject->hCursor = lpwcx->hCursor;
316 ClassObject->hbrBackground = lpwcx->hbrBackground;
317 ClassObject->Unicode = !(Flags & REGISTERCLASS_ANSI);
318 ClassObject->Global = Global;
319 ClassObject->hIconSm = lpwcx->hIconSm;
320 ClassObject->Atom = Atom;
321 if (wpExtra == NULL)
322 {
323 if (Flags & REGISTERCLASS_ANSI)
324 {
325 ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
326 ClassObject->lpfnWndProcW = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,FALSE);
327 }
328 else
329 {
330 ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
331 ClassObject->lpfnWndProcA = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,TRUE);
332 }
333 }
334 else
335 {
336 if (Flags & REGISTERCLASS_ANSI)
337 {
338 ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
339 ClassObject->lpfnWndProcW = wpExtra;
340 }
341 else
342 {
343 ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
344 ClassObject->lpfnWndProcA = wpExtra;
345 }
346 }
347 if (MenuName->Length == 0)
348 {
349 ClassObject->lpszMenuName.Length =
350 ClassObject->lpszMenuName.MaximumLength = 0;
351 ClassObject->lpszMenuName.Buffer = MenuName->Buffer;
352 }
353 else
354 {
355 ClassObject->lpszMenuName.Length =
356 ClassObject->lpszMenuName.MaximumLength = MenuName->MaximumLength;
357 ClassObject->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, ClassObject->lpszMenuName.MaximumLength, TAG_STRING);
358 RtlCopyUnicodeString(&ClassObject->lpszMenuName, MenuName);
359 }
360 /* Extra class data */
361 if (ClassObject->cbClsExtra != 0)
362 {
363 ClassObject->ExtraData = (PCHAR)(ClassObject + 1);
364 RtlZeroMemory(ClassObject->ExtraData, (ULONG)ClassObject->cbClsExtra);
365 }
366 else
367 {
368 ClassObject->ExtraData = NULL;
369 }
370
371 InitializeListHead(&ClassObject->ClassWindowsListHead);
372
373 return(ClassObject);
374 }
375
376 RTL_ATOM STDCALL
377 NtUserRegisterClassExWOW(
378 CONST WNDCLASSEXW* lpwcx,
379 PUNICODE_STRING ClassName,
380 PUNICODE_STRING ClassNameCopy,
381 PUNICODE_STRING MenuName,
382 WNDPROC wpExtra, /* FIXME: Windows uses this parameter for something different. */
383 DWORD Flags,
384 DWORD Unknown7)
385
386 /*
387 * FUNCTION:
388 * Registers a new class with the window manager
389 * ARGUMENTS:
390 * lpwcx = Win32 extended window class structure
391 * bUnicodeClass = Whether to send ANSI or unicode strings
392 * to window procedures
393 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
394 * RETURNS:
395 * Atom identifying the new class
396 */
397 {
398 WNDCLASSEXW SafeClass;
399 PWINSTATION_OBJECT WinStaObject;
400 PWNDCLASS_OBJECT ClassObject;
401 NTSTATUS Status;
402 RTL_ATOM Atom;
403 DECLARE_RETURN(RTL_ATOM);
404
405 DPRINT("Enter NtUserRegisterClassExWOW\n");
406 UserEnterExclusive();
407
408 if (!lpwcx)
409 {
410 SetLastWin32Error(ERROR_INVALID_PARAMETER);
411 RETURN( (RTL_ATOM)0);
412 }
413
414 if (Flags & ~REGISTERCLASS_ALL)
415 {
416 SetLastWin32Error(ERROR_INVALID_FLAGS);
417 RETURN( (RTL_ATOM)0);
418 }
419
420 Status = MmCopyFromCaller(&SafeClass, lpwcx, sizeof(WNDCLASSEXW));
421 if (!NT_SUCCESS(Status))
422 {
423 SetLastNtError(Status);
424 RETURN( (RTL_ATOM)0);
425 }
426
427 /* Deny negative sizes */
428 if (lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0)
429 {
430 SetLastWin32Error(ERROR_INVALID_PARAMETER);
431 RETURN( (RTL_ATOM)0);
432 }
433
434 WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
435
436 if (ClassName->Length > 0)
437 {
438 DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName->Buffer);
439 /* FIXME - Safely copy/verify the buffer first!!! */
440 Status = RtlAddAtomToAtomTable(WinStaObject->AtomTable,
441 ClassName->Buffer,
442 &Atom);
443 if (!NT_SUCCESS(Status))
444 {
445 DPRINT1("Failed adding class name (%S) to atom table\n",
446 ClassName->Buffer);
447 SetLastNtError(Status);
448 RETURN((RTL_ATOM)0);
449 }
450 }
451 else
452 {
453 Atom = (RTL_ATOM)(ULONG)ClassName->Buffer;
454 }
455 ClassObject = IntCreateClass(&SafeClass, Flags, wpExtra, MenuName, Atom);
456 if (ClassObject == NULL)
457 {
458 if (ClassName->Length)
459 {
460 RtlDeleteAtomFromAtomTable(WinStaObject->AtomTable, Atom);
461 }
462 DPRINT("Failed creating window class object\n");
463 RETURN((RTL_ATOM)0);
464 }
465
466 InsertTailList(&PsGetWin32Process()->ClassListHead, &ClassObject->ListEntry);
467
468 RETURN(Atom);
469
470 CLEANUP:
471 DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_);
472 UserLeave();
473 END_CLEANUP;
474 }
475
476 ULONG FASTCALL
477 IntGetClassLong(struct _WINDOW_OBJECT *Window, ULONG Offset, BOOL Ansi)
478 {
479 LONG Ret;
480
481 if ((int)Offset >= 0)
482 {
483 DPRINT("GetClassLong(%x, %d)\n", Window->hSelf, Offset);
484 if ((Offset + sizeof(LONG)) > Window->Class->cbClsExtra)
485 {
486 SetLastWin32Error(ERROR_INVALID_PARAMETER);
487 return 0;
488 }
489 Ret = *((LONG *)(Window->Class->ExtraData + Offset));
490 DPRINT("Result: %x\n", Ret);
491 return Ret;
492 }
493
494 switch (Offset)
495 {
496 case GCL_CBWNDEXTRA:
497 Ret = Window->Class->cbWndExtra;
498 break;
499 case GCL_CBCLSEXTRA:
500 Ret = Window->Class->cbClsExtra;
501 break;
502 case GCL_HBRBACKGROUND:
503 Ret = (ULONG)Window->Class->hbrBackground;
504 break;
505 case GCL_HCURSOR:
506 Ret = (ULONG)Window->Class->hCursor;
507 break;
508 case GCL_HICON:
509 Ret = (ULONG)Window->Class->hIcon;
510 break;
511 case GCL_HICONSM:
512 Ret = (ULONG)Window->Class->hIconSm;
513 break;
514 case GCL_HMODULE:
515 Ret = (ULONG)Window->Class->hInstance;
516 break;
517 case GCL_MENUNAME:
518 Ret = (ULONG)Window->Class->lpszMenuName.Buffer;
519 break;
520 case GCL_STYLE:
521 Ret = Window->Class->style;
522 break;
523 case GCL_WNDPROC:
524 if (Ansi)
525 {
526 Ret = (ULONG)Window->Class->lpfnWndProcA;
527 }
528 else
529 {
530 Ret = (ULONG)Window->Class->lpfnWndProcW;
531 }
532 break;
533 case GCW_ATOM:
534 Ret = Window->Class->Atom;
535 break;
536 default:
537 Ret = 0;
538 break;
539 }
540 return(Ret);
541 }
542
543 DWORD STDCALL
544 NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
545 {
546 PWINDOW_OBJECT Window;
547 DECLARE_RETURN(DWORD);
548
549 DPRINT("Enter NtUserGetClassLong\n");
550 UserEnterExclusive();
551
552 if (!(Window = UserGetWindowObject(hWnd)))
553 {
554 RETURN(0);
555 }
556
557 RETURN(IntGetClassLong(Window, Offset, Ansi));
558
559 CLEANUP:
560 DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_);
561 UserLeave();
562 END_CLEANUP;
563 }
564
565 void FASTCALL
566 co_IntSetClassLong(PWINDOW_OBJECT Window, ULONG Offset, LONG dwNewLong, BOOL Ansi)
567 {
568 ASSERT_REFS_CO(Window);
569
570 if ((int)Offset >= 0)
571 {
572 DPRINT("SetClassLong(%x, %d, %x)\n", Window->hSelf, Offset, dwNewLong);
573 if ((Offset + sizeof(LONG)) > Window->Class->cbClsExtra)
574 {
575 SetLastWin32Error(ERROR_INVALID_PARAMETER);
576 return;
577 }
578 *((LONG *)(Window->Class->ExtraData + Offset)) = dwNewLong;
579 return;
580 }
581
582 switch (Offset)
583 {
584 case GCL_CBWNDEXTRA:
585 Window->Class->cbWndExtra = dwNewLong;
586 break;
587 case GCL_CBCLSEXTRA:
588 Window->Class->cbClsExtra = dwNewLong;
589 break;
590 case GCL_HBRBACKGROUND:
591 Window->Class->hbrBackground = (HBRUSH)dwNewLong;
592 break;
593 case GCL_HCURSOR:
594 Window->Class->hCursor = (HCURSOR)dwNewLong;
595 break;
596 case GCL_HICON:
597 Window->Class->hIcon = (HICON)dwNewLong;
598
599 if (!IntGetOwner(Window) && !IntGetParent(Window))
600 {
601 co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) Window->hSelf);
602 }
603 break;
604 case GCL_HICONSM:
605 Window->Class->hIconSm = (HICON)dwNewLong;
606 break;
607 case GCL_HMODULE:
608 Window->Class->hInstance = (HINSTANCE)dwNewLong;
609 break;
610 case GCL_MENUNAME:
611 if (Window->Class->lpszMenuName.MaximumLength)
612 RtlFreeUnicodeString(&Window->Class->lpszMenuName);
613 if (!IS_INTRESOURCE(dwNewLong))
614 {
615 Window->Class->lpszMenuName.Length =
616 Window->Class->lpszMenuName.MaximumLength = ((PUNICODE_STRING)dwNewLong)->MaximumLength;
617 Window->Class->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, Window->Class->lpszMenuName.MaximumLength, TAG_STRING);
618 RtlCopyUnicodeString(&Window->Class->lpszMenuName, (PUNICODE_STRING)dwNewLong);
619 }
620 else
621 {
622 Window->Class->lpszMenuName.Length =
623 Window->Class->lpszMenuName.MaximumLength = 0;
624 Window->Class->lpszMenuName.Buffer = (LPWSTR)dwNewLong;
625 }
626 break;
627 case GCL_STYLE:
628 Window->Class->style = dwNewLong;
629 break;
630 case GCL_WNDPROC:
631 if (Ansi)
632 {
633 Window->Class->lpfnWndProcA = (WNDPROC)dwNewLong;
634 Window->Class->lpfnWndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,FALSE);
635 Window->Class->Unicode = FALSE;
636 }
637 else
638 {
639 Window->Class->lpfnWndProcW = (WNDPROC)dwNewLong;
640 Window->Class->lpfnWndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,TRUE);
641 Window->Class->Unicode = TRUE;
642 }
643 break;
644 }
645 }
646
647 DWORD STDCALL
648 NtUserSetClassLong(HWND hWnd,
649 DWORD Offset,
650 LONG dwNewLong,
651 BOOL Ansi)
652 {
653 PWINDOW_OBJECT Window;
654 LONG Ret;
655 DECLARE_RETURN(DWORD);
656
657 DPRINT("Enter NtUserSetClassLong\n");
658 UserEnterExclusive();
659
660 if (!(Window = UserGetWindowObject(hWnd)))
661 {
662 RETURN(0);
663 }
664
665 UserRefObjectCo(Window);
666
667 Ret = IntGetClassLong(Window, Offset, Ansi);
668 co_IntSetClassLong(Window, Offset, dwNewLong, Ansi);
669
670 UserDerefObjectCo(Window);
671
672 RETURN(Ret);
673
674 CLEANUP:
675 DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_);
676 UserLeave();
677 END_CLEANUP;
678 }
679
680 DWORD STDCALL
681 NtUserSetClassWord(DWORD Unknown0,
682 DWORD Unknown1,
683 DWORD Unknown2)
684 {
685 UNIMPLEMENTED;
686 return(0);
687 }
688
689 BOOL STDCALL
690 NtUserUnregisterClass(
691 LPCWSTR ClassNameOrAtom,
692 HINSTANCE hInstance,
693 DWORD Unknown)
694 {
695 PWNDCLASS_OBJECT Class;
696 PWINSTATION_OBJECT WinSta;
697 DECLARE_RETURN(BOOL);
698
699 DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom);
700 UserEnterExclusive();
701
702 if (!ClassNameOrAtom || !PsGetWin32Thread()->Desktop)
703 {
704 SetLastWin32Error(ERROR_INVALID_PARAMETER);
705 RETURN( FALSE);
706 }
707
708 WinSta = PsGetWin32Thread()->Desktop->WindowStation;
709
710 if (!ClassReferenceClassByNameOrAtom(&Class, ClassNameOrAtom, hInstance))
711 {
712 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
713 RETURN( FALSE);
714 }
715
716 if (Class->hInstance && Class->hInstance != hInstance)
717 {
718 ClassDereferenceObject(Class);
719 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
720 RETURN( FALSE);
721 }
722
723 if (!IsListEmpty(&Class->ClassWindowsListHead))
724 {
725 /* Dereference the ClassReferenceClassByNameOrAtom() call */
726 ObmDereferenceObject(Class);
727 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
728 RETURN( FALSE);
729 }
730
731 /* Dereference the ClassReferenceClassByNameOrAtom() call */
732 ClassDereferenceObject(Class);
733
734 RemoveEntryList(&Class->ListEntry);
735
736 RtlDeleteAtomFromAtomTable(WinSta->AtomTable, Class->Atom);
737
738 /* Free the object */
739 ClassDereferenceObject(Class);
740
741 RETURN( TRUE);
742
743 CLEANUP:
744 DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_);
745 UserLeave();
746 END_CLEANUP;
747 }
748
749 /* EOF */