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 *****************************************************************/
16 #define TAG_ATOM 'motA'
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();
94 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
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 or kernel-mode */
112 if (PreviousMode
== KernelMode
)
114 /* Re-use the given name if kernel mode */
115 CapturedName
= AtomName
;
119 /* Check if we have a name */
122 /* Allocate an aligned buffer + the null char */
123 CapturedSize
= ((AtomNameLength
+ sizeof(WCHAR
)) &
124 ~(sizeof(WCHAR
) -1));
125 CapturedName
= ExAllocatePoolWithTag(PagedPool
,
132 return STATUS_INSUFFICIENT_RESOURCES
;
139 ProbeForRead(AtomName
, AtomNameLength
, sizeof(WCHAR
));
141 /* Copy the name and null-terminate it */
142 RtlCopyMemory(CapturedName
, AtomName
, AtomNameLength
);
143 CapturedName
[AtomNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
145 /* Probe the atom too */
146 if (Atom
) ProbeForWriteUshort(Atom
);
148 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
150 /* Return the exception code */
151 _SEH2_YIELD(return _SEH2_GetExceptionCode());
162 /* Call the runtime function */
163 Status
= RtlAddAtomToAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
164 if (NT_SUCCESS(Status
) && (Atom
))
166 /* Success and caller wants the atom back.. .enter SEH */
169 /* Return the atom */
172 _SEH2_EXCEPT(ExSystemExceptionFilter())
174 /* Get the exception code */
175 Status
= _SEH2_GetExceptionCode();
180 /* If we captured anything, free it */
181 if ((CapturedName
!= NULL
) && (CapturedName
!= AtomName
))
182 ExFreePoolWithTag(CapturedName
, TAG_ATOM
);
184 /* Return to caller */
192 * Removes Atom from Global Atom Table. If Atom's reference counter
193 * is greater then 1, function decrements this counter, but Atom
194 * stayed in Global Atom Table.
195 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html
200 * @return STATUS_SUCCESS in case of success, proper error code
208 NtDeleteAtom(IN RTL_ATOM Atom
)
210 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
213 /* Check for valid table */
214 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
216 /* Call worker function */
217 return RtlDeleteAtomFromAtomTable(AtomTable
, Atom
);
224 * Retrieves existing Atom's identifier without incrementing Atom's
226 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html
229 * Atom name in Unicode
231 * @param AtomNameLength
232 * Length of the atom name
235 * Pointer to RTL_ATOM
237 * @return STATUS_SUCCESS in case of success, proper error code
245 NtFindAtom(IN PWSTR AtomName
,
246 IN ULONG AtomNameLength
,
249 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
251 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
252 LPWSTR CapturedName
= NULL
;
257 /* Check for the table */
258 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
260 /* Check for valid name */
261 if (AtomNameLength
> (RTL_MAXIMUM_ATOM_LENGTH
* sizeof(WCHAR
)))
264 DPRINT1("Atom name too long\n");
265 return STATUS_INVALID_PARAMETER
;
268 /* Re-use the given name if kernel mode or no atom name */
269 CapturedName
= AtomName
;
271 /* Check if we're called from user-mode*/
272 if (PreviousMode
!= KernelMode
)
277 /* Check if we have a name */
281 ProbeForRead(AtomName
, AtomNameLength
, sizeof(WCHAR
));
283 /* Allocate an aligned buffer + the null char */
284 CapturedSize
= ((AtomNameLength
+ sizeof(WCHAR
)) &~
286 CapturedName
= ExAllocatePoolWithTag(PagedPool
,
292 Status
= STATUS_INSUFFICIENT_RESOURCES
;
296 /* Copy the name and null-terminate it */
297 RtlCopyMemory(CapturedName
, AtomName
, AtomNameLength
);
298 CapturedName
[AtomNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
301 /* Probe the atom too */
302 if (Atom
) ProbeForWriteUshort(Atom
);
305 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
307 /* Return the exception code */
308 _SEH2_YIELD(return _SEH2_GetExceptionCode());
313 /* Call the runtime function */
314 Status
= RtlLookupAtomInAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
315 if (NT_SUCCESS(Status
) && (Atom
))
317 /* Success and caller wants the atom back.. .enter SEH */
320 /* Return the atom */
323 _SEH2_EXCEPT(ExSystemExceptionFilter())
325 Status
= _SEH2_GetExceptionCode();
330 /* If we captured anything, free it */
331 if ((CapturedName
) && (CapturedName
!= AtomName
))
332 ExFreePoolWithTag(CapturedName
, TAG_ATOM
);
334 /* Return to caller */
339 * @name NtQueryInformationAtom
342 * Gets single Atom properties or reads Global Atom Table
343 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html
346 * Atom to query. If AtomInformationClass parameter is
347 * AtomTableInformation, Atom parameter is not used.
349 * @param AtomInformationClass
350 * See ATOM_INFORMATION_CLASS enumeration type for details
352 * @param AtomInformation
353 * Result of call - pointer to user's allocated buffer for data
355 * @param AtomInformationLength
356 * Size of AtomInformation buffer, in bytes
358 * @param ReturnLength
359 * Pointer to ULONG value containing required AtomInformation
362 * @return STATUS_SUCCESS in case of success, proper error code
370 NtQueryInformationAtom(RTL_ATOM Atom
,
371 ATOM_INFORMATION_CLASS AtomInformationClass
,
372 PVOID AtomInformation
,
373 ULONG AtomInformationLength
,
376 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
377 PATOM_BASIC_INFORMATION BasicInformation
= AtomInformation
;
378 PATOM_TABLE_INFORMATION TableInformation
= AtomInformation
;
379 NTSTATUS Status
= STATUS_SUCCESS
;
380 ULONG Flags
, UsageCount
, NameLength
, RequiredLength
= 0;
381 KPROCESSOR_MODE PreviousMode
;
385 /* Check for valid table */
386 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
388 PreviousMode
= ExGetPreviousMode();
392 /* Probe the parameters */
393 if (PreviousMode
!= KernelMode
)
395 ProbeForWrite(AtomInformation
,
396 AtomInformationLength
,
399 if (ReturnLength
!= NULL
)
401 ProbeForWriteUlong(ReturnLength
);
406 switch (AtomInformationClass
)
408 /* Caller requested info about an atom */
409 case AtomBasicInformation
:
412 RequiredLength
= FIELD_OFFSET(ATOM_BASIC_INFORMATION
, Name
);
413 if (RequiredLength
> AtomInformationLength
)
416 DPRINT1("Buffer too small\n");
417 Status
= STATUS_INFO_LENGTH_MISMATCH
;
423 NameLength
= AtomInformationLength
- RequiredLength
;
424 BasicInformation
->Name
[0] = UNICODE_NULL
;
427 Status
= RtlQueryAtomInAtomTable(AtomTable
,
431 BasicInformation
->Name
,
433 if (NT_SUCCESS(Status
))
436 BasicInformation
->UsageCount
= (USHORT
)UsageCount
;
437 BasicInformation
->Flags
= (USHORT
)Flags
;
438 BasicInformation
->NameLength
= (USHORT
)NameLength
;
439 RequiredLength
+= NameLength
+ sizeof(WCHAR
);
443 /* Caller requested info about an Atom Table */
444 case AtomTableInformation
:
447 RequiredLength
= FIELD_OFFSET(ATOM_TABLE_INFORMATION
, Atoms
);
448 if (RequiredLength
> AtomInformationLength
)
451 DPRINT1("Buffer too small\n");
452 Status
= STATUS_INFO_LENGTH_MISMATCH
;
457 Status
= RtlQueryAtomListInAtomTable(AtomTable
,
458 (AtomInformationLength
- RequiredLength
) /
460 &TableInformation
->NumberOfAtoms
,
461 TableInformation
->Atoms
);
462 if (NT_SUCCESS(Status
))
464 /* Update the return length */
465 RequiredLength
+= TableInformation
->NumberOfAtoms
* sizeof(RTL_ATOM
);
469 /* Caller was on crack */
472 /* Unrecognized class */
473 Status
= STATUS_INVALID_INFO_CLASS
;
477 /* Return the required size */
478 if (ReturnLength
!= NULL
)
480 *ReturnLength
= RequiredLength
;
483 _SEH2_EXCEPT(ExSystemExceptionFilter())
485 Status
= _SEH2_GetExceptionCode();
489 /* Return to caller */