advpack: Add tests for the TranslateInfStringEx trio of functions and
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdio.h>
23 #include <windows.h>
24 #include <advpub.h>
25 #include <assert.h>
26 #include "wine/test.h"
27
28 #define TEST_STRING1 "\\Application Name"
29 #define TEST_STRING2 "%49001%\\Application Name"
30
31 static HRESULT (WINAPI *pCloseINFEngine)(HINF);
32 static HRESULT (WINAPI *pDelNode)(LPCSTR,DWORD);
33 static HRESULT (WINAPI *pGetVersionFromFile)(LPSTR,LPDWORD,LPDWORD,BOOL);
34 static HRESULT (WINAPI *pOpenINFEngine)(PCSTR,PCSTR,DWORD,HINF*,PVOID);
35 static HRESULT (WINAPI *pTranslateInfString)(LPSTR,LPSTR,LPSTR,LPSTR,LPSTR,DWORD,LPDWORD,LPVOID);
36 static HRESULT (WINAPI *pTranslateInfStringEx)(HINF,PCSTR,PCSTR,PCSTR,PSTR,DWORD,PDWORD,PVOID);
37
38 static BOOL init_function_pointers(void)
39 {
40     HMODULE hAdvPack = LoadLibraryA("advpack.dll");
41
42     if (!hAdvPack)
43         return FALSE;
44
45     pCloseINFEngine = (void*)GetProcAddress(hAdvPack, "CloseINFEngine");
46     pDelNode = (void *)GetProcAddress(hAdvPack, "DelNode");
47     pGetVersionFromFile = (void *)GetProcAddress(hAdvPack, "GetVersionFromFile");
48     pOpenINFEngine = (void*)GetProcAddress(hAdvPack, "OpenINFEngine");
49     pTranslateInfString = (void *)GetProcAddress(hAdvPack, "TranslateInfString");
50     pTranslateInfStringEx = (void*)GetProcAddress(hAdvPack, "TranslateInfStringEx");
51
52     if (!pCloseINFEngine || !pDelNode || !pGetVersionFromFile ||
53         !pOpenINFEngine || !pTranslateInfString)
54         return FALSE;
55
56     return TRUE;
57 }
58
59 static void version_test(void)
60 {
61     HRESULT hr;
62     DWORD major, minor;
63
64     major = minor = 0;
65     hr = pGetVersionFromFile("kernel32.dll", &major, &minor, FALSE);
66     ok (hr == S_OK, "GetVersionFromFileEx(kernel32.dll) failed, returned "
67         "0x%08lx\n", hr);
68     trace("kernel32.dll Language ID: 0x%08lx, Codepage ID: 0x%08lx\n",
69            major, minor);
70
71     major = minor = 0;
72     hr = pGetVersionFromFile("kernel32.dll", &major, &minor, TRUE);
73     ok (hr == S_OK, "GetVersionFromFileEx(kernel32.dll) failed, returned "
74         "0x%08lx\n", hr);
75     trace("kernel32.dll version: %d.%d.%d.%d\n", HIWORD(major), LOWORD(major),
76           HIWORD(minor), LOWORD(minor));
77
78     major = minor = 0;
79     hr = pGetVersionFromFile("advpack.dll", &major, &minor, FALSE);
80     ok (hr == S_OK, "GetVersionFromFileEx(advpack.dll) failed, returned "
81         "0x%08lx\n", hr);
82     trace("advpack.dll Language ID: 0x%08lx, Codepage ID: 0x%08lx\n",
83            major, minor);
84
85     major = minor = 0;
86     hr = pGetVersionFromFile("advpack.dll", &major, &minor, TRUE);
87     ok (hr == S_OK, "GetVersionFromFileEx(advpack.dll) failed, returned "
88         "0x%08lx\n", hr);
89     trace("advpack.dll version: %d.%d.%d.%d\n", HIWORD(major), LOWORD(major),
90           HIWORD(minor), LOWORD(minor));
91 }
92
93 static void delnode_test(void)
94 {
95     HRESULT hr;
96     HANDLE hn;
97     CHAR currDir[MAX_PATH];
98     int currDirLen;
99
100     /* Native DelNode apparently does not support relative paths, so we use
101        absolute paths for testing */
102     currDirLen = GetCurrentDirectoryA(sizeof(currDir) / sizeof(CHAR), currDir);
103     assert(currDirLen > 0 && currDirLen < sizeof(currDir) / sizeof(CHAR));
104
105     if(currDir[currDirLen - 1] == '\\')
106         currDir[--currDirLen] = 0;
107
108     /* Simple tests; these should fail. */
109     hr = pDelNode(NULL, 0);
110     ok (hr == E_FAIL, "DelNode called with NULL pathname should return E_FAIL\n");
111     hr = pDelNode("", 0);
112     ok (hr == E_FAIL, "DelNode called with empty pathname should return E_FAIL\n");
113
114     /* Test deletion of a file. */
115     hn = CreateFile("DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
116         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
117     assert(hn != INVALID_HANDLE_VALUE);
118     CloseHandle(hn);
119     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestFile1"), 0);
120     ok (hr == S_OK, "DelNode failed deleting a single file\n");
121     currDir[currDirLen] = '\0';
122
123     /* Test deletion of an empty directory. */
124     CreateDirectoryA("DelNodeTestDir", NULL);
125     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
126     ok (hr == S_OK, "DelNode failed deleting an empty directory\n");
127     currDir[currDirLen] = '\0';
128
129     /* Test deletion of a directory containing one file. */
130     CreateDirectoryA("DelNodeTestDir", NULL);
131     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
132         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
133     assert(hn != INVALID_HANDLE_VALUE);
134     CloseHandle(hn);
135     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
136     ok (hr == S_OK, "DelNode failed deleting a directory containing one file\n");
137     currDir[currDirLen] = '\0';
138
139     /* Test deletion of a directory containing multiple files. */
140     CreateDirectoryA("DelNodeTestDir", NULL);
141     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile1", GENERIC_WRITE, 0, NULL,
142         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
143     assert(hn != INVALID_HANDLE_VALUE);
144     CloseHandle(hn);
145     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile2", GENERIC_WRITE, 0, NULL,
146         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
147     assert(hn != INVALID_HANDLE_VALUE);
148     CloseHandle(hn);
149     hn = CreateFile("DelNodeTestDir\\DelNodeTestFile3", GENERIC_WRITE, 0, NULL,
150         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
151     assert(hn != INVALID_HANDLE_VALUE);
152     CloseHandle(hn);
153     hr = pDelNode(lstrcat(currDir, "\\DelNodeTestDir"), 0);
154     ok (hr == S_OK, "DelNode failed deleting a directory containing multiple files\n");
155     currDir[currDirLen] = '\0';
156 }
157
158 static void append_str(char **str, const char *data)
159 {
160     sprintf(*str, data);
161     *str += strlen(*str);
162 }
163
164 static void create_inf_file()
165 {
166     char data[1024];
167     char *ptr = data;
168     DWORD dwNumberOfBytesWritten;
169     HANDLE hf = CreateFile("c:\\test.inf", GENERIC_WRITE, 0, NULL,
170                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
171
172     append_str(&ptr, "[Version]\n");
173     append_str(&ptr, "Signature=\"$Chicago$\"\n");
174     append_str(&ptr, "[CustInstDestSection]\n");
175     append_str(&ptr, "49001=ProgramFilesDir\n");
176     append_str(&ptr, "[ProgramFilesDir]\n");
177     append_str(&ptr, "HKLM,\"Software\\Microsoft\\Windows\\CurrentVersion\",");
178     append_str(&ptr, "\"ProgramFilesDir\",,\"%%24%%\\%%LProgramF%%\"\n");
179     append_str(&ptr, "[section]\n");
180     append_str(&ptr, "NotACustomDestination=Version\n");
181     append_str(&ptr, "CustomDestination=CustInstDestSection\n");
182     append_str(&ptr, "[Options.NTx86]\n");
183     append_str(&ptr, "49001=ProgramFilesDir\n");
184     append_str(&ptr, "InstallDir=%%49001%%\\%%DefaultAppPath%%\n");
185     append_str(&ptr, "CustomHDestination=CustInstDestSection\n");
186     append_str(&ptr, "[Strings]\n");
187     append_str(&ptr, "DefaultAppPath=\"Application Name\"\n");
188     append_str(&ptr, "LProgramF=\"Program Files\"\n");
189
190     WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL);
191     CloseHandle(hf);
192 }
193
194 static void translateinfstring_test()
195 {
196     HRESULT hr;
197     char buffer[MAX_PATH];
198     DWORD dwSize;
199
200     create_inf_file();
201
202     /* pass in a couple invalid parameters */
203     hr = pTranslateInfString(NULL, NULL, NULL, NULL, buffer, MAX_PATH, &dwSize, NULL);
204     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08x\n", (UINT)hr);
205
206     /* try to open an inf file that doesn't exist */
207     hr = pTranslateInfString("c:\\a.inf", "Options.NTx86", "Options.NTx86",
208                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
209     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || hr == E_INVALIDARG || 
210        hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), 
211        "Expected E_INVALIDARG, 0x80070002 or 0x8007007e, got 0x%08x\n", (UINT)hr);
212
213     if(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND))
214     {
215         trace("WinNT 3.51 detected. Skipping tests for TranslateInfString()\n");
216         return;
217     }
218
219     /* try a nonexistent section */
220     buffer[0] = 0;
221     hr = pTranslateInfString("c:\\test.inf", "idontexist", "Options.NTx86",
222                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
223     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", (UINT)hr);
224     ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
225     ok(dwSize == 25, "Expected size 25, got %ld\n", dwSize);
226
227     buffer[0] = 0;
228     /* try other nonexistent section */
229     hr = pTranslateInfString("c:\\test.inf", "Options.NTx86", "idontexist",
230                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
231     ok(hr == SPAPI_E_LINE_NOT_FOUND || hr == E_INVALIDARG, 
232        "Expected SPAPI_E_LINE_NOT_FOUND or E_INVALIDARG, got 0x%08x\n", (UINT)hr);
233
234     buffer[0] = 0;
235     /* try nonexistent key */
236     hr = pTranslateInfString("c:\\test.inf", "Options.NTx86", "Options.NTx86",
237                              "notvalid", buffer, MAX_PATH, &dwSize, NULL);
238     ok(hr == SPAPI_E_LINE_NOT_FOUND || hr == E_INVALIDARG, 
239        "Expected SPAPI_E_LINE_NOT_FOUND or E_INVALIDARG, got 0x%08x\n", (UINT)hr);
240
241     buffer[0] = 0;
242     /* test the behavior of pszInstallSection */
243     hr = pTranslateInfString("c:\\test.inf", "section", "Options.NTx86",
244                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
245     ok(hr == ERROR_SUCCESS || hr == E_FAIL, 
246        "Expected ERROR_SUCCESS or E_FAIL, got 0x%08x\n", (UINT)hr);
247
248     if(hr == ERROR_SUCCESS)
249     {
250         HKEY key;
251         DWORD len = MAX_PATH;
252         char cmpbuffer[MAX_PATH];
253         LONG res = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key);
254         if(res == ERROR_SUCCESS) {
255             res = RegQueryValueExA(key, "ProgramFilesDir", NULL, NULL, (LPBYTE)cmpbuffer, &len);
256             if(res == ERROR_SUCCESS) {
257                 strcat(cmpbuffer, TEST_STRING1);
258                 ok(!strcmp(buffer, cmpbuffer), "Expected '%s', got '%s'\n", cmpbuffer, buffer);
259                 ok(dwSize == (strlen(cmpbuffer)+1), "Expected size %d, got %ld\n",
260                    strlen(cmpbuffer)+1, dwSize);
261             }
262             RegCloseKey(key);
263         }
264     }
265
266     buffer[0] = 0;
267     /* try without a pszInstallSection */
268     hr = pTranslateInfString("c:\\test.inf", NULL, "Options.NTx86",
269                              "InstallDir", buffer, MAX_PATH, &dwSize, NULL);
270     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", (UINT)hr);
271     todo_wine
272     {
273         ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
274         ok(dwSize == 25, "Expected size 25, got %ld\n", dwSize);
275     }
276
277     DeleteFile("c:\\a.inf");
278     DeleteFile("c:\\test.inf");
279 }
280
281 static void translateinfstringex_test(void)
282 {
283     HINF hinf;
284     HKEY hkey;
285     HRESULT hr;
286     char buffer[MAX_PATH];
287     char progfiles[MAX_PATH];
288     DWORD size = MAX_PATH;
289
290     create_inf_file();
291
292     RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey);
293     RegQueryValueExA(hkey, "ProgramFilesDir", NULL, NULL, (LPBYTE)progfiles, &size);
294     lstrcatA(progfiles, TEST_STRING1);
295     
296     /* need to see if there are any flags */
297
298     /* try a NULL filename */
299     hr = pOpenINFEngine(NULL, "Options.NTx86", 0, &hinf, NULL);
300     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
301
302     /* try an empty filename */
303     hr = pOpenINFEngine("", "Options.NTx86", 0, &hinf, NULL);
304     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
305         "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %ld\n", hr);
306
307     /* try a NULL hinf */
308     hr = pOpenINFEngine("c:\\test.inf", "Options.NTx86", 0, NULL, NULL);
309     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
310
311     /* open the INF without the Install section specified */
312     hr = pOpenINFEngine("c:\\test.inf", NULL, 0, &hinf, NULL);
313     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
314
315     /* try a NULL hinf */
316     hr = pTranslateInfStringEx(NULL, "c:\\test.inf", "Options.NTx86", "InstallDir",
317                               buffer, size, &size, NULL);
318     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
319
320     /* try a NULL filename */
321     hr = pTranslateInfStringEx(hinf, NULL, "Options.NTx86", "InstallDir",
322                               buffer, size, &size, NULL);
323     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
324
325     /* try an empty filename */
326     size = MAX_PATH;
327     hr = pTranslateInfStringEx(hinf, "", "Options.NTx86", "InstallDir",
328                               buffer, size, &size, NULL);
329     ok(hr == S_OK, "Expected S_OK, got %08x\n", (UINT)hr);
330     todo_wine
331     {
332         ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer);
333         ok(size == 25, "Expected size 25, got %ld\n", size);
334     }
335
336     /* try a NULL translate section */
337     hr = pTranslateInfStringEx(hinf, "c:\\test.inf", NULL, "InstallDir",
338                               buffer, size, &size, NULL);
339     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
340
341     /* try an empty translate section */
342     hr = pTranslateInfStringEx(hinf, "c:\\test.inf", "", "InstallDir",
343                               buffer, size, &size, NULL);
344     ok(hr == SPAPI_E_LINE_NOT_FOUND, "Expected SPAPI_E_LINE_NOT_FOUND, got %ld\n", hr);
345
346     /* try a NULL translate key */
347     hr = pTranslateInfStringEx(hinf, "c:\\test.inf", "Options.NTx86", NULL,
348                               buffer, size, &size, NULL);
349     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
350
351     /* try an empty translate key */
352     hr = pTranslateInfStringEx(hinf, "c:\\test.inf", "Options.NTx86", "",
353                               buffer, size, &size, NULL);
354     ok(hr == SPAPI_E_LINE_NOT_FOUND, "Expected SPAPI_E_LINE_NOT_FOUND, got %ld\n", hr);
355
356     /* successfully translate the string */
357     size = MAX_PATH;
358     hr = pTranslateInfStringEx(hinf, "c:\\test.inf", "Options.NTx86", "InstallDir",
359                               buffer, size, &size, NULL);
360     ok(hr == S_OK, "Expected S_OK, got %ld\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 %ld\n", size);
365     }
366
367     /* try a NULL hinf */
368     hr = pCloseINFEngine(NULL);
369     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
370
371     /* successfully close the hinf */
372     hr = pCloseINFEngine(hinf);
373     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
374
375     /* open the inf with the install section */
376     hr = pOpenINFEngine("c:\\test.inf", "section", 0, &hinf, NULL);
377     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
378
379     /* translate the string with the install section specified */
380     size = MAX_PATH;
381     hr = pTranslateInfStringEx(hinf, "c:\\test.inf", "Options.NTx86", "InstallDir",
382                               buffer, size, &size, NULL);
383     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
384     ok(!strcmp(buffer, progfiles), "Expected %s, got %s\n", progfiles, buffer);
385     ok(size == lstrlenA(progfiles) + 1, "Expected size %i, got %ld\n",
386        lstrlenA(progfiles) + 1, size);
387
388     /* close the INF again */
389     hr = pCloseINFEngine(hinf);
390     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
391
392     DeleteFileA("c:\\test.inf");
393 }
394
395 START_TEST(advpack)
396 {
397     if (!init_function_pointers())
398         return;
399
400     version_test();
401     delnode_test();
402     translateinfstring_test();
403     translateinfstringex_test();
404 }