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 /* Re-use the given name if kernel mode or no atom name */
112 CapturedName
= AtomName
;
114 /* Check if we're called from user-mode*/
115 if (PreviousMode
!= KernelMode
)
120 /* Check if we have a name */
124 ProbeForRead(AtomName
, AtomNameLength
, sizeof(WCHAR
));
126 /* Allocate an aligned buffer + the null char */
127 CapturedSize
= ((AtomNameLength
+ sizeof(WCHAR
)) &~
129 CapturedName
= ExAllocatePoolWithTag(PagedPool
,
135 Status
= STATUS_INSUFFICIENT_RESOURCES
;
139 /* Copy the name and null-terminate it */
140 RtlCopyMemory(CapturedName
, AtomName
, AtomNameLength
);
141 CapturedName
[AtomNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
144 /* Probe the atom too */
145 if (Atom
) ProbeForWriteUshort(Atom
);
148 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
150 /* Return the exception code */
151 _SEH2_YIELD(return _SEH2_GetExceptionCode());
156 /* Call the runtime function */
157 Status
= RtlAddAtomToAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
158 if (NT_SUCCESS(Status
) && (Atom
))
160 /* Success and caller wants the atom back.. .enter SEH */
163 /* Return the atom */
166 _SEH2_EXCEPT(ExSystemExceptionFilter())
168 /* Get the exception code */
169 Status
= _SEH2_GetExceptionCode();
174 /* If we captured anything, free it */
175 if ((CapturedName
) && (CapturedName
!= AtomName
)) ExFreePool(CapturedName
);
177 /* Return to caller */
185 * Removes Atom from Global Atom Table. If Atom's reference counter
186 * is greater then 1, function decrements this counter, but Atom
187 * stayed in Global Atom Table.
188 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html
193 * @return STATUS_SUCCESS in case of success, proper error code
201 NtDeleteAtom(IN RTL_ATOM Atom
)
203 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
206 /* Check for valid table */
207 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
209 /* Call worker function */
210 return RtlDeleteAtomFromAtomTable(AtomTable
, Atom
);
217 * Retrieves existing Atom's identifier without incrementing Atom's
219 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html
222 * Atom name in Unicode
224 * @param AtomNameLength
225 * Length of the atom name
228 * Pointer to RTL_ATOM
230 * @return STATUS_SUCCESS in case of success, proper error code
238 NtFindAtom(IN PWSTR AtomName
,
239 IN ULONG AtomNameLength
,
242 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
244 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
245 LPWSTR CapturedName
= NULL
;
250 /* Check for the table */
251 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
253 /* Check for valid name */
254 if (AtomNameLength
> (RTL_MAXIMUM_ATOM_LENGTH
* sizeof(WCHAR
)))
257 DPRINT1("Atom name too long\n");
258 return STATUS_INVALID_PARAMETER
;
261 /* Re-use the given name if kernel mode or no atom name */
262 CapturedName
= AtomName
;
264 /* Check if we're called from user-mode*/
265 if (PreviousMode
!= KernelMode
)
270 /* Check if we have a name */
274 ProbeForRead(AtomName
, AtomNameLength
, sizeof(WCHAR
));
276 /* Allocate an aligned buffer + the null char */
277 CapturedSize
= ((AtomNameLength
+ sizeof(WCHAR
)) &~
279 CapturedName
= ExAllocatePoolWithTag(PagedPool
,
285 Status
= STATUS_INSUFFICIENT_RESOURCES
;
289 /* Copy the name and null-terminate it */
290 RtlCopyMemory(CapturedName
, AtomName
, AtomNameLength
);
291 CapturedName
[AtomNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
294 /* Probe the atom too */
295 if (Atom
) ProbeForWriteUshort(Atom
);
298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
300 /* Return the exception code */
301 _SEH2_YIELD(return _SEH2_GetExceptionCode());
306 /* Call the runtime function */
307 Status
= RtlLookupAtomInAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
308 if (NT_SUCCESS(Status
) && (Atom
))
310 /* Success and caller wants the atom back.. .enter SEH */
313 /* Return the atom */
316 _SEH2_EXCEPT(ExSystemExceptionFilter())
318 Status
= _SEH2_GetExceptionCode();
323 /* If we captured anything, free it */
324 if ((CapturedName
) && (CapturedName
!= AtomName
)) ExFreePool(CapturedName
);
326 /* Return to caller */
331 * @name NtQueryInformationAtom
334 * Gets single Atom properties or reads Global Atom Table
335 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html
338 * Atom to query. If AtomInformationClass parameter is
339 * AtomTableInformation, Atom parameter is not used.
341 * @param AtomInformationClass
342 * See ATOM_INFORMATION_CLASS enumeration type for details
344 * @param AtomInformation
345 * Result of call - pointer to user's allocated buffer for data
347 * @param AtomInformationLength
348 * Size of AtomInformation buffer, in bytes
350 * @param ReturnLength
351 * Pointer to ULONG value containing required AtomInformation
354 * @return STATUS_SUCCESS in case of success, proper error code
362 NtQueryInformationAtom(RTL_ATOM Atom
,
363 ATOM_INFORMATION_CLASS AtomInformationClass
,
364 PVOID AtomInformation
,
365 ULONG AtomInformationLength
,
368 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
369 PATOM_BASIC_INFORMATION BasicInformation
= AtomInformation
;
370 PATOM_TABLE_INFORMATION TableInformation
= AtomInformation
;
371 NTSTATUS Status
= STATUS_SUCCESS
;
372 ULONG Flags
, UsageCount
, NameLength
, RequiredLength
= 0;
373 KPROCESSOR_MODE PreviousMode
;
377 /* Check for valid table */
378 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
380 PreviousMode
= ExGetPreviousMode();
384 /* Probe the parameters */
385 if (PreviousMode
!= KernelMode
)
387 ProbeForWrite(AtomInformation
,
388 AtomInformationLength
,
391 if (ReturnLength
!= NULL
)
393 ProbeForWriteUlong(ReturnLength
);
398 switch (AtomInformationClass
)
400 /* Caller requested info about an atom */
401 case AtomBasicInformation
:
404 RequiredLength
= FIELD_OFFSET(ATOM_BASIC_INFORMATION
, Name
);
405 if (RequiredLength
> AtomInformationLength
)
408 DPRINT1("Buffer too small\n");
409 Status
= STATUS_INFO_LENGTH_MISMATCH
;
415 NameLength
= AtomInformationLength
- RequiredLength
;
416 BasicInformation
->Name
[0] = UNICODE_NULL
;
419 Status
= RtlQueryAtomInAtomTable(AtomTable
,
423 BasicInformation
->Name
,
425 if (NT_SUCCESS(Status
))
428 BasicInformation
->UsageCount
= (USHORT
)UsageCount
;
429 BasicInformation
->Flags
= (USHORT
)Flags
;
430 BasicInformation
->NameLength
= (USHORT
)NameLength
;
431 RequiredLength
+= NameLength
+ sizeof(WCHAR
);
435 /* Caller requested info about an Atom Table */
436 case AtomTableInformation
:
439 RequiredLength
= FIELD_OFFSET(ATOM_TABLE_INFORMATION
, Atoms
);
440 if (RequiredLength
> AtomInformationLength
)
443 DPRINT1("Buffer too small\n");
444 Status
= STATUS_INFO_LENGTH_MISMATCH
;
449 Status
= RtlQueryAtomListInAtomTable(AtomTable
,
450 (AtomInformationLength
- RequiredLength
) /
452 &TableInformation
->NumberOfAtoms
,
453 TableInformation
->Atoms
);
454 if (NT_SUCCESS(Status
))
456 /* Update the return length */
457 RequiredLength
+= TableInformation
->NumberOfAtoms
* sizeof(RTL_ATOM
);
461 /* Caller was on crack */
464 /* Unrecognized class */
465 Status
= STATUS_INVALID_INFO_CLASS
;
469 /* Return the required size */
470 if (ReturnLength
!= NULL
)
472 *ReturnLength
= RequiredLength
;
475 _SEH2_EXCEPT(ExSystemExceptionFilter())
477 Status
= _SEH2_GetExceptionCode();
481 /* Return to caller */