advpack/tests: Show errors in hex.
[wine] / dlls / advpack / tests / advpack.c
1 /*
2  * Unit tests for advpack.dll
3  *
4  * Copyright (C) 2005 Robert Reif
5  * Copyright (C) 2005 Sami Aario
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * 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 #define TEST_STRING2 "%49001%\\Application Name"
32
33 /* defines for the SetPerUserSecValues tests */
34 #define GUID_KEY    "SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\guid"
35 #define REG_VAL_EXISTS(key, value)   !RegQueryValueEx(key, value, NULL, NULL, NULL, NULL)
36 #define OPEN_GUID_KEY() !RegOpenKey(HKEY_LOCAL_MACHINE, GUID_KEY, &guid)
37
38 static HRESULT (WINAPI *pCloseINFEngine)(HINF);
39 static HRESULT (WINAPI *pDelNode)(LPCSTR,DWORD);
40 static HRESULT (WINAPI *pGetVersionFromFile)(LPCSTR,LPDWORD,LPDWORD,BOOL);
41 static HRESULT (WINAPI *pOpenINFEngine)(PCSTR,PCSTR,DWORD,HINF*,PVOID);
42 static HRESULT (WINAPI *pSetPerUserSecValues)(PPERUSERSECTION pPerUser);
43 static HRESULT (WINAPI *pTranslateInfString)(LPCSTR,LPCSTR,LPCSTR,LPCSTR,LPSTR,DWORD,LPDWORD,LPVOID);
44 static HRESULT (WINAPI *pTranslateInfStringEx)(HINF,PCSTR,PCSTR,PCSTR,PSTR,DWORD,PDWORD,PVOID);
45
46 static CHAR inf_file[MAX_PATH];
47 static CHAR PROG_FILES_ROOT[MAX_PATH];
48 static CHAR PROG_FILES[MAX_PATH];
49 static CHAR APP_PATH[MAX_PATH];
50 static DWORD APP_PATH_LEN;
51
52 static void get_progfiles_dir(void)
53 {
54     HKEY hkey;
55     DWORD size = MAX_PATH;
56
57     RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey);
58     RegQueryValueExA(hkey, "ProgramFilesDir", NULL, NULL, (LPBYTE)PROG_FILES_ROOT, &size);
59     RegCloseKey(hkey);
60
61     lstrcpyA(PROG_FILES, PROG_FILES_ROOT + 3); /* skip C:\ */
62     lstrcpyA(APP_PATH, PROG_FILES_ROOT);
63     lstrcatA(APP_PATH, TEST_STRING1);
64     APP_PATH_LEN = lstrlenA(APP_PATH) + 1;
65 }
66
67 static BOOL init_function_pointers(void)
68 {
69     HMODULE hAdvPack = LoadLibraryA("advpack.dll");
70
71     if (!hAdvPack)
72         return FALSE;
73
74     pCloseINFEngine = (void*)GetProcAddress(hAdvPack, "CloseINFEngine");
75     pDelNode = (void *)GetProcAddress(hAdvPack, "DelNode");
76     pGetVersionFromFile = (void *)GetProcAddress(hAdvPack, "GetVersionFromFile");
77     pOpenINFEngine = (void*)GetProcAddress(hAdvPack, "OpenINFEngine");
78     pSetPerUserSecValues = (void*)GetProcAddress(hAdvPack, "SetPerUserSecValues");
79     pTranslateInfString = (void *)GetProcAddress(hAdvPack, "TranslateInfString");
80     pTranslateInfStringEx = (void*)GetProcAddress(hAdvPack, "TranslateInfStringEx");
81
82     if (!pCloseINFEngine || !pDelNode || !pGetVersionFromFile ||
83         !pOpenINFEngine || !pSetPerUserSecValues || !pTranslateInfString)
84         return FALSE;
85
86     return TRUE;
87 }
88
89 static void version_test(void)
90 {
91     HRESULT hr;
92     DWORD major, minor;
93
94     major = minor = 0;
95     hr = pGetVersionFromFile("kernel32.dll", &major, &minor, FALSE);
96     ok (hr == S_OK, "GetVersionFromFileEx(kernel32.dll) failed, returned "
97         "0x%08x\n", hr);
98     trace("kernel32.dll Language ID: 0x%08x, Codepage ID: 0x%08x\n",
99            major, minor);
100
101     major = minor = 0;
102     hr = pGetVersionFromFile("kernel32.dll", &major, &minor, TRUE);
103     ok (hr == S_OK, "GetVersionFromFileEx(kernel32.dll) failed, returned "
104         "0x%08x\n", hr);
105     trace("kernel32.dll version: %d.%d.%d.%d\n", HIWORD(major), LOWORD(major),
106           HIWORD(minor), LOWORD(minor));
107
108     major = minor = 0;
109     hr = pGetVersionFromFile("advpack.dll", &major, &minor, FALSE);
110     ok (hr == S_OK, "GetVersionFromFileEx(advpack.dll) failed, returned "
111         "0x%08x\n", hr);
112     trace("advpack.dll Language ID: 0x%08x, Codepage ID: 0x%08x\n",
113            major, minor);
114
115     major = minor = 0;
116     hr = pGetVersionFromFile("advpack.dll", &major, &minor, TRUE);
117     ok (hr == S_OK, "GetVersionFromFileEx(advpack.dll) failed, returned "
118         "0x%08x\n", hr);
119     trace("advpack.dll version: %d.%d.%d.%d\n", HIWORD(major), LOWORD(major),
120           HIWORD(minor), LOWORD(minor));
121 }
122
123 static void delnode_test(void)
124 {
125     HRESULT hr;
126     HANDLE hn;
127     CHAR currDir[MAX_PATH];
128     int currDirLen;
129
130     /* Native DelNode apparently does not support relative paths, so we use
131        absolute paths for testing */
132     currDirLen = GetCurrentDirectoryA(sizeof(currDir) / sizeof(CHAR), currDir);
133     assert(currDirLen > 0 && currDirLen < sizeof(currDir) / sizeof(CHAR));
134
135     if(currDir[currDirLen - 1] == '\\')
136         currDir[--currDirLen] = 0;
137
138     /* Simple tests; these should fail. */
139     hr = pDelNode(NULL, 0);
140     ok (hr == E_FAIL, "DelNode called with NULL pathname should return E_FAIL\n");
141     hr = pDelNode("", 0);
142     ok (hr == E_FAIL, "DelNode called with empty pathname should return E_FAIL\n");
143
144     /* Test deletion of a file. */
145     hn = CreateFile("DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
146         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
147     assert(hn != INVALID_HANDLE_VALUE);
148     CloseHandle(hn);
149     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestFile1"), 0);
150     ok (hr == S_OK, "DelNode failed deleting a single file\n");
151     currDir[currDirLen] = '\0';
152
153     /* Test deletion of an empty directory. */
154     CreateDirectoryA("DelNodeTestDir", NULL);
155     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
156     ok (hr == S_OK, "DelNode failed deleting an empty directory\n");
157     currDir[currDirLen] = '\0';
158
159     /* Test deletion of a directory containing one file. */
160     CreateDirectoryA("DelNodeTestDir", NULL);
161     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
162         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
163     assert(hn != INVALID_HANDLE_VALUE);
164     CloseHandle(hn);
165     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
166     ok (hr == S_OK, "DelNode failed deleting a directory containing one file\n");
167     currDir[currDirLen] = '\0';
168
169     /* Test deletion of a directory containing multiple files. */
170     CreateDirectoryA("DelNodeTestDir", NULL);
171     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
172         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
173     assert(hn != INVALID_HANDLE_VALUE);
174     CloseHandle(hn);
175     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile2", GENERIC_WRITE, 0, NULL,
176         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
177     assert(hn != INVALID_HANDLE_VALUE);
178     CloseHandle(hn);
179     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile3", GENERIC_WRITE, 0, NULL,
180         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
181     assert(hn != INVALID_HANDLE_VALUE);
182     CloseHandle(hn);
183     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
184     ok (hr == S_OK, "DelNode failed deleting a directory containing multiple files\n");
185     currDir[currDirLen] = '\0';
186 }
187
188 static void append_str(char **str, const char *data, ...)
189 {
190     va_list valist;
191
192     va_start(valist, data);
193     vsprintf(*str, data, valist);
194     *str += strlen(*str);
195     va_end(valist);
196 }
197
198 static void create_inf_file(void)
199 {
200     char data[1024];
201     char *ptr = data;
202     DWORD dwNumberOfBytesWritten;
203     HANDLE hf = CreateFile(inf_file, GENERIC_WRITE, 0, NULL,
204                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
205
206     append_str(&ptr, "[Version]\n");
207     append_str(&ptr, "Signature=\"$Chicago$\"\n");
208     append_str(&ptr, "[CustInstDestSection]\n");
209     append_str(&ptr, "49001=ProgramFilesDir\n");
210     append_str(&ptr, "49010=DestA,1\n");
211     append_str(&ptr, "49020=DestB\n");
212     append_str(&ptr, "49030=DestC\n");
213     append_str(&ptr, "[ProgramFilesDir]\n");
214     append_str(&ptr, "HKLM,\"Software\\Microsoft\\Windows\\CurrentVersion\",");
215     append_str(&ptr, "\"ProgramFilesDir\",,\"%%24%%\\%%LProgramF%%\"\n");
216     append_str(&ptr, "[section]\n");
217     append_str(&ptr, "NotACustomDestination=Version\n");
218     append_str(&ptr, "CustomDestination=CustInstDestSection\n");
219     append_str(&ptr, "[Options.NTx86]\n");
220     append_str(&ptr, "49001=ProgramFilesDir\n");
221     append_str(&ptr, "InstallDir=%%49001%%\\%%DefaultAppPath%%\n");
222     append_str(&ptr, "Result1=%%49010%%\n");
223     append_str(&ptr, "Result2=%%49020%%\n");
224     append_str(&ptr, "Result3=%%49030%%\n");
225     append_str(&ptr, "CustomHDestination=CustInstDestSection\n");
226     append_str(&ptr, "[Strings]\n");
227     append_str(&ptr, "DefaultAppPath=\"Application Name\"\n");
228     append_str(&ptr, "LProgramF=\"%s\"\n", PROG_FILES);
229     append_str(&ptr, "[DestA]\n");
230     append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%\\%%LProgramF%%'\n");
231     append_str(&ptr, "[DestB]\n");
232     append_str(&ptr, "'HKLM','Software\\Microsoft\\Windows\\CurrentVersion',");
233     append_str(&ptr, "'ProgramFilesDir',,\"%%24%%\"\n");
234     append_str(&ptr, "[DestC]\n");
235     append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n");
236
237     WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL);
238     CloseHandle(hf);
239 }
240
241 static void translateinfstring_test(void)
242 {
243     HRESULT hr;
244     char buffer[MAX_PATH];
245     DWORD dwSize;
246
247     create_inf_file();
248
249     /* pass in a couple invalid parameters */
250     hr = pTranslateInfString(NULL, NULL, NULL, NULL, buffer, MAX_PATH, &dwSize, NULL);
251     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", (UINT)hr);
252
253     /* try to open an inf file that doesn't exist */
254     hr = pTranslateInfString("c:\\a.inf", "Options.NTx86", "Options.NTx86",
255                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
256     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || hr == E_INVALIDARG || 
257        hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), 
258        "Expected E_INVALIDARG, 0x80070002 or 0x8007007e, got 0x%08x\n", (UINT)hr);
259
260     if(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND))
261     {
262         trace("WinNT 3.51 detected. Skipping tests for TranslateInfString()\n");
263         return;
264     }
265
266     /* try a nonexistent section */
267     buffer[0] = 0;
268     hr = pTranslateInfString(inf_file, "idontexist", "Options.NTx86",
269                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
270     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", (UINT)hr);
271     ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
272     ok(dwSize == 25, "Expected size 25, got %d\n", dwSize);
273
274     buffer[0] = 0;
275     /* try other nonexistent section */
276     hr = pTranslateInfString(inf_file, "Options.NTx86", "idontexist",
277                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
278     ok(hr == SPAPI_E_LINE_NOT_FOUND || hr == E_INVALIDARG, 
279        "Expected SPAPI_E_LINE_NOT_FOUND or E_INVALIDARG, got 0x%08x\n", (UINT)hr);
280
281     buffer[0] = 0;
282     /* try nonexistent key */
283     hr = pTranslateInfString(inf_file, "Options.NTx86", "Options.NTx86",
284                              "notvalid", buffer, MAX_PATH, &dwSize, NULL);
285     ok(hr == SPAPI_E_LINE_NOT_FOUND || hr == E_INVALIDARG, 
286        "Expected SPAPI_E_LINE_NOT_FOUND or E_INVALIDARG, got 0x%08x\n", (UINT)hr);
287
288     buffer[0] = 0;
289     /* test the behavior of pszInstallSection */
290     hr = pTranslateInfString(inf_file, "section", "Options.NTx86",
291                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
292     ok(hr == ERROR_SUCCESS || hr == E_FAIL, 
293        "Expected ERROR_SUCCESS or E_FAIL, got 0x%08x\n", (UINT)hr);
294
295     if(hr == ERROR_SUCCESS)
296     {
297         ok(!strcmp(buffer, APP_PATH), "Expected '%s', got '%s'\n", APP_PATH, buffer);
298         ok(dwSize == APP_PATH_LEN, "Expected size %d, got %d\n", APP_PATH_LEN, dwSize);
299     }
300
301     buffer[0] = 0;
302     /* try without a pszInstallSection */
303     hr = pTranslateInfString(inf_file, NULL, "Options.NTx86",
304                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
305     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", (UINT)hr);
306     todo_wine
307     {
308         ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
309         ok(dwSize == 25, "Expected size 25, got %d\n", dwSize);
310     }
311
312     DeleteFile("c:\\a.inf");
313     DeleteFile(inf_file);
314 }
315
316 static void translateinfstringex_test(void)
317 {
318     HINF hinf;
319     HRESULT hr;
320     char buffer[MAX_PATH];
321     DWORD size = MAX_PATH;
322
323     create_inf_file();
324     
325     /* need to see if there are any flags */
326
327     /* try a NULL filename */
328     hr = pOpenINFEngine(NULL, "Options.NTx86", 0, &hinf, NULL);
329     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
330
331     /* try an empty filename */
332     hr = pOpenINFEngine("", "Options.NTx86", 0, &hinf, NULL);
333     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
334         "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr);
335
336     /* try a NULL hinf */
337     hr = pOpenINFEngine(inf_file, "Options.NTx86", 0, NULL, NULL);
338     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
339
340     /* open the INF without the Install section specified */
341     hr = pOpenINFEngine(inf_file, NULL, 0, &hinf, NULL);
342     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
343
344     /* try a NULL hinf */
345     hr = pTranslateInfStringEx(NULL, inf_file, "Options.NTx86", "InstallDir",
346                               buffer, size, &size, NULL);
347     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
348
349     /* try a NULL filename */
350     hr = pTranslateInfStringEx(hinf, NULL, "Options.NTx86", "InstallDir",
351                               buffer, size, &size, NULL);
352     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
353
354     /* try an empty filename */
355     memset(buffer, 'a', 25);
356     buffer[24] = '\0';
357     size = MAX_PATH;
358     hr = pTranslateInfStringEx(hinf, "", "Options.NTx86", "InstallDir",
359                               buffer, size, &size, NULL);
360     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
361     todo_wine
362     {
363         ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
364         ok(size == 25, "Expected size 25, got %d\n", size);
365     }
366
367     /* try a NULL translate section */
368     hr = pTranslateInfStringEx(hinf, inf_file, NULL, "InstallDir",
369                               buffer, size, &size, NULL);
370     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
371
372     /* try an empty translate section */
373     hr = pTranslateInfStringEx(hinf, inf_file, "", "InstallDir",
374                               buffer, size, &size, NULL);
375     ok(hr == SPAPI_E_LINE_NOT_FOUND, "Expected SPAPI_E_LINE_NOT_FOUND, got %08x\n", hr);
376
377     /* try a NULL translate key */
378     hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", NULL,
379                               buffer, size, &size, NULL);
380     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
381
382     /* try an empty translate key */
383     hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "",
384                               buffer, size, &size, NULL);
385     ok(hr == SPAPI_E_LINE_NOT_FOUND, "Expected SPAPI_E_LINE_NOT_FOUND, got %08x\n", hr);
386
387     /* successfully translate the string */
388     memset(buffer, 'a', 25);
389     buffer[24] = '\0';
390     size = MAX_PATH;
391     hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "InstallDir",
392                               buffer, size, &size, NULL);
393     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
394     todo_wine
395     {
396         ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
397         ok(size == 25, "Expected size 25, got %d\n", size);
398     }
399
400     /* try a NULL hinf */
401     hr = pCloseINFEngine(NULL);
402     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
403
404     /* successfully close the hinf */
405     hr = pCloseINFEngine(hinf);
406     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
407
408     /* open the inf with the install section */
409     hr = pOpenINFEngine(inf_file, "section", 0, &hinf, NULL);
410     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
411
412     /* translate the string with the install section specified */
413     memset(buffer, 'a', APP_PATH_LEN);
414     buffer[APP_PATH_LEN - 1] = '\0';
415     size = MAX_PATH;
416     hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "InstallDir",
417                               buffer, size, &size, NULL);
418     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
419     ok(!strcmp(buffer, APP_PATH), "Expected %s, got %s\n", APP_PATH, buffer);
420     ok(size == APP_PATH_LEN, "Expected size %d, got %d\n", APP_PATH_LEN, size);
421
422     /* Single quote test (Note size includes null on return from call) */
423     memset(buffer, 'a', APP_PATH_LEN);
424     buffer[APP_PATH_LEN - 1] = '\0';
425     size = MAX_PATH;
426     hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result1",
427                               buffer, size, &size, NULL);
428     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
429     ok(!lstrcmpi(buffer, PROG_FILES_ROOT),
430            "Expected %s, got %s\n", PROG_FILES_ROOT, buffer);
431     ok(size == lstrlenA(PROG_FILES_ROOT)+1, "Expected size %d, got %d\n",
432            lstrlenA(PROG_FILES_ROOT)+1, size);
433
434     memset(buffer, 'a', APP_PATH_LEN);
435     buffer[APP_PATH_LEN - 1] = '\0';
436     size = MAX_PATH;
437     hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result2",
438                               buffer, size, &size, NULL);
439     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
440     ok(!lstrcmpi(buffer, PROG_FILES_ROOT),
441            "Expected %s, got %s\n", PROG_FILES_ROOT, buffer);
442     ok(size == lstrlenA(PROG_FILES_ROOT)+1, "Expected size %d, got %d\n",
443            lstrlenA(PROG_FILES_ROOT)+1, size);
444
445     {
446         char drive[MAX_PATH];
447         lstrcpy(drive, PROG_FILES_ROOT);
448         drive[3] = 0x00; /* Just keep the system drive plus '\' */
449
450         memset(buffer, 'a', APP_PATH_LEN);
451         buffer[APP_PATH_LEN - 1] = '\0';
452         size = MAX_PATH;
453         hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result3",
454                                   buffer, size, &size, NULL);
455         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
456         ok(!lstrcmpi(buffer, drive),
457                "Expected %s, got %s\n", drive, buffer);
458         ok(size == lstrlenA(drive)+1, "Expected size %d, got %d\n",
459                lstrlenA(drive)+1, size);
460     }
461
462     /* close the INF again */
463     hr = pCloseINFEngine(hinf);
464     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
465
466     DeleteFileA(inf_file);
467 }
468
469 static BOOL check_reg_str(HKEY hkey, LPCSTR name, LPCSTR value)
470 {
471     DWORD size = MAX_PATH;
472     char check[MAX_PATH];
473
474     if (RegQueryValueEx(hkey, name, NULL, NULL, (LPBYTE)check, &size))
475         return FALSE;
476
477     return !lstrcmp(check, value);
478 }
479
480 static BOOL check_reg_dword(HKEY hkey, LPCSTR name, DWORD value)
481 {
482     DWORD size = sizeof(DWORD);
483     DWORD check;
484
485     if (RegQueryValueEx(hkey, name, NULL, NULL, (LPBYTE)&check, &size))
486         return FALSE;
487
488     return (check == value);
489 }
490
491 static void setperusersecvalues_test(void)
492 {
493     PERUSERSECTION peruser;
494     HRESULT hr;
495     HKEY guid;
496
497     lstrcpy(peruser.szDispName, "displayname");
498     lstrcpy(peruser.szLocale, "locale");
499     lstrcpy(peruser.szStub, "stub");
500     lstrcpy(peruser.szVersion, "1,1,1,1");
501     lstrcpy(peruser.szCompID, "compid");
502     peruser.dwIsInstalled = 1;
503     peruser.bRollback = FALSE;
504
505     /* try a NULL pPerUser */
506     if (0)
507     {
508         /* This crashes on systems with IE7 */
509         hr = pSetPerUserSecValues(NULL);
510         todo_wine
511         ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
512         ok(!OPEN_GUID_KEY(), "Expected guid key to not exist\n");
513     }
514
515     /* at the very least, szGUID must be valid */
516     peruser.szGUID[0] = '\0';
517     hr = pSetPerUserSecValues(&peruser);
518     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
519     ok(!OPEN_GUID_KEY(), "Expected guid key to not exist\n");
520
521     /* set initial values */
522     lstrcpy(peruser.szGUID, "guid");
523     hr = pSetPerUserSecValues(&peruser);
524     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
525     ok(OPEN_GUID_KEY(), "Expected guid key to exist\n");
526     ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n");
527     ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n");
528     ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n");
529     ok(check_reg_str(guid, "StubPath", "stub"), "Expected stub\n");
530     ok(check_reg_str(guid, "Version", "1,1,1,1"), "Expected 1,1,1,1\n");
531     ok(check_reg_dword(guid, "IsInstalled", 1), "Expected 1\n");
532     ok(!REG_VAL_EXISTS(guid, "OldDisplayName"), "Expected OldDisplayName to not exist\n");
533     ok(!REG_VAL_EXISTS(guid, "OldLocale"), "Expected OldLocale to not exist\n");
534     ok(!REG_VAL_EXISTS(guid, "OldStubPath"), "Expected OldStubPath to not exist\n");
535     ok(!REG_VAL_EXISTS(guid, "OldVersion"), "Expected OldVersion to not exist\n");
536     ok(!REG_VAL_EXISTS(guid, "RealStubPath"), "Expected RealStubPath to not exist\n");
537
538     /* raise the version, but bRollback is FALSE, so vals not saved */
539     lstrcpy(peruser.szVersion, "2,1,1,1");
540     hr = pSetPerUserSecValues(&peruser);
541     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
542     ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n");
543     ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n");
544     ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n");
545     ok(check_reg_str(guid, "StubPath", "stub"), "Expected stub\n");
546     ok(check_reg_str(guid, "Version", "2,1,1,1"), "Expected 2,1,1,1\n");
547     ok(check_reg_dword(guid, "IsInstalled", 1), "Expected 1\n");
548     ok(!REG_VAL_EXISTS(guid, "OldDisplayName"), "Expected OldDisplayName to not exist\n");
549     ok(!REG_VAL_EXISTS(guid, "OldLocale"), "Expected OldLocale to not exist\n");
550     ok(!REG_VAL_EXISTS(guid, "OldStubPath"), "Expected OldStubPath to not exist\n");
551     ok(!REG_VAL_EXISTS(guid, "OldVersion"), "Expected OldVersion to not exist\n");
552     ok(!REG_VAL_EXISTS(guid, "RealStubPath"), "Expected RealStubPath to not exist\n");
553
554     /* raise the version again, bRollback is TRUE so vals are saved */
555     peruser.bRollback = TRUE;
556     lstrcpy(peruser.szVersion, "3,1,1,1");
557     hr = pSetPerUserSecValues(&peruser);
558     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
559     ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n");
560     ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n");
561     ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n");
562     ok(check_reg_dword(guid, "IsInstalled", 1), "Expected 1\n");
563     ok(check_reg_str(guid, "Version", "3,1,1,1"), "Expected 3,1,1,1\n");
564     todo_wine
565     {
566         ok(check_reg_str(guid, "OldDisplayName", "displayname"), "Expected displayname\n");
567         ok(check_reg_str(guid, "OldLocale", "locale"), "Expected locale\n");
568         ok(check_reg_str(guid, "RealStubPath", "stub"), "Expected stub\n");
569         ok(check_reg_str(guid, "OldStubPath", "stub"), "Expected stub\n");
570         ok(check_reg_str(guid, "OldVersion", "2,1,1,1"), "Expected 2,1,1,1\n");
571         ok(check_reg_str(guid, "StubPath",
572            "rundll32.exe advpack.dll,UserInstStubWrapper guid"),
573            "Expected real stub\n");
574     }
575
576     RegDeleteKey(HKEY_LOCAL_MACHINE, GUID_KEY);
577 }
578
579 START_TEST(advpack)
580 {
581     if (!init_function_pointers())
582         return;
583
584     /* Make sure we create the temporary file in a directory
585      * were we have enough rights
586      */
587     GetTempPath(MAX_PATH, inf_file);
588     lstrcat(inf_file,"test.inf");
589
590     get_progfiles_dir();
591
592     version_test();
593     delnode_test();
594     setperusersecvalues_test();
595     translateinfstring_test();
596     translateinfstringex_test();
597 }