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();
93 NTSTATUS Status
= STATUS_SUCCESS
;
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(ExSystemExceptionFilter())
150 Status
= _SEH2_GetExceptionCode();
155 /* Make sure probe worked */
156 if (NT_SUCCESS(Status
))
158 /* Call the runtime function */
159 Status
= RtlAddAtomToAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
160 if (NT_SUCCESS(Status
) && (Atom
))
162 /* Success and caller wants the atom back.. .enter SEH */
165 /* Return the atom */
168 _SEH2_EXCEPT(ExSystemExceptionFilter())
170 Status
= _SEH2_GetExceptionCode();
176 /* If we captured anything, free it */
177 if ((CapturedName
) && (CapturedName
!= AtomName
)) ExFreePool(CapturedName
);
179 /* Return to caller */
187 * Removes Atom from Global Atom Table. If Atom's reference counter
188 * is greater then 1, function decrements this counter, but Atom
189 * stayed in Global Atom Table.
190 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html
195 * @return STATUS_SUCCESS in case of success, proper error code
203 NtDeleteAtom(IN RTL_ATOM Atom
)
205 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
208 /* Check for valid table */
209 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
211 /* Call worker function */
212 return RtlDeleteAtomFromAtomTable(AtomTable
, Atom
);
219 * Retrieves existing Atom's identifier without incrementing Atom's
221 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html
224 * Atom name in Unicode
226 * @param AtomNameLength
227 * Length of the atom name
230 * Pointer to RTL_ATOM
232 * @return STATUS_SUCCESS in case of success, proper error code
240 NtFindAtom(IN PWSTR AtomName
,
241 IN ULONG AtomNameLength
,
244 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
245 NTSTATUS Status
= STATUS_SUCCESS
;
246 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
247 LPWSTR CapturedName
= NULL
;
252 /* Check for the table */
253 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
255 /* Check for valid name */
256 if (AtomNameLength
> (RTL_MAXIMUM_ATOM_LENGTH
* sizeof(WCHAR
)))
259 DPRINT1("Atom name too long\n");
260 return STATUS_INVALID_PARAMETER
;
263 /* Re-use the given name if kernel mode or no atom name */
264 CapturedName
= AtomName
;
266 /* Check if we're called from user-mode*/
267 if (PreviousMode
!= KernelMode
)
272 /* Check if we have a name */
276 ProbeForRead(AtomName
, AtomNameLength
, sizeof(WCHAR
));
278 /* Allocate an aligned buffer + the null char */
279 CapturedSize
= ((AtomNameLength
+ sizeof(WCHAR
)) &~
281 CapturedName
= ExAllocatePoolWithTag(PagedPool
,
287 Status
= STATUS_INSUFFICIENT_RESOURCES
;
291 /* Copy the name and null-terminate it */
292 RtlCopyMemory(CapturedName
, AtomName
, AtomNameLength
);
293 CapturedName
[AtomNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
296 /* Probe the atom too */
297 if (Atom
) ProbeForWriteUshort(Atom
);
300 _SEH2_EXCEPT(ExSystemExceptionFilter())
302 Status
= _SEH2_GetExceptionCode();
307 /* Make sure probe worked */
308 if (NT_SUCCESS(Status
))
310 /* Call the runtime function */
311 Status
= RtlLookupAtomInAtomTable(AtomTable
, CapturedName
, &SafeAtom
);
312 if (NT_SUCCESS(Status
) && (Atom
))
314 /* Success and caller wants the atom back.. .enter SEH */
317 /* Return the atom */
320 _SEH2_EXCEPT(ExSystemExceptionFilter())
322 Status
= _SEH2_GetExceptionCode();
328 /* If we captured anything, free it */
329 if ((CapturedName
) && (CapturedName
!= AtomName
)) ExFreePool(CapturedName
);
331 /* Return to caller */
336 * @name NtQueryInformationAtom
339 * Gets single Atom properties or reads Global Atom Table
340 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html
343 * Atom to query. If AtomInformationClass parameter is
344 * AtomTableInformation, Atom parameter is not used.
346 * @param AtomInformationClass
347 * See ATOM_INFORMATION_CLASS enumeration type for details
349 * @param AtomInformation
350 * Result of call - pointer to user's allocated buffer for data
352 * @param AtomInformationLength
353 * Size of AtomInformation buffer, in bytes
355 * @param ReturnLength
356 * Pointer to ULONG value containing required AtomInformation
359 * @return STATUS_SUCCESS in case of success, proper error code
367 NtQueryInformationAtom(RTL_ATOM Atom
,
368 ATOM_INFORMATION_CLASS AtomInformationClass
,
369 PVOID AtomInformation
,
370 ULONG AtomInformationLength
,
373 PRTL_ATOM_TABLE AtomTable
= ExpGetGlobalAtomTable();
374 PATOM_BASIC_INFORMATION BasicInformation
= AtomInformation
;
375 PATOM_TABLE_INFORMATION TableInformation
= AtomInformation
;
376 NTSTATUS Status
= STATUS_SUCCESS
;
377 ULONG Flags
, UsageCount
, NameLength
, RequiredLength
= 0;
378 KPROCESSOR_MODE PreviousMode
;
382 /* Check for valid table */
383 if (AtomTable
== NULL
) return STATUS_ACCESS_DENIED
;
385 PreviousMode
= ExGetPreviousMode();
389 /* Probe the parameters */
390 if (PreviousMode
!= KernelMode
)
392 ProbeForWrite(AtomInformation
,
393 AtomInformationLength
,
396 if (ReturnLength
!= NULL
)
398 ProbeForWriteUlong(ReturnLength
);
403 switch (AtomInformationClass
)
405 /* Caller requested info about an atom */
406 case AtomBasicInformation
:
409 RequiredLength
= FIELD_OFFSET(ATOM_BASIC_INFORMATION
, Name
);
410 if (RequiredLength
> AtomInformationLength
)
413 DPRINT1("Buffer too small\n");
414 Status
= STATUS_INFO_LENGTH_MISMATCH
;
420 NameLength
= AtomInformationLength
- RequiredLength
;
421 BasicInformation
->Name
[0] = UNICODE_NULL
;
424 Status
= RtlQueryAtomInAtomTable(AtomTable
,
428 BasicInformation
->Name
,
430 if (NT_SUCCESS(Status
))
433 BasicInformation
->UsageCount
= (USHORT
)UsageCount
;
434 BasicInformation
->Flags
= (USHORT
)Flags
;
435 BasicInformation
->NameLength
= (USHORT
)NameLength
;
436 RequiredLength
+= NameLength
+ sizeof(WCHAR
);
440 /* Caller requested info about an Atom Table */
441 case AtomTableInformation
:
444 RequiredLength
= FIELD_OFFSET(ATOM_TABLE_INFORMATION
, Atoms
);
445 if (RequiredLength
> AtomInformationLength
)
448 DPRINT1("Buffer too small\n");
449 Status
= STATUS_INFO_LENGTH_MISMATCH
;
454 Status
= RtlQueryAtomListInAtomTable(AtomTable
,
455 (AtomInformationLength
- RequiredLength
) /
457 &TableInformation
->NumberOfAtoms
,
458 TableInformation
->Atoms
);
459 if (NT_SUCCESS(Status
))
461 /* Update the return length */
462 RequiredLength
+= TableInformation
->NumberOfAtoms
* sizeof(RTL_ATOM
);
466 /* Caller was on crack */
469 /* Unrecognized class */
470 Status
= STATUS_INVALID_INFO_CLASS
;
474 /* Return the required size */
475 if (ReturnLength
!= NULL
)
477 *ReturnLength
= RequiredLength
;
480 _SEH2_EXCEPT(ExSystemExceptionFilter())
482 Status
= _SEH2_GetExceptionCode();
486 /* Return to caller */