Fix RtlQueryAtomInAtomTable and add regression tests
Modified: trunk/reactos/lib/rtl/atom.c
Modified: trunk/reactos/regtests/winetests/ntdll/atom.c
Modified: trunk/reactos/subsys/win32k/ntuser/class.c
_____
Modified: trunk/reactos/lib/rtl/atom.c
--- trunk/reactos/lib/rtl/atom.c 2005-09-23 19:24:20 UTC (rev
18019)
+++ trunk/reactos/lib/rtl/atom.c 2005-09-23 21:08:57 UTC (rev
18020)
@@ -565,6 +565,23 @@
/*
* @implemented
+ *
+ * This API is really messed up with regards to NameLength. If you pass
in a
+ * valid buffer for AtomName, NameLength should be the size of the
buffer
+ * (in bytes, not characters). So if you expect the string to be 6 char
long,
+ * you need to allocate a buffer of 7 WCHARs and pass 14 for
NameLength.
+ * The AtomName returned is always null terminated. If the NameLength
you pass
+ * is smaller than 4 (4 would leave room for 1 character) the function
will
+ * return with status STATUS_BUFFER_TOO_SMALL. If you pass more than 4,
the
+ * return status will be STATUS_SUCCESS, even if the buffer is not
large enough
+ * to hold the complete string. In that case, the string is silently
truncated
+ * and made to fit in the provided buffer. On return NameLength is set
to the
+ * number of bytes (but EXCLUDING the bytes for the null terminator)
copied.
+ * So, if the string is 6 char long, you pass a buffer of 10 bytes, on
return
+ * NameLength will be set to 8.
+ * If you pass in a NULL value for AtomName, the length of the string
in bytes
+ * (again EXCLUDING the null terminator) is returned in NameLength, at
least
+ * on Win2k, XP and ReactOS. NT4 will return 0 in that case.
*/
NTSTATUS STDCALL
RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
@@ -575,54 +592,35 @@
PULONG NameLength)
{
ULONG Length;
+ union
+ {
+ /* A RTL_ATOM_TABLE_ENTRY has a "WCHAR Name[1]" entry at the end.
+ * Make sure we reserve enough room to facilitate a 12 character
name */
+ RTL_ATOM_TABLE_ENTRY AtomTableEntry;
+ WCHAR StringBuffer[sizeof(RTL_ATOM_TABLE_ENTRY) / sizeof(WCHAR) +
12];
+ } NumberEntry;
PRTL_ATOM_TABLE_ENTRY Entry;
NTSTATUS Status = STATUS_SUCCESS;
if (Atom < 0xC000)
{
- if (RefCount != NULL)
- {
- *RefCount = 1;
- }
+ /* Synthesize an entry */
+ NumberEntry.AtomTableEntry.Atom = Atom;
+ NumberEntry.AtomTableEntry.NameLength =
swprintf(NumberEntry.AtomTableEntry.Name,
+ L"#%lu",
+ (ULONG)Atom);
+ NumberEntry.AtomTableEntry.ReferenceCount = 1;
+ NumberEntry.AtomTableEntry.Flags = RTL_ATOM_IS_PINNED;
+ Entry = &NumberEntry.AtomTableEntry;
+ }
+ else
+ {
+ RtlpLockAtomTable(AtomTable);
- if (PinCount != NULL)
- {
- *PinCount = 1;
- }
-
- if ((AtomName != NULL) && (NameLength != NULL) && (NameLength
>
0))
- {
- WCHAR NameString[12];
-
- Length = swprintf(NameString, L"#%lu", (ULONG)Atom) *
sizeof(WCHAR);
-
- if (*NameLength < Length + sizeof(WCHAR))
- {
- *NameLength = Length;
- Status = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- RtlCopyMemory(AtomName,
- NameString,
- Length);
- AtomName[Length / sizeof(WCHAR)] = L'\0';
- *NameLength = Length;
- }
- }
- else if (NameLength != NULL)
- {
- *NameLength = (Entry->NameLength + 1) * sizeof(WCHAR);
- }
-
- return Status;
+ Entry = RtlpGetAtomEntry(AtomTable,
+ (ULONG)((USHORT)Atom - 0xC000));
}
- RtlpLockAtomTable(AtomTable);
-
- Entry = RtlpGetAtomEntry(AtomTable,
- (ULONG)((USHORT)Atom - 0xC000));
-
if (Entry != NULL && Entry->Atom == (USHORT)Atom)
{
DPRINT("Atom name: %wZ\n", &Entry->Name);
@@ -637,27 +635,40 @@
*PinCount = ((Entry->Flags & RTL_ATOM_IS_PINNED) != 0);
}
- if ((AtomName != NULL) && (NameLength != NULL))
+ if (NULL != NameLength)
{
Length = Entry->NameLength * sizeof(WCHAR);
-
- if (*NameLength < Length + sizeof(WCHAR))
+ if (NULL != AtomName)
{
- *NameLength = Length;
- Status = STATUS_BUFFER_TOO_SMALL;
+ if (*NameLength < Length + sizeof(WCHAR))
+ {
+ if (*NameLength < 4)
+ {
+ *NameLength = Length;
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ Length = *NameLength - sizeof(WCHAR);
+ }
+ }
+ if (NT_SUCCESS(Status))
+ {
+ RtlCopyMemory(AtomName,
+ Entry->Name,
+ Length);
+ AtomName[Length / sizeof(WCHAR)] = L'\0';
+ *NameLength = Length;
+ }
}
else
{
- RtlCopyMemory(AtomName,
- Entry->Name,
- Length);
- AtomName[Length / sizeof(WCHAR)] = L'\0';
*NameLength = Length;
}
}
- else if (NameLength != NULL)
+ else if (NULL != AtomName)
{
- *NameLength = (Entry->NameLength + 1) * sizeof(WCHAR);
+ Status = STATUS_INVALID_PARAMETER;
}
}
else
@@ -665,7 +676,10 @@
Status = STATUS_INVALID_HANDLE;
}
- RtlpUnlockAtomTable(AtomTable);
+ if (NULL != Entry && Entry != &NumberEntry.AtomTableEntry)
+ {
+ RtlpUnlockAtomTable(AtomTable);
+ }
return Status;
}
_____
Modified: trunk/reactos/regtests/winetests/ntdll/atom.c
--- trunk/reactos/regtests/winetests/ntdll/atom.c 2005-09-23
19:24:20 UTC (rev 18019)
+++ trunk/reactos/regtests/winetests/ntdll/atom.c 2005-09-23
21:08:57 UTC (rev 18020)
@@ -233,6 +233,19 @@
ok(res == STATUS_BUFFER_TOO_SMALL, "Got wrong retval, retval:
%lx\n", res);
ok((strlenW(testAtom1) * sizeof(WCHAR)) == Len, "Got wrong
length %lx\n", Len);
+ res = pRtlQueryAtomInAtomTable(AtomTable, Atom1, NULL, NULL,
NULL, &Len);
+ ok(!res, "Failed to retrieve atom length, retval: %lx\n", res);
+ ok(Len == strlenW(testAtom1) * sizeof(WCHAR), "Invalid atom
length got %lu expected %u\n",
+ Len, strlenW(testAtom1) * sizeof(WCHAR));
+
+ Len = strlenW(testAtom1) * sizeof(WCHAR);
+ Name[strlenW(testAtom1)] = '*';
+ res = pRtlQueryAtomInAtomTable(AtomTable, Atom1, NULL, NULL,
Name, &Len);
+ ok(!res, "Failed with exactly long enough buffer, retval:
%lx\n", res);
+ ok(Name[strlenW(testAtom1)] == '*', "Writing outside
buffer\n");
+ ok(0 == memcmp(Name, testAtom1, (strlenW(testAtom1) - 1) *
sizeof(WCHAR)),
+ "We found wrong atom!!\n");
+
res = pRtlPinAtomInAtomTable(AtomTable, Atom1);
ok(!res, "Unable to pin atom in atom table, retval: %lx\n",
res);
_____
Modified: trunk/reactos/subsys/win32k/ntuser/class.c
--- trunk/reactos/subsys/win32k/ntuser/class.c 2005-09-23 19:24:20 UTC
(rev 18019)
+++ trunk/reactos/subsys/win32k/ntuser/class.c 2005-09-23 21:08:57 UTC
(rev 18020)
@@ -207,10 +207,13 @@
Length = 0;
Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,
- WindowObject->Class->Atom, NULL,
NULL, NULL, &Length);
+ WindowObject->Class->Atom, NULL,
NULL,
+ NULL, &Length);
+ Length += sizeof(WCHAR);
Name = ExAllocatePoolWithTag(PagedPool, Length, TAG_STRING);
Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,
- WindowObject->Class->Atom, NULL,
NULL, Name, &Length);
+ WindowObject->Class->Atom, NULL,
NULL,
+ Name, &Length);
if (!NT_SUCCESS(Status))
{
DPRINT("IntGetClassName: RtlQueryAtomInAtomTable failed\n");