advpack.c 26.4 KB
Newer Older
1 2 3 4
/*
 * Unit tests for advpack.dll
 *
 * Copyright (C) 2005 Robert Reif
5
 * Copyright (C) 2005 Sami Aario
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22
#include <stdio.h>
23
#include <stdarg.h>
24
#include <windows.h>
25
#include <advpub.h>
26
#include <assert.h>
27
#include "wine/test.h"
28

29
/* defines for the TranslateInfString/Ex tests */
30
#define TEST_STRING1 "\\Application Name"
31 32
#define TEST_STRING2 "%49001%\\Application Name"

33 34 35 36 37
/* defines for the SetPerUserSecValues tests */
#define GUID_KEY    "SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\guid"
#define REG_VAL_EXISTS(key, value)   !RegQueryValueEx(key, value, NULL, NULL, NULL, NULL)
#define OPEN_GUID_KEY() !RegOpenKey(HKEY_LOCAL_MACHINE, GUID_KEY, &guid)

38
static HMODULE hAdvPack;
39
static HRESULT (WINAPI *pCloseINFEngine)(HINF);
40
static HRESULT (WINAPI *pDelNode)(LPCSTR,DWORD);
41
static HRESULT (WINAPI *pGetVersionFromFile)(LPCSTR,LPDWORD,LPDWORD,BOOL);
42
static HRESULT (WINAPI *pOpenINFEngine)(PCSTR,PCSTR,DWORD,HINF*,PVOID);
43
static HRESULT (WINAPI *pSetPerUserSecValues)(PPERUSERSECTION pPerUser);
44
static HRESULT (WINAPI *pTranslateInfString)(LPCSTR,LPCSTR,LPCSTR,LPCSTR,LPSTR,DWORD,LPDWORD,LPVOID);
45
static HRESULT (WINAPI *pTranslateInfStringEx)(HINF,PCSTR,PCSTR,PCSTR,PSTR,DWORD,PDWORD,PVOID);
46

47
static CHAR inf_file[MAX_PATH];
48
static CHAR PROG_FILES_ROOT[MAX_PATH];
49
static CHAR PROG_FILES[MAX_PATH];
50 51
static CHAR APP_PATH[MAX_PATH];
static DWORD APP_PATH_LEN;
52 53 54 55 56 57 58

static void get_progfiles_dir(void)
{
    HKEY hkey;
    DWORD size = MAX_PATH;

    RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey);
59
    RegQueryValueExA(hkey, "ProgramFilesDir", NULL, NULL, (LPBYTE)PROG_FILES_ROOT, &size);
60 61
    RegCloseKey(hkey);

62 63 64 65
    lstrcpyA(PROG_FILES, PROG_FILES_ROOT + 3); /* skip C:\ */
    lstrcpyA(APP_PATH, PROG_FILES_ROOT);
    lstrcatA(APP_PATH, TEST_STRING1);
    APP_PATH_LEN = lstrlenA(APP_PATH) + 1;
66 67
}

68 69
static BOOL init_function_pointers(void)
{
70
    hAdvPack = LoadLibraryA("advpack.dll");
71 72 73 74

    if (!hAdvPack)
        return FALSE;

75
    pCloseINFEngine = (void*)GetProcAddress(hAdvPack, "CloseINFEngine");
76 77
    pDelNode = (void *)GetProcAddress(hAdvPack, "DelNode");
    pGetVersionFromFile = (void *)GetProcAddress(hAdvPack, "GetVersionFromFile");
78
    pOpenINFEngine = (void*)GetProcAddress(hAdvPack, "OpenINFEngine");
79
    pSetPerUserSecValues = (void*)GetProcAddress(hAdvPack, "SetPerUserSecValues");
80
    pTranslateInfString = (void *)GetProcAddress(hAdvPack, "TranslateInfString");
81
    pTranslateInfStringEx = (void*)GetProcAddress(hAdvPack, "TranslateInfStringEx");
82

83
    if (!pCloseINFEngine || !pDelNode || !pGetVersionFromFile ||
84
        !pOpenINFEngine || !pSetPerUserSecValues || !pTranslateInfString)
85
    {
86
        win_skip("Needed functions are not available\n");
87
        FreeLibrary(hAdvPack);
88
        return FALSE;
89
    }
90 91 92 93

    return TRUE;
}

94
static void version_test(void)
95 96 97 98 99
{
    HRESULT hr;
    DWORD major, minor;

    major = minor = 0;
100
    hr = pGetVersionFromFile("kernel32.dll", &major, &minor, FALSE);
101
    ok (hr == S_OK, "GetVersionFromFileEx(kernel32.dll) failed, returned "
102 103
        "0x%08x\n", hr);
    trace("kernel32.dll Language ID: 0x%08x, Codepage ID: 0x%08x\n",
104 105 106
           major, minor);

    major = minor = 0;
107
    hr = pGetVersionFromFile("kernel32.dll", &major, &minor, TRUE);
108
    ok (hr == S_OK, "GetVersionFromFileEx(kernel32.dll) failed, returned "
109
        "0x%08x\n", hr);
110 111
    trace("kernel32.dll version: %d.%d.%d.%d\n", HIWORD(major), LOWORD(major),
          HIWORD(minor), LOWORD(minor));
112 113 114 115

    major = minor = 0;
    hr = pGetVersionFromFile("advpack.dll", &major, &minor, FALSE);
    ok (hr == S_OK, "GetVersionFromFileEx(advpack.dll) failed, returned "
116 117
        "0x%08x\n", hr);
    trace("advpack.dll Language ID: 0x%08x, Codepage ID: 0x%08x\n",
118 119 120 121 122
           major, minor);

    major = minor = 0;
    hr = pGetVersionFromFile("advpack.dll", &major, &minor, TRUE);
    ok (hr == S_OK, "GetVersionFromFileEx(advpack.dll) failed, returned "
123
        "0x%08x\n", hr);
124 125
    trace("advpack.dll version: %d.%d.%d.%d\n", HIWORD(major), LOWORD(major),
          HIWORD(minor), LOWORD(minor));
126 127
}

128
static void delnode_test(void)
129 130 131 132
{
    HRESULT hr;
    HANDLE hn;
    CHAR currDir[MAX_PATH];
133
    UINT currDirLen;
134 135 136 137 138 139

    /* Native DelNode apparently does not support relative paths, so we use
       absolute paths for testing */
    currDirLen = GetCurrentDirectoryA(sizeof(currDir) / sizeof(CHAR), currDir);
    assert(currDirLen > 0 && currDirLen < sizeof(currDir) / sizeof(CHAR));

140 141 142
    if(currDir[currDirLen - 1] == '\\')
        currDir[--currDirLen] = 0;

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
    /* Simple tests; these should fail. */
    hr = pDelNode(NULL, 0);
    ok (hr == E_FAIL, "DelNode called with NULL pathname should return E_FAIL\n");
    hr = pDelNode("", 0);
    ok (hr == E_FAIL, "DelNode called with empty pathname should return E_FAIL\n");

    /* Test deletion of a file. */
    hn = CreateFile("DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    assert(hn != INVALID_HANDLE_VALUE);
    CloseHandle(hn);
    hr = pDelNode(lstrcat(currDir, "\\DelNodeTestFile1"), 0);
    ok (hr == S_OK, "DelNode failed deleting a single file\n");
    currDir[currDirLen] = '\0';

    /* Test deletion of an empty directory. */
    CreateDirectoryA("DelNodeTestDir", NULL);
    hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
    ok (hr == S_OK, "DelNode failed deleting an empty directory\n");
    currDir[currDirLen] = '\0';

    /* Test deletion of a directory containing one file. */
    CreateDirectoryA("DelNodeTestDir", NULL);
    hn = CreateFile("DelNodeTestDir\\DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    assert(hn != INVALID_HANDLE_VALUE);
    CloseHandle(hn);
    hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
    ok (hr == S_OK, "DelNode failed deleting a directory containing one file\n");
    currDir[currDirLen] = '\0';

    /* Test deletion of a directory containing multiple files. */
    CreateDirectoryA("DelNodeTestDir", NULL);
    hn = CreateFile("DelNodeTestDir\\DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    assert(hn != INVALID_HANDLE_VALUE);
    CloseHandle(hn);
    hn = CreateFile("DelNodeTestDir\\DelNodeTestFile2", GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    assert(hn != INVALID_HANDLE_VALUE);
    CloseHandle(hn);
    hn = CreateFile("DelNodeTestDir\\DelNodeTestFile3", GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    assert(hn != INVALID_HANDLE_VALUE);
    CloseHandle(hn);
    hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
    ok (hr == S_OK, "DelNode failed deleting a directory containing multiple files\n");
    currDir[currDirLen] = '\0';
}

193
static void append_str(char **str, const char *data, ...)
194
{
195 196 197 198
    va_list valist;

    va_start(valist, data);
    vsprintf(*str, data, valist);
199
    *str += strlen(*str);
200
    va_end(valist);
201 202
}

203
static void create_inf_file(void)
204 205 206
{
    char data[1024];
    char *ptr = data;
Saulius Krasuckas's avatar
Saulius Krasuckas committed
207
    DWORD dwNumberOfBytesWritten;
208
    HANDLE hf = CreateFile(inf_file, GENERIC_WRITE, 0, NULL,
209 210 211 212 213 214
                           CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    append_str(&ptr, "[Version]\n");
    append_str(&ptr, "Signature=\"$Chicago$\"\n");
    append_str(&ptr, "[CustInstDestSection]\n");
    append_str(&ptr, "49001=ProgramFilesDir\n");
215 216 217
    append_str(&ptr, "49010=DestA,1\n");
    append_str(&ptr, "49020=DestB\n");
    append_str(&ptr, "49030=DestC\n");
218 219
    append_str(&ptr, "[ProgramFilesDir]\n");
    append_str(&ptr, "HKLM,\"Software\\Microsoft\\Windows\\CurrentVersion\",");
220
    append_str(&ptr, "\"ProgramFilesDir\",,\"%%24%%\\%%LProgramF%%\"\n");
221 222 223 224 225 226
    append_str(&ptr, "[section]\n");
    append_str(&ptr, "NotACustomDestination=Version\n");
    append_str(&ptr, "CustomDestination=CustInstDestSection\n");
    append_str(&ptr, "[Options.NTx86]\n");
    append_str(&ptr, "49001=ProgramFilesDir\n");
    append_str(&ptr, "InstallDir=%%49001%%\\%%DefaultAppPath%%\n");
227 228 229
    append_str(&ptr, "Result1=%%49010%%\n");
    append_str(&ptr, "Result2=%%49020%%\n");
    append_str(&ptr, "Result3=%%49030%%\n");
230 231 232
    append_str(&ptr, "CustomHDestination=CustInstDestSection\n");
    append_str(&ptr, "[Strings]\n");
    append_str(&ptr, "DefaultAppPath=\"Application Name\"\n");
233
    append_str(&ptr, "LProgramF=\"%s\"\n", PROG_FILES);
234
    append_str(&ptr, "[DestA]\n");
235
    append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%\\%%LProgramF%%'\n");
236 237 238 239 240
    append_str(&ptr, "[DestB]\n");
    append_str(&ptr, "'HKLM','Software\\Microsoft\\Windows\\CurrentVersion',");
    append_str(&ptr, "'ProgramFilesDir',,\"%%24%%\"\n");
    append_str(&ptr, "[DestC]\n");
    append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n");
241

Saulius Krasuckas's avatar
Saulius Krasuckas committed
242
    WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL);
243 244 245
    CloseHandle(hf);
}

246
static void translateinfstring_test(void)
247 248 249 250 251 252 253 254 255 256 257 258 259 260
{
    HRESULT hr;
    char buffer[MAX_PATH];
    DWORD dwSize;

    create_inf_file();

    /* pass in a couple invalid parameters */
    hr = pTranslateInfString(NULL, NULL, NULL, NULL, buffer, MAX_PATH, &dwSize, NULL);
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", (UINT)hr);

    /* try to open an inf file that doesn't exist */
    hr = pTranslateInfString("c:\\a.inf", "Options.NTx86", "Options.NTx86",
                             "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
261 262 263 264 265 266
    ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || hr == E_INVALIDARG || 
       hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), 
       "Expected E_INVALIDARG, 0x80070002 or 0x8007007e, got 0x%08x\n", (UINT)hr);

    if(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND))
    {
267
        win_skip("WinNT 3.51 detected. Skipping tests for TranslateInfString()\n");
268 269
        return;
    }
270 271

    /* try a nonexistent section */
Saulius Krasuckas's avatar
Saulius Krasuckas committed
272
    buffer[0] = 0;
273
    hr = pTranslateInfString(inf_file, "idontexist", "Options.NTx86",
274
                             "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
275 276 277 278 279
    if (hr == E_ACCESSDENIED)
    {
        skip("TranslateInfString is broken\n");
        return;
    }
280 281
    ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", (UINT)hr);
    ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
282
    ok(dwSize == 25, "Expected size 25, got %d\n", dwSize);
283

Saulius Krasuckas's avatar
Saulius Krasuckas committed
284
    buffer[0] = 0;
285
    /* try other nonexistent section */
286
    hr = pTranslateInfString(inf_file, "Options.NTx86", "idontexist",
287
                             "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
Saulius Krasuckas's avatar
Saulius Krasuckas committed
288 289
    ok(hr == SPAPI_E_LINE_NOT_FOUND || hr == E_INVALIDARG, 
       "Expected SPAPI_E_LINE_NOT_FOUND or E_INVALIDARG, got 0x%08x\n", (UINT)hr);
290

Saulius Krasuckas's avatar
Saulius Krasuckas committed
291
    buffer[0] = 0;
292
    /* try nonexistent key */
293
    hr = pTranslateInfString(inf_file, "Options.NTx86", "Options.NTx86",
294
                             "notvalid", buffer, MAX_PATH, &dwSize, NULL);
Saulius Krasuckas's avatar
Saulius Krasuckas committed
295 296
    ok(hr == SPAPI_E_LINE_NOT_FOUND || hr == E_INVALIDARG, 
       "Expected SPAPI_E_LINE_NOT_FOUND or E_INVALIDARG, got 0x%08x\n", (UINT)hr);
297

Saulius Krasuckas's avatar
Saulius Krasuckas committed
298
    buffer[0] = 0;
299
    /* test the behavior of pszInstallSection */
300
    hr = pTranslateInfString(inf_file, "section", "Options.NTx86",
301
                             "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
Saulius Krasuckas's avatar
Saulius Krasuckas committed
302 303
    ok(hr == ERROR_SUCCESS || hr == E_FAIL, 
       "Expected ERROR_SUCCESS or E_FAIL, got 0x%08x\n", (UINT)hr);
304

Saulius Krasuckas's avatar
Saulius Krasuckas committed
305
    if(hr == ERROR_SUCCESS)
306
    {
307 308
        ok(!strcmp(buffer, APP_PATH), "Expected '%s', got '%s'\n", APP_PATH, buffer);
        ok(dwSize == APP_PATH_LEN, "Expected size %d, got %d\n", APP_PATH_LEN, dwSize);
309 310
    }

Saulius Krasuckas's avatar
Saulius Krasuckas committed
311
    buffer[0] = 0;
312
    /* try without a pszInstallSection */
313
    hr = pTranslateInfString(inf_file, NULL, "Options.NTx86",
314 315
                             "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
    ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", (UINT)hr);
316 317 318
    todo_wine
    {
        ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
319
        ok(dwSize == 25, "Expected size 25, got %d\n", dwSize);
320
    }
321

Saulius Krasuckas's avatar
Saulius Krasuckas committed
322
    DeleteFile("c:\\a.inf");
323
    DeleteFile(inf_file);
324 325
}

326 327 328 329 330 331 332
static void translateinfstringex_test(void)
{
    HINF hinf;
    HRESULT hr;
    char buffer[MAX_PATH];
    DWORD size = MAX_PATH;

333 334 335
    hr = pOpenINFEngine(inf_file, NULL, 0, &hinf, NULL);
    if (hr == E_UNEXPECTED)
    {
336
        win_skip("Skipping tests on win9x because of brokenness\n");
337 338 339
        return;
    }

340 341 342 343 344 345
    create_inf_file();
    
    /* need to see if there are any flags */

    /* try a NULL filename */
    hr = pOpenINFEngine(NULL, "Options.NTx86", 0, &hinf, NULL);
346
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
347 348 349

    /* try an empty filename */
    hr = pOpenINFEngine("", "Options.NTx86", 0, &hinf, NULL);
350 351 352
    ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* NT+ */ ||
       hr == HRESULT_FROM_WIN32(E_UNEXPECTED) /* 9x */,
        "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND or E_UNEXPECTED), got %08x\n", hr);
353 354

    /* try a NULL hinf */
355
    hr = pOpenINFEngine(inf_file, "Options.NTx86", 0, NULL, NULL);
356
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
357 358

    /* open the INF without the Install section specified */
359
    hr = pOpenINFEngine(inf_file, NULL, 0, &hinf, NULL);
360
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
361 362

    /* try a NULL hinf */
363
    hr = pTranslateInfStringEx(NULL, inf_file, "Options.NTx86", "InstallDir",
364
                              buffer, size, &size, NULL);
365
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
366 367 368 369

    /* try a NULL filename */
    hr = pTranslateInfStringEx(hinf, NULL, "Options.NTx86", "InstallDir",
                              buffer, size, &size, NULL);
370
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
371 372

    /* try an empty filename */
373 374
    memset(buffer, 'a', 25);
    buffer[24] = '\0';
375 376 377
    size = MAX_PATH;
    hr = pTranslateInfStringEx(hinf, "", "Options.NTx86", "InstallDir",
                              buffer, size, &size, NULL);
378
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
379 380 381
    todo_wine
    {
        ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
382
        ok(size == 25, "Expected size 25, got %d\n", size);
383 384 385
    }

    /* try a NULL translate section */
386
    hr = pTranslateInfStringEx(hinf, inf_file, NULL, "InstallDir",
387
                              buffer, size, &size, NULL);
388
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
389 390

    /* try an empty translate section */
391
    hr = pTranslateInfStringEx(hinf, inf_file, "", "InstallDir",
392
                              buffer, size, &size, NULL);
393
    ok(hr == SPAPI_E_LINE_NOT_FOUND, "Expected SPAPI_E_LINE_NOT_FOUND, got %08x\n", hr);
394 395

    /* try a NULL translate key */
396
    hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", NULL,
397
                              buffer, size, &size, NULL);
398
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
399 400

    /* try an empty translate key */
401
    hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "",
402
                              buffer, size, &size, NULL);
403
    ok(hr == SPAPI_E_LINE_NOT_FOUND, "Expected SPAPI_E_LINE_NOT_FOUND, got %08x\n", hr);
404 405

    /* successfully translate the string */
406 407
    memset(buffer, 'a', 25);
    buffer[24] = '\0';
408
    size = MAX_PATH;
409
    hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "InstallDir",
410
                              buffer, size, &size, NULL);
411
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
412 413 414
    todo_wine
    {
        ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
415
        ok(size == 25, "Expected size 25, got %d\n", size);
416 417 418 419
    }

    /* try a NULL hinf */
    hr = pCloseINFEngine(NULL);
420
    ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
421 422 423

    /* successfully close the hinf */
    hr = pCloseINFEngine(hinf);
424
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
425 426

    /* open the inf with the install section */
427
    hr = pOpenINFEngine(inf_file, "section", 0, &hinf, NULL);
428
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
429 430

    /* translate the string with the install section specified */
431 432
    memset(buffer, 'a', APP_PATH_LEN);
    buffer[APP_PATH_LEN - 1] = '\0';
433
    size = MAX_PATH;
434
    hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "InstallDir",
435
                              buffer, size, &size, NULL);
436
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
437 438
    ok(!strcmp(buffer, APP_PATH), "Expected %s, got %s\n", APP_PATH, buffer);
    ok(size == APP_PATH_LEN, "Expected size %d, got %d\n", APP_PATH_LEN, size);
439

440
    /* Single quote test (Note size includes null on return from call) */
441 442
    memset(buffer, 'a', APP_PATH_LEN);
    buffer[APP_PATH_LEN - 1] = '\0';
443 444 445 446
    size = MAX_PATH;
    hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result1",
                              buffer, size, &size, NULL);
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
447 448
    ok(!lstrcmpi(buffer, PROG_FILES_ROOT),
           "Expected %s, got %s\n", PROG_FILES_ROOT, buffer);
449
    ok(size == strlen(PROG_FILES_ROOT)+1, "Expected size %d, got %d\n",
450
           lstrlenA(PROG_FILES_ROOT)+1, size);
451

452 453
    memset(buffer, 'a', APP_PATH_LEN);
    buffer[APP_PATH_LEN - 1] = '\0';
454 455 456 457 458 459
    size = MAX_PATH;
    hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result2",
                              buffer, size, &size, NULL);
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
    ok(!lstrcmpi(buffer, PROG_FILES_ROOT),
           "Expected %s, got %s\n", PROG_FILES_ROOT, buffer);
460
    ok(size == strlen(PROG_FILES_ROOT)+1, "Expected size %d, got %d\n",
461 462 463 464 465 466 467
           lstrlenA(PROG_FILES_ROOT)+1, size);

    {
        char drive[MAX_PATH];
        lstrcpy(drive, PROG_FILES_ROOT);
        drive[3] = 0x00; /* Just keep the system drive plus '\' */

468 469
        memset(buffer, 'a', APP_PATH_LEN);
        buffer[APP_PATH_LEN - 1] = '\0';
470 471 472 473 474 475
        size = MAX_PATH;
        hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result3",
                                  buffer, size, &size, NULL);
        ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
        ok(!lstrcmpi(buffer, drive),
               "Expected %s, got %s\n", drive, buffer);
476
        ok(size == strlen(drive)+1, "Expected size %d, got %d\n",
477 478 479
               lstrlenA(drive)+1, size);
    }

480 481
    /* close the INF again */
    hr = pCloseINFEngine(hinf);
482
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
483

484
    DeleteFileA(inf_file);
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533

    /* Create another .inf file which is just here to trigger a wine bug */
    {
        char data[1024];
        char *ptr = data;
        DWORD dwNumberOfBytesWritten;
        HANDLE hf = CreateFile(inf_file, GENERIC_WRITE, 0, NULL,
                           CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

        append_str(&ptr, "[Version]\n");
        append_str(&ptr, "Signature=\"$Chicago$\"\n");
        append_str(&ptr, "[section]\n");
        append_str(&ptr, "NotACustomDestination=Version\n");
        append_str(&ptr, "CustomDestination=CustInstDestSection\n");
        append_str(&ptr, "[CustInstDestSection]\n");
        append_str(&ptr, "49010=DestA,1\n");
        append_str(&ptr, "49020=DestB\n");
        append_str(&ptr, "49030=DestC\n");
        append_str(&ptr, "49040=DestD\n");
        append_str(&ptr, "[Options.NTx86]\n");
        append_str(&ptr, "Result2=%%49030%%\n");
        append_str(&ptr, "[DestA]\n");
        append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n");
        /* The point of this test is to have HKCU just before the quoted HKLM */
        append_str(&ptr, "[DestB]\n");
        append_str(&ptr, "HKCU,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n");
        append_str(&ptr, "[DestC]\n");
        append_str(&ptr, "'HKLM','Software\\Microsoft\\Windows\\CurrentVersion',");
        append_str(&ptr, "'ProgramFilesDir',,\"%%24%%\"\n");
        append_str(&ptr, "[DestD]\n");
        append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n");

        WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL);
        CloseHandle(hf);
    }

    /* open the inf with the install section */
    hr = pOpenINFEngine(inf_file, "section", 0, &hinf, NULL);
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);

    /* Single quote test (Note size includes null on return from call) */
    memset(buffer, 'a', APP_PATH_LEN);
    buffer[APP_PATH_LEN - 1] = '\0';
    size = MAX_PATH;
    hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result2",
                              buffer, size, &size, NULL);
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
    ok(!lstrcmpi(buffer, PROG_FILES_ROOT),
           "Expected %s, got %s\n", PROG_FILES_ROOT, buffer);
534
    ok(size == strlen(PROG_FILES_ROOT)+1, "Expected size %d, got %d\n",
535 536 537 538 539 540 541
           lstrlenA(PROG_FILES_ROOT)+1, size);

    /* close the INF again */
    hr = pCloseINFEngine(hinf);
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);

    DeleteFileA(inf_file);
542 543
}

544
static BOOL check_reg_str(HKEY hkey, LPCSTR name, LPCSTR value)
545 546 547 548 549 550 551 552 553 554
{
    DWORD size = MAX_PATH;
    char check[MAX_PATH];

    if (RegQueryValueEx(hkey, name, NULL, NULL, (LPBYTE)check, &size))
        return FALSE;

    return !lstrcmp(check, value);
}

555
static BOOL check_reg_dword(HKEY hkey, LPCSTR name, DWORD value)
556 557 558 559 560 561 562 563 564 565
{
    DWORD size = sizeof(DWORD);
    DWORD check;

    if (RegQueryValueEx(hkey, name, NULL, NULL, (LPBYTE)&check, &size))
        return FALSE;

    return (check == value);
}

566
static void setperusersecvalues_test(void)
567 568 569 570 571 572 573 574 575 576 577 578 579
{
    PERUSERSECTION peruser;
    HRESULT hr;
    HKEY guid;

    lstrcpy(peruser.szDispName, "displayname");
    lstrcpy(peruser.szLocale, "locale");
    lstrcpy(peruser.szStub, "stub");
    lstrcpy(peruser.szVersion, "1,1,1,1");
    lstrcpy(peruser.szCompID, "compid");
    peruser.dwIsInstalled = 1;
    peruser.bRollback = FALSE;

580
    /* try a NULL pPerUser */
581 582 583 584 585 586 587 588
    if (0)
    {
        /* This crashes on systems with IE7 */
        hr = pSetPerUserSecValues(NULL);
        todo_wine
        ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
        ok(!OPEN_GUID_KEY(), "Expected guid key to not exist\n");
    }
589 590 591 592

    /* at the very least, szGUID must be valid */
    peruser.szGUID[0] = '\0';
    hr = pSetPerUserSecValues(&peruser);
593
    ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
594 595
    ok(!OPEN_GUID_KEY(), "Expected guid key to not exist\n");

596
    /* set initial values */
597
    lstrcpy(peruser.szGUID, "guid");
598
    hr = pSetPerUserSecValues(&peruser);
599 600 601 602 603
    if (hr == E_FAIL)
    {
        skip("SetPerUserSecValues is broken\n");
        return;
    }
604
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
605 606 607 608 609 610 611
    ok(OPEN_GUID_KEY(), "Expected guid key to exist\n");
    ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n");
    ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n");
    ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n");
    ok(check_reg_str(guid, "StubPath", "stub"), "Expected stub\n");
    ok(check_reg_str(guid, "Version", "1,1,1,1"), "Expected 1,1,1,1\n");
    ok(check_reg_dword(guid, "IsInstalled", 1), "Expected 1\n");
612 613 614 615 616 617 618 619 620
    ok(!REG_VAL_EXISTS(guid, "OldDisplayName"), "Expected OldDisplayName to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "OldLocale"), "Expected OldLocale to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "OldStubPath"), "Expected OldStubPath to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "OldVersion"), "Expected OldVersion to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "RealStubPath"), "Expected RealStubPath to not exist\n");

    /* raise the version, but bRollback is FALSE, so vals not saved */
    lstrcpy(peruser.szVersion, "2,1,1,1");
    hr = pSetPerUserSecValues(&peruser);
621
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
622 623 624 625 626 627
    ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n");
    ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n");
    ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n");
    ok(check_reg_str(guid, "StubPath", "stub"), "Expected stub\n");
    ok(check_reg_str(guid, "Version", "2,1,1,1"), "Expected 2,1,1,1\n");
    ok(check_reg_dword(guid, "IsInstalled", 1), "Expected 1\n");
628 629 630 631 632 633 634
    ok(!REG_VAL_EXISTS(guid, "OldDisplayName"), "Expected OldDisplayName to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "OldLocale"), "Expected OldLocale to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "OldStubPath"), "Expected OldStubPath to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "OldVersion"), "Expected OldVersion to not exist\n");
    ok(!REG_VAL_EXISTS(guid, "RealStubPath"), "Expected RealStubPath to not exist\n");

    /* raise the version again, bRollback is TRUE so vals are saved */
635
    peruser.bRollback = TRUE;
636 637
    lstrcpy(peruser.szVersion, "3,1,1,1");
    hr = pSetPerUserSecValues(&peruser);
638
    ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
639 640 641 642 643
    ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n");
    ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n");
    ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n");
    ok(check_reg_dword(guid, "IsInstalled", 1), "Expected 1\n");
    ok(check_reg_str(guid, "Version", "3,1,1,1"), "Expected 3,1,1,1\n");
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
    todo_wine
    {
        ok(check_reg_str(guid, "OldDisplayName", "displayname"), "Expected displayname\n");
        ok(check_reg_str(guid, "OldLocale", "locale"), "Expected locale\n");
        ok(check_reg_str(guid, "RealStubPath", "stub"), "Expected stub\n");
        ok(check_reg_str(guid, "OldStubPath", "stub"), "Expected stub\n");
        ok(check_reg_str(guid, "OldVersion", "2,1,1,1"), "Expected 2,1,1,1\n");
        ok(check_reg_str(guid, "StubPath",
           "rundll32.exe advpack.dll,UserInstStubWrapper guid"),
           "Expected real stub\n");
    }

    RegDeleteKey(HKEY_LOCAL_MACHINE, GUID_KEY);
}

659 660
START_TEST(advpack)
{
661
    if (!init_function_pointers())
662 663
        return;

664 665 666 667 668 669
    /* Make sure we create the temporary file in a directory
     * were we have enough rights
     */
    GetTempPath(MAX_PATH, inf_file);
    lstrcat(inf_file,"test.inf");

670 671
    get_progfiles_dir();

672
    version_test();
673
    delnode_test();
674
    setperusersecvalues_test();
675
    translateinfstring_test();
676
    translateinfstringex_test();
677 678

    FreeLibrary(hAdvPack);
679
}