1 /*
2  * Miscellaneous tests
3  *
4  * Copyright 2007 James Hawkins
5  * Copyright 2007 Hans Leidekker
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 <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "setupapi.h"
32 #include "cfgmgr32.h"
33 
34 #include "wine/test.h"
35 
36 static CHAR CURR_DIR[MAX_PATH];
37 
38 /* test:
39  *  - fails if not administrator
40  *  - what if it's not a .inf file?
41  *  - copied to %windir%/Inf
42  *  - SourceInfFileName should be a full path
43  *  - SourceInfFileName should be <= MAX_PATH
44  *  - copy styles
45  */
46 
47 static BOOL (WINAPI *pSetupGetFileCompressionInfoExA)(PCSTR, PSTR, DWORD, PDWORD, PDWORD, PDWORD, PUINT);
48 static BOOL (WINAPI *pSetupCopyOEMInfA)(PCSTR, PCSTR, DWORD, DWORD, PSTR, DWORD, PDWORD, PSTR *);
49 static BOOL (WINAPI *pSetupQueryInfOriginalFileInformationA)(PSP_INF_INFORMATION, UINT, PSP_ALTPLATFORM_INFO, PSP_ORIGINAL_FILE_INFO_A);
50 static BOOL (WINAPI *pSetupUninstallOEMInfA)(PCSTR, DWORD, PVOID);
51 
52 static void create_inf_file(LPCSTR filename)
53 {
54     DWORD dwNumberOfBytesWritten;
55     HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
56                             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
57 
58     static const char data[] =
59         "[Version]\n"
60         "Signature=\"$Chicago$\"\n"
61         "AdvancedINF=2.5\n"
62         "[DefaultInstall]\n"
63         "RegisterOCXs=RegisterOCXsSection\n"
64         "[RegisterOCXsSection]\n"
65         "%%11%%\\ole32.dll\n";
66 
67     WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL);
68     CloseHandle(hf);
69 }
70 
71 static void get_temp_filename(LPSTR path)
72 {
73     CHAR temp[MAX_PATH];
74     LPSTR ptr;
75 
76     GetTempFileNameA(CURR_DIR, "set", 0, temp);
77     ptr = strrchr(temp, '\\');
78 
79     strcpy(path, ptr + 1);
80 }
81 
82 static BOOL file_exists(LPSTR path)
83 {
84     return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
85 }
86 
87 static BOOL check_format(LPSTR path, LPSTR inf)
88 {
89     CHAR check[MAX_PATH];
90     BOOL res;
91 
92     static const CHAR format[] = "\\INF\\oem";
93 
94     GetWindowsDirectoryA(check, MAX_PATH);
95     strcat(check, format);
96     res = CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, check, -1, path, strlen(check)) == CSTR_EQUAL &&
97           path[strlen(check)] != '\\';
98 
99     return (!inf) ? res : res && (inf == path + strlen(check) - 3);
100 }
101 
102 static void test_original_file_name(LPCSTR original, LPCSTR dest)
103 {
104     HINF hinf;
105     PSP_INF_INFORMATION pspii;
106     SP_ORIGINAL_FILE_INFO_A spofi;
107     BOOL res;
108     DWORD size;
109 
110     if (!pSetupQueryInfOriginalFileInformationA)
111     {
112         win_skip("SetupQueryInfOriginalFileInformationA is not available\n");
113         return;
114     }
115 
116     hinf = SetupOpenInfFileA(dest, NULL, INF_STYLE_WIN4, NULL);
117     ok(hinf != NULL, "SetupOpenInfFileA failed with error %d\n", GetLastError());
118 
119     res = SetupGetInfInformationA(hinf, INFINFO_INF_SPEC_IS_HINF, NULL, 0, &size);
120     ok(res, "SetupGetInfInformation failed with error %d\n", GetLastError());
121 
122     pspii = HeapAlloc(GetProcessHeap(), 0, size);
123 
124     res = SetupGetInfInformationA(hinf, INFINFO_INF_SPEC_IS_HINF, pspii, size, NULL);
125     ok(res, "SetupGetInfInformation failed with error %d\n", GetLastError());
126 
127     spofi.cbSize = 0;
128     res = pSetupQueryInfOriginalFileInformationA(pspii, 0, NULL, &spofi);
129     ok(!res && GetLastError() == ERROR_INVALID_USER_BUFFER,
130         "SetupQueryInfOriginalFileInformationA should have failed with ERROR_INVALID_USER_BUFFER instead of %d\n", GetLastError());
131 
132     spofi.cbSize = sizeof(spofi);
133     res = pSetupQueryInfOriginalFileInformationA(pspii, 0, NULL, &spofi);
134     ok(res, "SetupQueryInfOriginalFileInformationA failed with error %d\n", GetLastError());
135     ok(!spofi.OriginalCatalogName[0], "spofi.OriginalCatalogName should have been \"\" instead of \"%s\"\n", spofi.OriginalCatalogName);
136     todo_wine
137     ok(!strcmp(original, spofi.OriginalInfName), "spofi.OriginalInfName of %s didn't match real original name %s\n", spofi.OriginalInfName, original);
138 
139     HeapFree(GetProcessHeap(), 0, pspii);
140 
141     SetupCloseInfFile(hinf);
142 }
143 
144 static void test_SetupCopyOEMInf(void)
145 {
146     CHAR toolong[MAX_PATH * 2];
147     CHAR path[MAX_PATH], dest[MAX_PATH];
148     CHAR tmpfile[MAX_PATH], dest_save[MAX_PATH];
149     LPSTR inf = NULL;
150     DWORD size;
151     BOOL res;
152 
153     /* try NULL SourceInfFileName */
154     SetLastError(0xdeadbeef);
155     res = pSetupCopyOEMInfA(NULL, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL);
156     ok(res == FALSE, "Expected FALSE, got %d\n", res);
157     ok(GetLastError() == ERROR_INVALID_PARAMETER,
158        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
159 
160     /* try empty SourceInfFileName */
161     SetLastError(0xdeadbeef);
162     res = pSetupCopyOEMInfA("", NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL);
163     ok(res == FALSE, "Expected FALSE, got %d\n", res);
164     ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
165        GetLastError() == ERROR_BAD_PATHNAME || /* Win98 */
166        GetLastError() == ERROR_INVALID_PARAMETER, /* Vista, W2K8 */
167        "Unexpected error : %d\n", GetLastError());
168 
169     /* try a relative nonexistent SourceInfFileName */
170     SetLastError(0xdeadbeef);
171     res = pSetupCopyOEMInfA("nonexistent", NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL);
172     ok(res == FALSE, "Expected FALSE, got %d\n", res);
173     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
174        "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
175 
176     /* try an absolute nonexistent SourceInfFileName */
177     strcpy(path, CURR_DIR);
178     strcat(path, "\\nonexistent");
179     SetLastError(0xdeadbeef);
180     res = pSetupCopyOEMInfA(path, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL);
181     ok(res == FALSE, "Expected FALSE, got %d\n", res);
182     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
183        "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
184 
185     /* try a long SourceInfFileName */
186     memset(toolong, 'a', MAX_PATH * 2);
187     toolong[MAX_PATH * 2 - 1] = '\0';
188     SetLastError(0xdeadbeef);
189     res = pSetupCopyOEMInfA(toolong, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL);
190     ok(res == FALSE, "Expected FALSE, got %d\n", res);
191     ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
192        GetLastError() == ERROR_FILENAME_EXCED_RANGE, /* Win98 */
193        "Expected ERROR_FILE_NOT_FOUND or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError());
194 
195     get_temp_filename(tmpfile);
196     create_inf_file(tmpfile);
197 
198     /* try a relative SourceInfFileName */
199     SetLastError(0xdeadbeef);
200     res = pSetupCopyOEMInfA(tmpfile, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL);
201     ok(res == FALSE ||
202        broken(res == TRUE), /* Win98 */
203        "Expected FALSE, got %d\n", res);
204     if (GetLastError() == ERROR_WRONG_INF_TYPE || GetLastError() == ERROR_UNSUPPORTED_TYPE /* Win7 */)
205     {
206        /* FIXME:
207         * Vista needs a [Manufacturer] entry in the inf file. Doing this will give some
208         * popups during the installation though as it also needs a catalog file (signed?).
209         */
210        win_skip("Needs a different inf file on Vista+\n");
211        DeleteFileA(tmpfile);
212        return;
213     }
214 
215     ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
216        broken(GetLastError() == ERROR_SUCCESS), /* Win98 */
217        "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
218     ok(file_exists(tmpfile), "Expected tmpfile to exist\n");
219 
220     /* try SP_COPY_REPLACEONLY, dest does not exist */
221     SetLastError(0xdeadbeef);
222     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL);
223     ok(res == FALSE, "Expected FALSE, got %d\n", res);
224     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
225        "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
226     ok(file_exists(tmpfile), "Expected source inf to exist\n");
227 
228     /* try an absolute SourceInfFileName, without DestinationInfFileName */
229     strcpy(path, CURR_DIR);
230     strcat(path, "\\");
231     strcat(path, tmpfile);
232     SetLastError(0xdeadbeef);
233     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, NULL, 0, NULL, NULL);
234     if (!res && GetLastError() == ERROR_ACCESS_DENIED)
235     {
236         skip("SetupCopyOEMInfA() failed on insufficient permissions\n");
237         return;
238     }
239     ok(res == TRUE, "Expected TRUE, got %d\n", res);
240     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
241     ok(file_exists(path), "Expected source inf to exist\n");
242 
243     /* try SP_COPY_REPLACEONLY, dest exists */
244     SetLastError(0xdeadbeef);
245     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL);
246     ok(res == TRUE, "Expected TRUE, got %d\n", res);
247     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
248     ok(file_exists(path), "Expected source inf to exist\n");
249 
250     /* try SP_COPY_NOOVERWRITE */
251     SetLastError(0xdeadbeef);
252     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL);
253     ok(res == FALSE, "Expected FALSE, got %d\n", res);
254     ok(GetLastError() == ERROR_FILE_EXISTS,
255        "Expected ERROR_FILE_EXISTS, got %d\n", GetLastError());
256 
257     /* get the DestinationInfFileName */
258     SetLastError(0xdeadbeef);
259     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, MAX_PATH, NULL, NULL);
260     ok(res == TRUE, "Expected TRUE, got %d\n", res);
261     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
262     ok(strlen(dest) != 0, "Expected a non-zero length string\n");
263     ok(file_exists(dest), "Expected destination inf to exist\n");
264     ok(check_format(dest, NULL), "Expected %%windir%%\\inf\\OEMx.inf, got %s\n", dest);
265     ok(file_exists(path), "Expected source inf to exist\n");
266 
267     strcpy(dest_save, dest);
268     DeleteFileA(dest_save);
269 
270     /* get the DestinationInfFileName, DestinationInfFileNameSize is too small
271      *   - inf is still copied
272      */
273     strcpy(dest, "aaa");
274     size = 0;
275     SetLastError(0xdeadbeef);
276     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, 5, &size, NULL);
277     ok(res == FALSE, "Expected FALSE, got %d\n", res);
278     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
279        "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
280     ok(file_exists(path), "Expected source inf to exist\n");
281     ok(file_exists(dest_save), "Expected dest inf to exist\n");
282     ok(!strcmp(dest, "aaa"), "Expected dest to be unchanged\n");
283     ok(size == strlen(dest_save) + 1, "Expected size to be lstrlen(dest_save) + 1\n");
284 
285     /* get the DestinationInfFileName and DestinationInfFileNameSize */
286     SetLastError(0xdeadbeef);
287     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, MAX_PATH, &size, NULL);
288     ok(res == TRUE, "Expected TRUE, got %d\n", res);
289     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
290     ok(lstrlenA(dest) + 1 == size, "Expected sizes to match, got (%d, %d)\n", lstrlenA(dest), size);
291     ok(file_exists(dest), "Expected destination inf to exist\n");
292     ok(check_format(dest, NULL), "Expected %%windir%%\\inf\\OEMx.inf, got %s\n", dest);
293     ok(file_exists(path), "Expected source inf to exist\n");
294     ok(size == lstrlenA(dest_save) + 1, "Expected size to be lstrlen(dest_save) + 1\n");
295 
296     test_original_file_name(strrchr(path, '\\') + 1, dest);
297 
298     /* get the DestinationInfFileName, DestinationInfFileNameSize, and DestinationInfFileNameComponent */
299     SetLastError(0xdeadbeef);
300     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, MAX_PATH, &size, &inf);
301     ok(res == TRUE, "Expected TRUE, got %d\n", res);
302     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
303     ok(lstrlenA(dest) + 1 == size, "Expected sizes to match, got (%d, %d)\n", lstrlenA(dest), size);
304     ok(file_exists(dest), "Expected destination inf to exist\n");
305     ok((inf && inf[0] != 0) ||
306        broken(!inf), /* Win98 */
307        "Expected inf to point to the filename\n");
308     ok(check_format(dest, inf), "Expected %%windir%%\\inf\\OEMx.inf, got %s\n", dest);
309     ok(file_exists(path), "Expected source inf to exist\n");
310     ok(size == lstrlenA(dest_save) + 1, "Expected size to be lstrlen(dest_save) + 1\n");
311 
312     /* try SP_COPY_DELETESOURCE */
313     SetLastError(0xdeadbeef);
314     res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_DELETESOURCE, NULL, 0, NULL, NULL);
315     ok(res == TRUE, "Expected TRUE, got %d\n", res);
316     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
317     ok(!file_exists(path), "Expected source inf to not exist\n");
318 
319     if (pSetupUninstallOEMInfA)
320     {
321         char pnf[MAX_PATH];
322         char *pnffile;
323         char *destfile = strrchr(dest, '\\') + 1;
324 
325         strcpy(pnf, dest);
326         *(strrchr(pnf, '.') + 1) = 'p';
327         pnffile = strrchr(pnf, '\\') + 1;
328 
329         SetLastError(0xdeadbeef);
330         res = pSetupUninstallOEMInfA(destfile, 0, NULL);
331         if(!res)
332             res = pSetupUninstallOEMInfA(pnffile, 0, NULL);
333         ok(res, "Failed to uninstall '%s'/'%s' : %d\n", destfile,
334            pnffile, GetLastError());
335         todo_wine ok(!file_exists(dest), "Expected inf '%s' to not exist\n", dest);
336         if(file_exists(dest))
337         {
338             SetLastError(0xdeadbeef);
339             res = DeleteFileA(dest);
340             ok(res, "Failed to delete file '%s' : %d\n", dest, GetLastError());
341         }
342         ok(!file_exists(pnf), "Expected pnf '%s' to not exist\n", pnf);
343         if(file_exists(pnf))
344         {
345             SetLastError(0xdeadbeef);
346             res = DeleteFileA(pnf);
347             ok(res, "Failed to delete file '%s' : %d\n", pnf, GetLastError());
348         }
349     }
350     else
351     {
352         /* Win9x/WinMe */
353         SetLastError(0xdeadbeef);
354         res = DeleteFileA(dest);
355         ok(res, "Failed to delete file '%s' : %d\n", dest, GetLastError());
356 
357         /* On WinMe we also need to remove the .pnf file */
358         *(strrchr(dest, '.') + 1) = 'p';
359         DeleteFileA(dest);
360     }
361 }
362 
363 static void create_source_file(LPSTR filename, const BYTE *data, DWORD size)
364 {
365     HANDLE handle;
366     DWORD written;
367 
368     handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
369     WriteFile(handle, data, size, &written, NULL);
370     CloseHandle(handle);
371 }
372 
373 static BOOL compare_file_data(LPSTR file, const BYTE *data, DWORD size)
374 {
375     DWORD read;
376     HANDLE handle;
377     BOOL ret = FALSE;
378     LPBYTE buffer;
379 
380     handle = CreateFileA(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
381     buffer = HeapAlloc(GetProcessHeap(), 0, size);
382     if (buffer)
383     {
384         ReadFile(handle, buffer, size, &read, NULL);
385         if (read == size && !memcmp(data, buffer, size)) ret = TRUE;
386         HeapFree(GetProcessHeap(), 0, buffer);
387     }
388     CloseHandle(handle);
389     return ret;
390 }
391 
392 static const BYTE uncompressed[] = {
393     'u','n','c','o','m','p','r','e','s','s','e','d','\r','\n'
394 };
395 static const BYTE laurence[] = {
396     'l','a','u','r','e','n','c','e','\r','\n'
397 };
398 static const BYTE comp_lzx[] = {
399     0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33, 0x41, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xff, 0x00,
400     0x00, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x3f, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64
401 };
402 static const BYTE comp_zip[] = {
403     0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xae, 0x81, 0x36, 0x75, 0x11,
404     0x2c, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x15, 0x00, 0x77, 0x69,
405     0x6e, 0x65, 0x55, 0x54, 0x09, 0x00, 0x03, 0xd6, 0x0d, 0x10, 0x46, 0xfd, 0x0d, 0x10, 0x46, 0x55,
406     0x78, 0x04, 0x00, 0xe8, 0x03, 0xe8, 0x03, 0x00, 0x00, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72,
407     0x65, 0x73, 0x73, 0x65, 0x64, 0x50, 0x4b, 0x01, 0x02, 0x17, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00,
408     0x00, 0xbd, 0xae, 0x81, 0x36, 0x75, 0x11, 0x2c, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
409     0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00,
410     0x00, 0x00, 0x00, 0x77, 0x69, 0x6e, 0x65, 0x55, 0x54, 0x05, 0x00, 0x03, 0xd6, 0x0d, 0x10, 0x46,
411     0x55, 0x78, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
412     0x3f, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00
413 };
414 static const BYTE comp_cab_lzx[] = {
415     0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416     0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
417     0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x0f, 0x0e, 0x00, 0x00, 0x00,
418     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x36, 0x86, 0x72, 0x20, 0x00, 0x77, 0x69, 0x6e, 0x65,
419     0x00, 0x19, 0xd0, 0x1a, 0xe3, 0x22, 0x00, 0x0e, 0x00, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x30, 0xe0,
420     0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x63,
421     0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x0d, 0x0a
422 };
423 static const BYTE comp_cab_zip[] =  {
424     0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
425     0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
426     0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00,
427     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x36, 0x2f, 0xa5, 0x20, 0x00, 0x77, 0x69, 0x6e, 0x65,
428     0x00, 0x7c, 0x80, 0x26, 0x2b, 0x12, 0x00, 0x0e, 0x00, 0x43, 0x4b, 0x2b, 0xcd, 0x4b, 0xce, 0xcf,
429     0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e, 0x4d, 0xe1, 0xe5, 0x02, 0x00
430 };
431 static const BYTE comp_cab_zip_multi[] = {
432     0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433     0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,
434     0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00,
435     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x38, 0xf0, 0x48, 0x20, 0x00, 0x74, 0x72, 0x69, 0x73,
436     0x74, 0x72, 0x61, 0x6d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1,
437     0x38, 0xf0, 0x48, 0x20, 0x00, 0x77, 0x69, 0x6e, 0x65, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00,
438     0x00, 0x00, 0x00, 0x00, 0xd1, 0x38, 0xf0, 0x48, 0x20, 0x00, 0x73, 0x68, 0x61, 0x6e, 0x64, 0x79,
439     0x00, 0x67, 0x2c, 0x03, 0x85, 0x23, 0x00, 0x20, 0x00, 0x43, 0x4b, 0xcb, 0x49, 0x2c, 0x2d, 0x4a,
440     0xcd, 0x4b, 0x4e, 0xe5, 0xe5, 0x2a, 0xcd, 0x4b, 0xce, 0xcf, 0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e,
441     0x4d, 0xe1, 0xe5, 0x2a, 0x2e, 0x49, 0x2d, 0xca, 0x03, 0x8a, 0x02, 0x00
442 };
443 
444 static void test_SetupGetFileCompressionInfo(void)
445 {
446     DWORD ret, source_size, target_size;
447     char source[MAX_PATH], temp[MAX_PATH], *name;
448     UINT type;
449 
450     GetTempPathA(sizeof(temp), temp);
451     GetTempFileNameA(temp, "fci", 0, source);
452 
453     create_source_file(source, uncompressed, sizeof(uncompressed));
454 
455     ret = SetupGetFileCompressionInfoA(NULL, NULL, NULL, NULL, NULL);
456     ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n");
457 
458     ret = SetupGetFileCompressionInfoA(source, NULL, NULL, NULL, NULL);
459     ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n");
460 
461     ret = SetupGetFileCompressionInfoA(source, &name, NULL, NULL, NULL);
462     ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n");
463 
464     ret = SetupGetFileCompressionInfoA(source, &name, &source_size, NULL, NULL);
465     ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n");
466 
467     ret = SetupGetFileCompressionInfoA(source, &name, &source_size, &target_size, NULL);
468     ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n");
469 
470     name = NULL;
471     source_size = target_size = 0;
472     type = 5;
473 
474     ret = SetupGetFileCompressionInfoA(source, &name, &source_size, &target_size, &type);
475     ok(!ret, "SetupGetFileCompressionInfo failed unexpectedly\n");
476     ok(name && !lstrcmpA(name, source), "got %s, expected %s\n", name, source);
477     ok(source_size == sizeof(uncompressed), "got %d\n", source_size);
478     ok(target_size == sizeof(uncompressed), "got %d\n", target_size);
479     ok(type == FILE_COMPRESSION_NONE, "got %d, expected FILE_COMPRESSION_NONE\n", type);
480 
481     MyFree(name);
482     DeleteFileA(source);
483 }
484 
485 static void test_SetupGetFileCompressionInfoEx(void)
486 {
487     BOOL ret;
488     DWORD required_len, source_size, target_size;
489     char source[MAX_PATH], temp[MAX_PATH], name[MAX_PATH];
490     UINT type;
491 
492     GetTempPathA(sizeof(temp), temp);
493     GetTempFileNameA(temp, "doc", 0, source);
494 
495     ret = pSetupGetFileCompressionInfoExA(NULL, NULL, 0, NULL, NULL, NULL, NULL);
496     ok(!ret, "SetupGetFileCompressionInfoEx succeeded unexpectedly\n");
497 
498     ret = pSetupGetFileCompressionInfoExA(source, NULL, 0, NULL, NULL, NULL, NULL);
499     ok(!ret, "SetupGetFileCompressionInfoEx succeeded unexpectedly\n");
500 
501     ret = pSetupGetFileCompressionInfoExA(source, NULL, 0, &required_len, NULL, NULL, NULL);
502     ok(!ret, "SetupGetFileCompressionInfoEx succeeded unexpectedly\n");
503     ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1);
504 
505     create_source_file(source, comp_lzx, sizeof(comp_lzx));
506 
507     ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type);
508     ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret);
509     ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source);
510     ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1);
511     ok(source_size == sizeof(comp_lzx), "got %d\n", source_size);
512     ok(target_size == sizeof(uncompressed), "got %d\n", target_size);
513     ok(type == FILE_COMPRESSION_WINLZA, "got %d, expected FILE_COMPRESSION_WINLZA\n", type);
514     DeleteFileA(source);
515 
516     create_source_file(source, comp_zip, sizeof(comp_zip));
517 
518     ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type);
519     ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret);
520     ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source);
521     ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1);
522     ok(source_size == sizeof(comp_zip), "got %d\n", source_size);
523     ok(target_size == sizeof(comp_zip), "got %d\n", target_size);
524     ok(type == FILE_COMPRESSION_NONE, "got %d, expected FILE_COMPRESSION_NONE\n", type);
525     DeleteFileA(source);
526 
527     create_source_file(source, comp_cab_lzx, sizeof(comp_cab_lzx));
528 
529     ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type);
530     ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret);
531     ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source);
532     ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1);
533     ok(source_size == sizeof(comp_cab_lzx), "got %d\n", source_size);
534     ok(target_size == sizeof(uncompressed), "got %d\n", target_size);
535     ok(type == FILE_COMPRESSION_MSZIP, "got %d, expected FILE_COMPRESSION_MSZIP\n", type);
536     DeleteFileA(source);
537 
538     create_source_file(source, comp_cab_zip, sizeof(comp_cab_zip));
539 
540     ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type);
541     ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret);
542     ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source);
543     ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1);
544     ok(source_size == sizeof(comp_cab_zip), "got %d\n", source_size);
545     ok(target_size == sizeof(uncompressed), "got %d\n", target_size);
546     ok(type == FILE_COMPRESSION_MSZIP, "got %d, expected FILE_COMPRESSION_MSZIP\n", type);
547     DeleteFileA(source);
548 }
549 
550 static void test_SetupDecompressOrCopyFile(void)
551 {
552     DWORD ret;
553     char source[MAX_PATH], target[MAX_PATH], temp[MAX_PATH], *p;
554     UINT type;
555     int i;
556 
557     const struct
558     {
559         PCSTR source;
560         PCSTR target;
561         PUINT type;
562     } invalid_parameters[] =
563     {
564         {NULL,   NULL,   NULL},
565         {NULL,   NULL,   &type},
566         {NULL,   target, NULL},
567         {NULL,   target, &type},
568         {source, NULL,   NULL},
569         {source, NULL,   &type},
570     };
571 
572     const struct
573     {
574         const char *filename;
575         const BYTE *expected_buffer;
576         const size_t buffer_size;
577     } zip_multi_tests[] =
578     {
579         {"tristram",     laurence, sizeof(laurence)},
580         {"tristram.txt", laurence, sizeof(laurence)},
581         {"wine",         laurence, sizeof(laurence)},
582         {"wine.txt",     laurence, sizeof(laurence)},
583         {"shandy",       laurence, sizeof(laurence)},
584         {"shandy.txt",   laurence, sizeof(laurence)},
585         {"deadbeef",     laurence, sizeof(laurence)},
586         {"deadbeef.txt", laurence, sizeof(laurence)},
587     };
588 
589     GetTempPathA(sizeof(temp), temp);
590     GetTempFileNameA(temp, "doc", 0, source);
591     GetTempFileNameA(temp, "doc", 0, target);
592 
593     /* parameter tests */
594 
595     create_source_file(source, uncompressed, sizeof(uncompressed));
596 
597     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
598     {
599         type = FILE_COMPRESSION_NONE;
600         ret = SetupDecompressOrCopyFileA(invalid_parameters[i].source,
601                                          invalid_parameters[i].target,
602                                          invalid_parameters[i].type);
603         ok(ret == ERROR_INVALID_PARAMETER,
604            "[%d] Expected SetupDecompressOrCopyFileA to return ERROR_INVALID_PARAMETER, got %u\n",
605            i, ret);
606 
607         /* try an invalid compression type */
608         type = 5;
609         ret = SetupDecompressOrCopyFileA(invalid_parameters[i].source,
610                                          invalid_parameters[i].target,
611                                          invalid_parameters[i].type);
612         ok(ret == ERROR_INVALID_PARAMETER,
613            "[%d] Expected SetupDecompressOrCopyFileA to return ERROR_INVALID_PARAMETER, got %u\n",
614            i, ret);
615     }
616 
617     type = 5; /* try an invalid compression type */
618     ret = SetupDecompressOrCopyFileA(source, target, &type);
619     ok(ret == ERROR_INVALID_PARAMETER, "SetupDecompressOrCopyFile failed unexpectedly\n");
620 
621     DeleteFileA(target);
622 
623     /* no compression tests */
624 
625     ret = SetupDecompressOrCopyFileA(source, target, NULL);
626     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
627     ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n");
628 
629     /* try overwriting existing file */
630     ret = SetupDecompressOrCopyFileA(source, target, NULL);
631     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
632     DeleteFileA(target);
633 
634     type = FILE_COMPRESSION_NONE;
635     ret = SetupDecompressOrCopyFileA(source, target, &type);
636     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
637     ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n");
638     DeleteFileA(target);
639 
640     type = FILE_COMPRESSION_WINLZA;
641     ret = SetupDecompressOrCopyFileA(source, target, &type);
642     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
643     ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n");
644     DeleteFileA(target);
645 
646     /* lz compression tests */
647 
648     create_source_file(source, comp_lzx, sizeof(comp_lzx));
649 
650     ret = SetupDecompressOrCopyFileA(source, target, NULL);
651     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
652     DeleteFileA(target);
653 
654     /* zip compression tests */
655 
656     create_source_file(source, comp_zip, sizeof(comp_zip));
657 
658     ret = SetupDecompressOrCopyFileA(source, target, NULL);
659     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
660     ok(compare_file_data(target, comp_zip, sizeof(comp_zip)), "incorrect target file\n");
661     DeleteFileA(target);
662 
663     /* cabinet compression tests */
664 
665     create_source_file(source, comp_cab_zip, sizeof(comp_cab_zip));
666 
667     p = strrchr(target, '\\');
668     lstrcpyA(p + 1, "wine");
669 
670     ret = SetupDecompressOrCopyFileA(source, target, NULL);
671     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
672     ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n");
673 
674     /* try overwriting existing file */
675     ret = SetupDecompressOrCopyFileA(source, target, NULL);
676     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
677 
678     /* try zip compression */
679     type = FILE_COMPRESSION_MSZIP;
680     ret = SetupDecompressOrCopyFileA(source, target, &type);
681     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
682     ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n");
683 
684     /* try no compression */
685     type = FILE_COMPRESSION_NONE;
686     ret = SetupDecompressOrCopyFileA(source, target, &type);
687     ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret);
688     ok(compare_file_data(target, comp_cab_zip, sizeof(comp_cab_zip)), "incorrect target file\n");
689 
690     /* Show that SetupDecompressOrCopyFileA simply extracts the first file it
691      * finds within the compressed cabinet. Contents are:
692      * tristram -> "laurence\r\n"
693      * wine     -> "uncompressed\r\n"
694      * shandy   -> "sterne\r\n" */
695 
696     create_source_file(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi));
697 
698     p = strrchr(target, '\\');
699 
700     for (i = 0; i < sizeof(zip_multi_tests)/sizeof(zip_multi_tests[0]); i++)
701     {
702         lstrcpyA(p + 1, zip_multi_tests[i].filename);
703 
704         ret = SetupDecompressOrCopyFileA(source, target, NULL);
705         ok(!ret, "[%d] SetupDecompressOrCopyFile failed unexpectedly: %d\n", i, ret);
706         ok(compare_file_data(target, zip_multi_tests[i].expected_buffer, zip_multi_tests[i].buffer_size),
707            "[%d] incorrect target file\n", i);
708         DeleteFileA(target);
709     }
710 
711     DeleteFileA(source);
712 }
713 
714 static void test_SetupUninstallOEMInf(void)
715 {
716     BOOL ret;
717 
718     SetLastError(0xdeadbeef);
719     ret = pSetupUninstallOEMInfA(NULL, 0, NULL);
720     ok(!ret, "Expected failure\n");
721     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
722 
723     SetLastError(0xdeadbeef);
724     ret = pSetupUninstallOEMInfA("", 0, NULL);
725     todo_wine
726     {
727     ok(!ret, "Expected failure\n");
728     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
729     }
730 
731     SetLastError(0xdeadbeef);
732     ret = pSetupUninstallOEMInfA("nonexistent.inf", 0, NULL);
733     todo_wine
734     {
735     ok(!ret, "Expected failure\n");
736     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
737     }
738 }
739 
740 struct default_callback_context
741 {
742     DWORD     magic;
743     HWND      owner;
744     DWORD     unk1[4];
745     DWORD_PTR unk2[7];
746     HWND      progress;
747     UINT      message;
748     DWORD_PTR unk3[5];
749 };
750 
751 static void test_defaultcallback(void)
752 {
753     struct default_callback_context *ctxt;
754     static const DWORD magic = 0x43515053; /* "SPQC" */
755     HWND owner, progress;
756 
757     owner = (HWND)0x123;
758     progress = (HWND)0x456;
759     ctxt = SetupInitDefaultQueueCallbackEx(owner, progress, WM_USER, 0, NULL);
760     ok(ctxt != NULL, "got %p\n", ctxt);
761 
762     ok(ctxt->magic == magic || broken(ctxt->magic != magic) /* win2000 */, "got magic 0x%08x\n", ctxt->magic);
763     if (ctxt->magic == magic)
764     {
765         ok(ctxt->owner == owner, "got %p, expected %p\n", ctxt->owner, owner);
766         ok(ctxt->progress == progress, "got %p, expected %p\n", ctxt->progress, progress);
767         ok(ctxt->message == WM_USER, "got %d, expected %d\n", ctxt->message, WM_USER);
768         SetupTermDefaultQueueCallback(ctxt);
769     }
770     else
771     {
772         win_skip("Skipping tests on old systems.\n");
773         SetupTermDefaultQueueCallback(ctxt);
774         return;
775     }
776 
777     ctxt = SetupInitDefaultQueueCallback(owner);
778     ok(ctxt->magic == magic, "got magic 0x%08x\n", ctxt->magic);
779     ok(ctxt->owner == owner, "got %p, expected %p\n", ctxt->owner, owner);
780     ok(ctxt->progress == NULL, "got %p, expected %p\n", ctxt->progress, progress);
781     ok(ctxt->message == 0, "got %d\n", ctxt->message);
782     SetupTermDefaultQueueCallback(ctxt);
783 }
784 
785 static void test_SetupLogError(void)
786 {
787     BOOL ret;
788     DWORD error;
789 
790     SetLastError(0xdeadbeef);
791     ret = SetupLogErrorA("Test without opening\r\n", LogSevInformation);
792     error = GetLastError();
793     ok(!ret, "SetupLogError succeeded\n");
794     ok(error == ERROR_FILE_INVALID, "got wrong error: %d\n", error);
795 
796     SetLastError(0xdeadbeef);
797     ret = SetupOpenLog(FALSE);
798     if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
799     {
800         skip("SetupOpenLog() failed on insufficient permissions\n");
801         return;
802     }
803     ok(ret, "SetupOpenLog failed, error %d\n", GetLastError());
804 
805     SetLastError(0xdeadbeef);
806     ret = SetupLogErrorA("Test with wrong log severity\r\n", LogSevMaximum);
807     error = GetLastError();
808     ok(!ret, "SetupLogError succeeded\n");
809     ok(error == 0xdeadbeef, "got wrong error: %d\n", error);
810     ret = SetupLogErrorA("Test without EOL", LogSevInformation);
811     ok(ret, "SetupLogError failed\n");
812 
813     SetLastError(0xdeadbeef);
814     ret = SetupLogErrorA(NULL, LogSevInformation);
815     ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER /* Win Vista+ */),
816         "SetupLogError failed: %08x\n", GetLastError());
817 
818     SetLastError(0xdeadbeef);
819     ret = SetupOpenLog(FALSE);
820     ok(ret, "SetupOpenLog failed, error %d\n", GetLastError());
821 
822     SetupCloseLog();
823 }
824 
825 static void test_CM_Get_Version(void)
826 {
827     WORD ret;
828 
829     ret = CM_Get_Version();
830     ok(ret == 0x0400, "got version %#x\n", ret);
831 }
832 
833 START_TEST(misc)
834 {
835     HMODULE hsetupapi = GetModuleHandleA("setupapi.dll");
836 
837     pSetupGetFileCompressionInfoExA = (void*)GetProcAddress(hsetupapi, "SetupGetFileCompressionInfoExA");
838     pSetupCopyOEMInfA = (void*)GetProcAddress(hsetupapi, "SetupCopyOEMInfA");
839     pSetupQueryInfOriginalFileInformationA = (void*)GetProcAddress(hsetupapi, "SetupQueryInfOriginalFileInformationA");
840     pSetupUninstallOEMInfA = (void*)GetProcAddress(hsetupapi, "SetupUninstallOEMInfA");
841 
842     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
843 
844     if (pSetupCopyOEMInfA)
845         test_SetupCopyOEMInf();
846     else
847         win_skip("SetupCopyOEMInfA is not available\n");
848 
849     test_SetupGetFileCompressionInfo();
850 
851     if (pSetupGetFileCompressionInfoExA)
852         test_SetupGetFileCompressionInfoEx();
853     else
854         win_skip("SetupGetFileCompressionInfoExA is not available\n");
855 
856     test_SetupDecompressOrCopyFile();
857 
858     if (pSetupUninstallOEMInfA)
859         test_SetupUninstallOEMInf();
860     else
861         win_skip("SetupUninstallOEMInfA is not available\n");
862 
863     test_defaultcallback();
864 
865     test_SetupLogError();
866     test_CM_Get_Version();
867 }
868