atom.c 21.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* Unit test suite for Ntdll atom API functions
 *
 * Copyright 2003 Gyorgy 'Nog' Jeney
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 19 20 21 22 23 24 25
 *
 * NOTES
 * We use function pointers here as there is no import library for NTDLL on
 * windows.
 */

#include <stdio.h>
#include <stdarg.h>
26 27 28 29 30 31 32

#include "ntstatus.h"
/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro 
 * definition errors when we get to winnt.h
 */
#define WIN32_NO_STATUS

33 34 35 36
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
37
#include "winuser.h"
38 39 40
#include "wine/test.h"
#include "winternl.h"

41 42 43 44 45
#ifndef __WINE_WINTERNL_H
typedef unsigned short RTL_ATOM, *PRTL_ATOM;
typedef struct atom_table *RTL_ATOM_TABLE, **PRTL_ATOM_TABLE;
#endif

46 47 48 49 50 51 52 53 54 55 56
/* Function pointers for ntdll calls */
static HMODULE hntdll = 0;
static NTSTATUS (WINAPI *pRtlCreateAtomTable)(ULONG,PRTL_ATOM_TABLE);
static NTSTATUS (WINAPI *pRtlDestroyAtomTable)(RTL_ATOM_TABLE);
static NTSTATUS (WINAPI *pRtlEmptyAtomTable)(RTL_ATOM_TABLE,BOOLEAN);
static NTSTATUS (WINAPI *pRtlAddAtomToAtomTable)(RTL_ATOM_TABLE,PCWSTR,PRTL_ATOM);
static NTSTATUS (WINAPI *pRtlDeleteAtomFromAtomTable)(RTL_ATOM_TABLE,RTL_ATOM);
static NTSTATUS (WINAPI *pRtlLookupAtomInAtomTable)(RTL_ATOM_TABLE,PCWSTR,PRTL_ATOM);
static NTSTATUS (WINAPI *pRtlPinAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM);
static NTSTATUS (WINAPI *pRtlQueryAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM,PULONG,PULONG,PWSTR,PULONG);

57
static NTSTATUS (WINAPI* pNtAddAtom)(LPCWSTR,ULONG,RTL_ATOM*);
58
static NTSTATUS (WINAPI* pNtAddAtomNT4)(LPCWSTR,RTL_ATOM*);
59 60
static NTSTATUS (WINAPI* pNtQueryInformationAtom)(RTL_ATOM,DWORD,void*,ULONG,PULONG);

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
static const WCHAR EmptyAtom[] = {0};
static const WCHAR testAtom1[] = {'H','e','l','l','o',' ','W','o','r','l','d',0};
static const WCHAR testAtom2[] = {'H','e','l','l','o',' ','W','o','r','l','d','2',0};
static const WCHAR testAtom3[] = {'H','e','l','l','o',' ','W','o','r','l','d','3',0};

static const WCHAR testAtom1Cap[] = {'H','E','L','L','O',' ','W','O','R','L','D',0};
static const WCHAR testAtom1Low[] = {'h','e','l','l','o',' ','w','o','r','l','d',0};

static const WCHAR testAtomInt[] = {'#','1','3','2',0};
static const WCHAR testAtomIntInv[] = {'#','2','3','4','z',0};
static const WCHAR testAtomOTT[] = {'#','1','2','3',0};

static void InitFunctionPtr(void)
{
    hntdll = LoadLibraryA("ntdll.dll");
    ok(hntdll != 0, "Unable to load ntdll.dll\n");

    if (hntdll)
    {
        pRtlCreateAtomTable = (void *)GetProcAddress(hntdll, "RtlCreateAtomTable");
        pRtlDestroyAtomTable = (void *)GetProcAddress(hntdll, "RtlDestroyAtomTable");
        pRtlEmptyAtomTable = (void *)GetProcAddress(hntdll, "RtlEmptyAtomTable");
        pRtlAddAtomToAtomTable = (void *)GetProcAddress(hntdll, "RtlAddAtomToAtomTable");
        pRtlDeleteAtomFromAtomTable = (void *)GetProcAddress(hntdll, "RtlDeleteAtomFromAtomTable");
        pRtlLookupAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlLookupAtomInAtomTable");
        pRtlPinAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlPinAtomInAtomTable");
        pRtlQueryAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlQueryAtomInAtomTable");
88 89 90

        pNtAddAtom = (void *)GetProcAddress(hntdll, "NtAddAtom");
        pNtQueryInformationAtom = (void *)GetProcAddress(hntdll, "NtQueryInformationAtom");
91 92 93
    }
}

94
static DWORD WINAPI RtlAtomTestThread(LPVOID Table)
95 96 97 98 99 100 101 102
{
    RTL_ATOM_TABLE AtomTable = *(PRTL_ATOM_TABLE)Table;
    RTL_ATOM Atom;
    NTSTATUS res;
    ULONG RefCount = 0, PinCount = 0, Len = 0;
    WCHAR Name[64];

    res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &Atom);
103
    ok(!res, "Unable to find atom from another thread, retval: %x\n", res);
104 105

    res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &Atom);
106
    ok(!res, "Unable to lookup pinned atom in table, retval: %x\n", res);
107 108

    res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, Name, &Len);
109
    ok(res == STATUS_BUFFER_TOO_SMALL, "We got wrong retval: %x\n", res);
110 111 112

    Len = 64;
    res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, Name, &Len);
113
    ok(!res, "Failed with long enough buffer, retval: %x\n", res);
114 115
    ok(RefCount == 1, "Refcount was not 1 but %x\n", RefCount);
    ok(PinCount == 1, "Pincount was not 1 but %x\n", PinCount);
116
    ok(!lstrcmpW(Name, testAtom2), "We found wrong atom!!\n");
117
    ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len);
118 119 120

    Len = 64;
    res = pRtlQueryAtomInAtomTable(AtomTable, Atom, NULL, NULL, Name, &Len);
121
    ok(!res, "RtlQueryAtomInAtomTable with optional args invalid failed, retval: %x\n", res);
122
    ok(!lstrcmpW(Name, testAtom2), "Found Wrong atom!\n");
123
    ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len);
124 125

    res = pRtlPinAtomInAtomTable(AtomTable, Atom);
126
    ok(!res, "Unable to pin atom in atom table, retval: %x\n", res);
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

    return 0;
}

static void test_NtAtom(void)
{
    RTL_ATOM_TABLE AtomTable = NULL;
    NTSTATUS res;
    RTL_ATOM Atom1, Atom2, Atom3, testEAtom, testAtom;
    HANDLE testThread;
    ULONG RefCount = 0, PinCount = 0, Len = 0;
    WCHAR Name[64];

    /* If we pass a non-null string to create atom table, then it thinks that we
     * have passed it an already allocated atom table */
    res = pRtlCreateAtomTable(0, &AtomTable);
    ok(!res, "RtlCreateAtomTable should succeed with an atom table size of 0\n");

    if (!res)
    {
        res = pRtlDestroyAtomTable(AtomTable);
148
        ok(!res, "We could create the atom table, but we couldn't destroy it! retval: %x\n", res);
149 150 151 152
    }

    AtomTable = NULL;
    res = pRtlCreateAtomTable(37, &AtomTable);
153
    ok(!res, "We're unable to create an atom table with a valid table size retval: %x\n", res);
154 155 156
    if (!res)
    {
        res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1);
157
        ok(!res, "We were unable to add a simple atom to the atom table, retval: %x\n", res);
158 159

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1Cap, &testAtom);
160
        ok(!res, "We were unable to find capital version of the atom, retval: %x\n", res);
161 162 163
        ok(Atom1 == testAtom, "Found wrong atom in table when querying capital atom\n");

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1Low, &testAtom);
164
        ok(!res, "Unable to find lowercase version of the atom, retval: %x\n", res);
165 166 167
        ok(testAtom == Atom1, "Found wrong atom when querying lowercase atom\n");

        res = pRtlAddAtomToAtomTable(AtomTable, EmptyAtom, &testEAtom);
168
        ok(res == STATUS_OBJECT_NAME_INVALID, "Got wrong retval, retval: %x\n", res);
169 170

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
171
        ok(!res, "Failed to find totally legitimate atom, retval: %x\n", res);
172 173 174
        ok(testAtom == Atom1, "Found wrong atom!\n");

        res = pRtlAddAtomToAtomTable(AtomTable, testAtom2, &Atom2);
175
        ok(!res, "Unable to add other legitimate atom to table, retval: %x\n", res);
176 177

        res = pRtlPinAtomInAtomTable(AtomTable, Atom2);
178
        ok(!res, "Unable to pin atom in atom table, retval: %x\n", res);
179

180
        testThread = CreateThread(NULL, 0, RtlAtomTestThread, &AtomTable, 0, NULL);
181 182 183 184
        WaitForSingleObject(testThread, INFINITE);

        Len = 64;
        res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, &RefCount, &PinCount, Name, &Len);
185 186 187
        ok(!res, "Unable to query atom in atom table, retval: %x\n", res);
        ok(RefCount == 1, "RefCount is not 1 but %x\n", RefCount);
        ok(PinCount == 1, "PinCount is not 1 but %x\n", PinCount);
188
        ok(!lstrcmpW(Name, testAtom2), "We found wrong atom\n");
189
        ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len);
190 191

        res = pRtlEmptyAtomTable(AtomTable, FALSE);
192
        ok(!res, "Unable to empty atom table, retval %x\n", res);
193 194 195

        Len = 64;
        res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, &RefCount, &PinCount, Name, &Len);
196 197 198
        ok(!res, "It seems RtlEmptyAtomTable deleted our pinned atom eaven though we asked it not to, retval: %x\n", res);
        ok(RefCount == 1, "RefCount is not 1 but %x\n", RefCount);
        ok(PinCount == 1, "PinCount is not 1 but %x\n", PinCount);
199
        ok(!lstrcmpW(Name, testAtom2), "We found wrong atom\n");
200
        ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len);
201

202
        Len = 8;
203
        Name[0] = Name[1] = Name[2] = Name[3] = Name[4] = 0x1337;
204
        res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, NULL, NULL, Name, &Len);
205 206
        ok(!res, "query atom %x\n", res);
        ok(Len == 6, "wrong length %u\n", Len);
207 208
        ok(!memcmp(Name, testAtom2, Len), "wrong atom string\n");
        ok(!Name[3], "wrong string termination\n");
209
        ok(Name[4] == 0x1337, "buffer overwrite\n");
210

211 212 213
        Len = lstrlenW(testAtom2) * sizeof(WCHAR);
        memset(Name, '.', sizeof(Name));
        res = pRtlQueryAtomInAtomTable( AtomTable, Atom2, NULL, NULL, Name, &Len );
214 215
        ok(!res, "query atom %x\n", res);
        ok(Len == (lstrlenW(testAtom2) - 1) * sizeof(WCHAR), "wrong length %u\n", Len);
216 217 218 219
        ok(!memcmp(testAtom2, Name, (lstrlenW(testAtom2) - 1) * sizeof(WCHAR)), "wrong atom name\n");
        ok(Name[lstrlenW(testAtom2) - 1] == '\0', "wrong char\n");
        ok(Name[lstrlenW(testAtom2)] == ('.' << 8) + '.', "wrong char\n");

220
        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &testAtom);
221
        ok(!res, "We can't find our pinned atom!! retval: %x\n", res);
222 223 224
        ok(testAtom == Atom2, "We found wrong atom!!!\n");

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
225
        ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "We found the atom in our table eaven though we asked RtlEmptyAtomTable to remove it, retval: %x\n", res);
226 227

        res = pRtlAddAtomToAtomTable(AtomTable, testAtom3, &Atom3);
228
        ok(!res, "Unable to add atom to table, retval: %x\n", res);
229 230

        res = pRtlEmptyAtomTable(AtomTable, TRUE);
231
        ok(!res, "Unable to empty atom table, retval: %x\n", res);
232 233

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &testAtom);
234
        ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "The pinned atom should be removed, retval: %x\n", res);
235 236

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom3, &testAtom);
237
        ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Non pinned atom should also be removed, retval: %x\n", res);
238 239

        res = pRtlDestroyAtomTable(AtomTable);
240
        ok(!res, "Can't destroy atom table, retval: %x\n", res);
241 242 243 244
    }

    AtomTable = NULL;
    res = pRtlCreateAtomTable(37, &AtomTable);
245
    ok(!res, "Unable to create atom table, retval: %x\n", res);
246 247 248 249

    if (!res)
    {
        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
250
        ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Didn't get expected retval with querying an empty atom table, retval: %x\n", res);
251 252

        res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1);
253
        ok(!res, "Unable to add atom to atom table, retval %x\n", res);
254 255

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
256 257
        ok(!res, "Can't find previously added atom in table, retval: %x\n", res);
        ok(testAtom == Atom1, "Found wrong atom! retval: %x\n", res);
258 259

        res = pRtlDeleteAtomFromAtomTable(AtomTable, Atom1);
260
        ok(!res, "Unable to delete atom from table, retval: %x\n", res);
261 262

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
263
        ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Able to find previously deleted atom in table, retval: %x\n", res);
264 265

        res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1);
266
        ok(!res, "Unable to add atom to atom table, retval: %x\n", res);
267 268 269

        Len = 0;
        res = pRtlQueryAtomInAtomTable(AtomTable, Atom1, NULL, NULL, Name, &Len);
270
        ok(res == STATUS_BUFFER_TOO_SMALL, "Got wrong retval, retval: %x\n", res);
271 272
        ok((lstrlenW(testAtom1) * sizeof(WCHAR)) == Len || broken(!Len) /* nt4 */, "Got wrong length %x\n", Len);
        if (!Len) pNtAddAtomNT4 = (void *)pNtAddAtom;
273 274

        res = pRtlPinAtomInAtomTable(AtomTable, Atom1);
275
        ok(!res, "Unable to pin atom in atom table, retval: %x\n", res);
276 277

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
278
        ok(!res, "Unable to find atom in atom table, retval: %x\n", res);
279 280 281
        ok(testAtom == Atom1, "Wrong atom found\n");

        res = pRtlDeleteAtomFromAtomTable(AtomTable, Atom1);
282
        ok(res == STATUS_WAS_LOCKED, "Unable to delete atom from table, retval: %x\n", res);
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298

        res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
        ok(!res, "Able to find deleted atom in table\n");

        res = pRtlDestroyAtomTable(AtomTable);
        ok(!res, "Unable to destroy atom table\n");
    }
}

/* Test Adding integer atoms to atom table */
static void test_NtIntAtom(void)
{
    NTSTATUS res;
    RTL_ATOM_TABLE AtomTable;
    RTL_ATOM testAtom;
    ULONG RefCount = 0, PinCount = 0;
299
    INT_PTR i;
300 301 302 303 304
    WCHAR Name[64];
    ULONG Len;

    AtomTable = NULL;
    res = pRtlCreateAtomTable(37, &AtomTable);
305
    ok(!res, "Unable to create atom table, %x\n", res);
306 307 308

    if (!res)
    {
Austin English's avatar
Austin English committed
309
        /* According to the kernel32 functions, integer atoms are only allowed from
310
         * 0x0001 to 0xbfff and not 0xc000 to 0xffff, which is correct */
311
        res = pRtlAddAtomToAtomTable(AtomTable, NULL, &testAtom);
312
        ok(res == STATUS_INVALID_PARAMETER, "Didn't get expected result from adding 0 int atom, retval: %x\n", res);
313 314
        for (i = 1; i <= 0xbfff; i++)
        {
315 316
            res = pRtlAddAtomToAtomTable(AtomTable, (LPWSTR)i, &testAtom);
            ok(!res, "Unable to add valid integer atom %li, retval: %x\n", i, res);
317 318 319 320
        }

        for (i = 1; i <= 0xbfff; i++)
        {
321 322
            res = pRtlLookupAtomInAtomTable(AtomTable, (LPWSTR)i, &testAtom);
            ok(!res, "Unable to find int atom %li, retval: %x\n", i, res);
323 324 325
            if (!res)
            {
                res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
326
                ok(!res, "Unable to pin int atom %li, retval: %x\n", i, res);
327 328 329 330 331
            }
        }

        for (i = 0xc000; i <= 0xffff; i++)
        {
332 333
            res = pRtlAddAtomToAtomTable(AtomTable, (LPWSTR)i, &testAtom);
            ok(res, "Able to illeageal integer atom %li, retval: %x\n", i, res);
334 335 336
        }

        res = pRtlDestroyAtomTable(AtomTable);
337
        ok(!res, "Unable to destroy atom table, retval: %x\n", res);
338 339 340 341
    }

    AtomTable = NULL;
    res = pRtlCreateAtomTable(37, &AtomTable);
342
    ok(!res, "Unable to create atom table, %x\n", res);
343 344 345
    if (!res)
    {
        res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)123, &testAtom);
346
        ok(!res, "Unable to query atom in atom table, retval: %x\n", res);
347 348

        res = pRtlAddAtomToAtomTable(AtomTable, testAtomInt, &testAtom);
349
        ok(!res, "Unable to add int atom to table, retval: %x\n", res);
350 351

        res = pRtlAddAtomToAtomTable(AtomTable, testAtomIntInv, &testAtom);
352
        ok(!res, "Unable to add int atom to table, retval: %x\n", res);
353 354

        res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom);
355
        ok(!res, "Unable to add int atom to table, retval: %x\n", res);
356 357

        res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom);
358
        ok(!res, "Unable to re-add int atom to table, retval: %x\n", res);
359 360 361

        Len = 64;
        res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, Name, &Len);
362 363 364
        ok(!res, "Unable to query atom in atom table, retval: %x\n", res);
        ok(PinCount == 1, "Expected pincount 1 but got %x\n", PinCount);
        ok(RefCount == 1, "Expected refcount 1 but got %x\n", RefCount);
365
        ok(!lstrcmpW(testAtomOTT, Name), "Got wrong atom name\n");
366
        ok((lstrlenW(testAtomOTT) * sizeof(WCHAR)) == Len, "Got wrong len %d\n", Len);
367 368

        res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
369
        ok(!res, "Unable to pin int atom, retval: %x\n", res);
370 371

        res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
372
        ok(!res, "Unable to pin int atom, retval: %x\n", res);
373 374

        res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, NULL, NULL);
375 376 377
        ok(!res, "Unable to query atom in atom table, retval: %x\n", res);
        ok(PinCount == 1, "Expected pincount 1 but got %x\n", PinCount);
        ok(RefCount == 1, "Expected refcount 1 but got %x\n", RefCount);
378 379

        res = pRtlDestroyAtomTable(AtomTable);
380
        ok(!res, "Unable to destroy atom table, retval: %x\n", res);
381 382 383 384 385 386 387 388 389 390 391 392 393
    }
}

/* Tests to see how the pincount and refcount actually works */
static void test_NtRefPinAtom(void)
{
    RTL_ATOM_TABLE AtomTable;
    RTL_ATOM Atom;
    ULONG PinCount = 0, RefCount = 0;
    NTSTATUS res;

    AtomTable = NULL;
    res = pRtlCreateAtomTable(37, &AtomTable);
394
    ok(!res, "Unable to create atom table, %x\n", res);
395 396 397 398

    if (!res)
    {
        res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
399
        ok(!res, "Unable to add our atom to the atom table, retval: %x\n", res);
400 401

        res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
402
        ok(!res, "Unable to add our atom to the atom table, retval: %x\n", res);
403 404

        res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
405
        ok(!res, "Unable to add our atom to the atom table, retval: %x\n", res);
406 407

        res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL);
408 409 410
        ok(!res, "Unable to query atom in atom table, retval: %x\n", res);
        ok(PinCount == 0, "Expected pincount 0 but got %x\n", PinCount);
        ok(RefCount == 3, "Expected refcount 3 but got %x\n", RefCount);
411 412

        res = pRtlPinAtomInAtomTable(AtomTable, Atom);
413
        ok(!res, "Unable to pin atom in atom table, retval: %x\n", res);
414 415

        res = pRtlPinAtomInAtomTable(AtomTable, Atom);
416
        ok(!res, "Unable to pin atom in atom table, retval: %x\n", res);
417 418

        res = pRtlPinAtomInAtomTable(AtomTable, Atom);
419
        ok(!res, "Unable to pin atom in atom table, retval: %x\n", res);
420 421

        res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL);
422 423 424
        ok(!res, "Unable to query atom in atom table, retval: %x\n", res);
        ok(PinCount == 1, "Expected pincount 1 but got %x\n", PinCount);
        ok(RefCount == 3, "Expected refcount 3 but got %x\n", RefCount);
425 426

        res = pRtlDestroyAtomTable(AtomTable);
427
        ok(!res, "Unable to destroy atom table, retval: %x\n", res);
428 429 430
    }
}

431 432 433 434 435 436 437 438
static void test_Global(void)
{
    NTSTATUS    res;
    RTL_ATOM    atom;
    char        ptr[sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR)];
    ATOM_BASIC_INFORMATION*     abi = (ATOM_BASIC_INFORMATION*)ptr;
    ULONG       ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR);

439 440 441 442 443
    if (pNtAddAtomNT4)
        res = pNtAddAtomNT4(testAtom1, &atom);
    else
        res = pNtAddAtom(testAtom1, lstrlenW(testAtom1) * sizeof(WCHAR), &atom);

444
    ok(!res, "Added atom (%x)\n", res);
445

446
    memset(abi->Name, 0xcc, 255 * sizeof(WCHAR));
447 448 449 450 451
    res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
    ok(!res, "atom lookup\n");
    ok(!lstrcmpW(abi->Name, testAtom1), "ok strings\n");
    ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "wrong string length\n");
    ok(abi->Name[lstrlenW(testAtom1)] == 0, "wrong string termination %x\n", abi->Name[lstrlenW(testAtom1)]);
452
    ok(abi->Name[lstrlenW(testAtom1) + 1] == 0xcccc, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]);
453 454 455

    ptr_size = sizeof(ATOM_BASIC_INFORMATION);
    res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
456
    ok(res == STATUS_BUFFER_TOO_SMALL, "wrong return status (%x)\n", res);
457 458
    ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR) || broken(abi->NameLength == sizeof(WCHAR)), /* nt4 */
       "string length %u\n",abi->NameLength);
459

460
    memset(abi->Name, 0xcc, lstrlenW(testAtom1) * sizeof(WCHAR));
461 462
    ptr_size = sizeof(ATOM_BASIC_INFORMATION) + lstrlenW(testAtom1) * sizeof(WCHAR);
    res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
463
    ok(!res, "atom lookup %x\n", res);
464 465 466
    ok(!lstrcmpW(abi->Name, testAtom1), "strings don't match\n");
    ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "wrong string length\n");
    ok(abi->Name[lstrlenW(testAtom1)] == 0, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1)]);
467
    ok(abi->Name[lstrlenW(testAtom1) + 1] == 0xcccc, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]);
468 469 470 471 472 473 474 475 476

    ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 4 * sizeof(WCHAR);
    abi->Name[0] = abi->Name[1] = abi->Name[2] = abi->Name[3] = '\0';
    res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
    ok(!res, "couldn't find atom\n");
    ok(abi->NameLength == 8, "wrong string length %u\n", abi->NameLength);
    ok(!memcmp(abi->Name, testAtom1, 8), "strings don't match\n");
}

477 478 479 480 481
START_TEST(atom)
{
    InitFunctionPtr();
    if (pRtlCreateAtomTable)
    {
482 483 484 485
        /* Global atom table seems to be available to GUI apps only in
           Win7, so let's turn this app into a GUI app */
        GetDesktopWindow();

486 487 488
        test_NtAtom();
        test_NtIntAtom();
        test_NtRefPinAtom();
489
        test_Global();
490
    }
491 492 493 494
    else
        win_skip("Needed atom functions are not available\n");

    FreeLibrary(hntdll);
495
}