2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/atom.c
5 * PURPOSE: Executive Atom Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
16 #define TAG_ATOM TAG('A', 't', 'o', 'm')
18 /* GLOBALS ****************************************************************/
21 * FIXME: this is WRONG! The global atom table should live in the WinSta struct
22 * and accessed through a win32k callout (received in PsEstablishWin32Callouts)
23 * NOTE: There is a session/win32k global atom table also, but its private to
24 * win32k. Its used for RegisterWindowMessage() and for window classes.
27 PRTL_ATOM_TABLE GlobalAtomTable
;
29 /* PRIVATE FUNCTIONS *********************************************************/
32 * @name ExpGetGlobalAtomTable
34 * Gets pointer to a global atom table, creates it if not already created
36 * @return Pointer to the RTL_ATOM_TABLE, or NULL if it's impossible
37 * to create atom table
39 * @remarks Internal function
44 ExpGetGlobalAtomTable(VOID
)
48 /* Return it if we have one */
49 if (GlobalAtomTable
) return GlobalAtomTable
;
52 Status
= RtlCreateAtomTable(37, &GlobalAtomTable
);
54 /* If we couldn't create it, return NULL */
55 if (!NT_SUCCESS(Status
)) return NULL
;
57 /* Return the newly created one */
58 return GlobalAtomTable
;
61 /* FUNCTIONS ****************************************************************/
67 * Function NtAddAtom creates new Atom in Global Atom Table. If Atom
68 * with the same name already exist, internal Atom counter is incremented.
69 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtAddAtom.html
72 * Atom name in Unicode
74 * @param AtomNameLength
75 * Length of the atom name
80 * @return STATUS_SUCCESS in case of success, proper error code
88 NtAddAtom(IN PWSTR AtomName
,
89 IN ULONG AtomNameLength
,
92 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
93 NTSTATUS Status
= STATUS_SUCCESS
;
94 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
95 LPWSTR CapturedName
= NULL
;
100 /* Check for the table */
101 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
103 /* Check for valid name */
104 if (AtomNameLength
> (RTL_MAXIMUM_ATOM_LENGTH
* sizeof(WCHAR
)))
107 DPRINT1("Atom name too long\n");
108 return STATUS_INVALID_PARAMETER
;
111 /* Check if we're called from user-mode*/
112 if (PreviousMode
!= KernelMode
)
117 /* Check if we have a name */
121 ProbeForRead(AtomName
, AtomNameLength
, sizeof(WCHAR
));
123 /* Allocate an aligned buffer + the null char */
124 CapturedSize
= ((AtomNameLength
+ sizeof(WCHAR
)) &~
126 CapturedName
= ExAllocatePoolWithTag(PagedPool
,
132 Status
= STATUS_INSUFFICIENT_RESOURCES
;
136 /* Copy the name and null-terminate it */
137 RtlCopyMemory(CapturedName
, AtomName
, AtomNameLength
);
138 CapturedName
[AtomNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
141 /* Probe the atom too */
142 if (Atom
) ProbeForWriteUshort(Atom
);
145 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
147 Status
= _SEH_GetExceptionCode();
153 /* Simplify code and re-use one variable */
154 if (AtomName
) CapturedName
= AtomName
;
157 /* Make sure probe worked */
158 if (NT_SUCCESS(Status
))
160 /* Call the runtime function */
161 Status
= RtlAddAtomToAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
162 if (NT_SUCCESS(Status
) && (Atom
))
164 /* Success and caller wants the atom back.. .enter SEH */
167 /* Return the atom */
170 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
172 Status
= _SEH_GetExceptionCode();
178 /* If we captured anything, free it */
179 if ((CapturedName
) && (CapturedName
!= AtomName
)) ExFreePool(CapturedName
);
181 /* Return to caller */
189 * Removes Atom from Global Atom Table. If Atom's reference counter
190 * is greater then 1, function decrements this counter, but Atom
191 * stayed in Global Atom Table.
192 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html
197 * @return STATUS_SUCCESS in case of success, proper error code
205 NtDeleteAtom(IN RTL_ATOM Atom
)
207 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
210 /* Check for valid table */
211 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
213 /* Call worker function */
214 return RtlDeleteAtomFromAtomTable(AtomTable
, Atom
);
221 * Retrieves existing Atom's identifier without incrementing Atom's
223 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html
226 * Atom name in Unicode
228 * @param AtomNameLength
229 * Length of the atom name
232 * Pointer to RTL_ATOM
234 * @return STATUS_SUCCESS in case of success, proper error code
242 NtFindAtom(IN PWSTR AtomName
,
243 IN ULONG AtomNameLength
,
246 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
247 NTSTATUS Status
= STATUS_SUCCESS
;
248 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
249 LPWSTR CapturedName
= NULL
;
254 /* Check for the table */
255 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
257 /* Check for valid name */
258 if (AtomNameLength
> (RTL_MAXIMUM_ATOM_LENGTH
* sizeof(WCHAR
)))
261 DPRINT1("Atom name too long\n");
262 return STATUS_INVALID_PARAMETER
;
265 /* Check if we're called from user-mode*/
266 if (PreviousMode
!= KernelMode
)
271 /* Check if we have a name */
275 ProbeForRead(AtomName
, AtomNameLength
, sizeof(WCHAR
));
277 /* Allocate an aligned buffer + the null char */
278 CapturedSize
= ((AtomNameLength
+ sizeof(WCHAR
)) &~
280 CapturedName
= ExAllocatePoolWithTag(PagedPool
,
286 Status
= STATUS_INSUFFICIENT_RESOURCES
;
290 /* Copy the name and null-terminate it */
291 RtlCopyMemory(CapturedName
, AtomName
, AtomNameLength
);
292 CapturedName
[AtomNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
295 /* Probe the atom too */
296 if (Atom
) ProbeForWriteUshort(Atom
);
299 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
301 Status
= _SEH_GetExceptionCode();
307 /* Simplify code and re-use one variable */
308 if (AtomName
) CapturedName
= AtomName
;
311 /* Make sure probe worked */
312 if (NT_SUCCESS(Status
))
314 /* Call the runtime function */
315 Status
= RtlLookupAtomInAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
316 if (NT_SUCCESS(Status
) && (Atom
))
318 /* Success and caller wants the atom back.. .enter SEH */
321 /* Return the atom */
324 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
326 Status
= _SEH_GetExceptionCode();
332 /* If we captured anything, free it */
333 if ((CapturedName
) && (CapturedName
!= AtomName
)) ExFreePool(CapturedName
);
335 /* Return to caller */
340 * @name NtQueryInformationAtom
343 * Gets single Atom properties or reads Global Atom Table
344 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html
347 * Atom to query. If AtomInformationClass parameter is
348 * AtomTableInformation, Atom parameter is not used.
350 * @param AtomInformationClass
351 * See ATOM_INFORMATION_CLASS enumeration type for details
353 * @param AtomInformation
354 * Result of call - pointer to user's allocated buffer for data
356 * @param AtomInformationLength
357 * Size of AtomInformation buffer, in bytes
359 * @param ReturnLength
360 * Pointer to ULONG value containing required AtomInformation
363 * @return STATUS_SUCCESS in case of success, proper error code
371 NtQueryInformationAtom(RTL_ATOM Atom
,
372 ATOM_INFORMATION_CLASS AtomInformationClass
,
373 PVOID AtomInformation
,
374 ULONG AtomInformationLength
,
377 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
378 PATOM_BASIC_INFORMATION BasicInformation
= AtomInformation
;
379 PATOM_TABLE_INFORMATION TableInformation
= AtomInformation
;
380 NTSTATUS Status
= STATUS_SUCCESS
;
381 ULONG Flags
, UsageCount
, NameLength
, RequiredLength
= 0;
382 KPROCESSOR_MODE PreviousMode
;
386 /* Check for valid table */
387 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
389 PreviousMode
= ExGetPreviousMode();
393 /* Probe the parameters */
394 if (PreviousMode
!= KernelMode
)
396 ProbeForWrite(AtomInformation
,
397 AtomInformationLength
,
400 if (ReturnLength
!= NULL
)
402 ProbeForWriteUlong(ReturnLength
);
407 switch (AtomInformationClass
)
409 /* Caller requested info about an atom */
410 case AtomBasicInformation
:
413 RequiredLength
= FIELD_OFFSET(ATOM_BASIC_INFORMATION
, Name
);
414 if (RequiredLength
> AtomInformationLength
)
417 DPRINT1("Buffer too small\n");
418 Status
= STATUS_INFO_LENGTH_MISMATCH
;
424 NameLength
= AtomInformationLength
- RequiredLength
;
425 BasicInformation
->Name
[0] = UNICODE_NULL
;
428 Status
= RtlQueryAtomInAtomTable(AtomTable
,
432 BasicInformation
->Name
,
434 if (NT_SUCCESS(Status
))
437 BasicInformation
->UsageCount
= (USHORT
)UsageCount
;
438 BasicInformation
->Flags
= (USHORT
)Flags
;
439 BasicInformation
->NameLength
= (USHORT
)NameLength
;
440 RequiredLength
+= NameLength
+ sizeof(WCHAR
);
444 /* Caller requested info about an Atom Table */
445 case AtomTableInformation
:
448 RequiredLength
= FIELD_OFFSET(ATOM_TABLE_INFORMATION
, Atoms
);
449 if (RequiredLength
> AtomInformationLength
)
452 DPRINT1("Buffer too small\n");
453 Status
= STATUS_INFO_LENGTH_MISMATCH
;
458 Status
= RtlQueryAtomListInAtomTable(AtomTable
,
459 (AtomInformationLength
- RequiredLength
) /
461 &TableInformation
->NumberOfAtoms
,
462 TableInformation
->Atoms
);
463 if (NT_SUCCESS(Status
))
465 /* Update the return length */
466 RequiredLength
+= TableInformation
->NumberOfAtoms
* sizeof(RTL_ATOM
);
470 /* Caller was on crack */
473 /* Unrecognized class */
474 Status
= STATUS_INVALID_INFO_CLASS
;
478 /* Return the required size */
479 if (ReturnLength
!= NULL
)
481 *ReturnLength
= RequiredLength
;
484 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
486 Status
= _SEH_GetExceptionCode();
490 /* Return to caller */