windowscodecs: Handle TIFF's with RowsPerStrip greater than Height.
[wine] / dlls / msi / tests / source.c
1 /*
2  * Tests for MSI Source functions
3  *
4  * Copyright (C) 2006 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define _WIN32_MSI 300
22
23 #include <stdio.h>
24
25 #include <windows.h>
26 #include <msiquery.h>
27 #include <msidefs.h>
28 #include <msi.h>
29 #include <sddl.h>
30 #include <secext.h>
31
32 #include "wine/test.h"
33
34 static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*);
35 static LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
36 static BOOLEAN (WINAPI *pGetUserNameExA)(EXTENDED_NAME_FORMAT, LPSTR, PULONG);
37 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
38
39 static UINT (WINAPI *pMsiSourceListAddMediaDiskA)
40     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCSTR, LPCSTR);
41 static UINT (WINAPI *pMsiSourceListAddSourceExA)
42     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, DWORD);
43 static UINT (WINAPI *pMsiSourceListEnumMediaDisksA)
44     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPDWORD, LPSTR,
45     LPDWORD, LPSTR, LPDWORD);
46 static UINT (WINAPI *pMsiSourceListEnumSourcesA)
47     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPSTR, LPDWORD);
48 static UINT (WINAPI *pMsiSourceListGetInfoA)
49     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD);
50 static UINT (WINAPI *pMsiSourceListSetInfoA)
51     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT,  DWORD,LPCSTR,  LPCSTR);
52 static UINT (WINAPI *pMsiSourceListAddSourceA)
53     (LPCSTR, LPCSTR, DWORD, LPCSTR);
54
55 static void init_functionpointers(void)
56 {
57     HMODULE hmsi = GetModuleHandleA("msi.dll");
58     HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
59     HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
60     HMODULE hsecur32 = LoadLibraryA("secur32.dll");
61
62 #define GET_PROC(dll, func) \
63     p ## func = (void *)GetProcAddress(dll, #func); \
64     if(!p ## func) \
65       trace("GetProcAddress(%s) failed\n", #func);
66
67     GET_PROC(hmsi, MsiSourceListAddMediaDiskA)
68     GET_PROC(hmsi, MsiSourceListAddSourceExA)
69     GET_PROC(hmsi, MsiSourceListEnumMediaDisksA)
70     GET_PROC(hmsi, MsiSourceListEnumSourcesA)
71     GET_PROC(hmsi, MsiSourceListGetInfoA)
72     GET_PROC(hmsi, MsiSourceListSetInfoA)
73     GET_PROC(hmsi, MsiSourceListAddSourceA)
74
75     GET_PROC(hadvapi32, ConvertSidToStringSidA)
76     GET_PROC(hadvapi32, RegDeleteKeyExA)
77     GET_PROC(hkernel32, IsWow64Process)
78     GET_PROC(hsecur32, GetUserNameExA)
79
80 #undef GET_PROC
81 }
82
83 /* copied from dlls/msi/registry.c */
84 static BOOL squash_guid(LPCWSTR in, LPWSTR out)
85 {
86     DWORD i,n=1;
87     GUID guid;
88
89     if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
90         return FALSE;
91
92     for(i=0; i<8; i++)
93         out[7-i] = in[n++];
94     n++;
95     for(i=0; i<4; i++)
96         out[11-i] = in[n++];
97     n++;
98     for(i=0; i<4; i++)
99         out[15-i] = in[n++];
100     n++;
101     for(i=0; i<2; i++)
102     {
103         out[17+i*2] = in[n++];
104         out[16+i*2] = in[n++];
105     }
106     n++;
107     for( ; i<8; i++)
108     {
109         out[17+i*2] = in[n++];
110         out[16+i*2] = in[n++];
111     }
112     out[32]=0;
113     return TRUE;
114 }
115
116 static void create_test_guid(LPSTR prodcode, LPSTR squashed)
117 {
118     WCHAR guidW[MAX_PATH];
119     WCHAR squashedW[MAX_PATH];
120     GUID guid;
121     HRESULT hr;
122     int size;
123
124     hr = CoCreateGuid(&guid);
125     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
126
127     size = StringFromGUID2(&guid, guidW, MAX_PATH);
128     ok(size == 39, "Expected 39, got %d\n", hr);
129
130     WideCharToMultiByte(CP_ACP, 0, guidW, size, prodcode, MAX_PATH, NULL, NULL);
131     squash_guid(guidW, squashedW);
132     WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL);
133 }
134
135 static int get_user_sid(LPSTR *usersid)
136 {
137     HANDLE token;
138     BYTE buf[1024];
139     DWORD size;
140     PTOKEN_USER user;
141     BOOL rc;
142
143     if (!pConvertSidToStringSidA)
144         return 0;
145     rc=OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
146     if (!rc && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
147         return 0;
148     size = sizeof(buf);
149     GetTokenInformation(token, TokenUser, buf, size, &size);
150     user = (PTOKEN_USER)buf;
151     pConvertSidToStringSidA(user->User.Sid, usersid);
152     CloseHandle(token);
153     return 1;
154 }
155
156 static void check_reg_str(HKEY prodkey, LPCSTR name, LPCSTR expected, BOOL bcase, DWORD line)
157 {
158     char val[MAX_PATH];
159     DWORD size, type;
160     LONG res;
161
162     size = MAX_PATH;
163     val[0] = '\0';
164     res = RegQueryValueExA(prodkey, name, NULL, &type, (LPBYTE)val, &size);
165
166     if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ))
167     {
168         ok_(__FILE__, line)(FALSE, "Key doesn't exist or wrong type\n");
169         return;
170     }
171
172     if (!expected)
173         ok_(__FILE__, line)(lstrlenA(val) == 0, "Expected empty string, got %s\n", val);
174     else
175     {
176         if (bcase)
177             ok_(__FILE__, line)(!lstrcmpA(val, expected), "Expected %s, got %s\n", expected, val);
178         else
179             ok_(__FILE__, line)(!lstrcmpiA(val, expected), "Expected %s, got %s\n", expected, val);
180     }
181 }
182
183 #define CHECK_REG_STR(prodkey, name, expected) \
184     check_reg_str(prodkey, name, expected, TRUE, __LINE__);
185
186 static void test_MsiSourceListGetInfo(void)
187 {
188     CHAR prodcode[MAX_PATH];
189     CHAR prod_squashed[MAX_PATH];
190     CHAR keypath[MAX_PATH*2];
191     CHAR value[MAX_PATH];
192     LPSTR usersid;
193     LPCSTR data;
194     LONG res;
195     UINT r;
196     HKEY userkey, hkey, media;
197     DWORD size;
198
199     if (!pMsiSourceListGetInfoA)
200     {
201         win_skip("Skipping MsiSourceListGetInfoA tests\n");
202         return;
203     }
204
205     create_test_guid(prodcode, prod_squashed);
206     if (!get_user_sid(&usersid))
207     {
208         skip("User SID not available -> skipping MsiSourceListGetInfoA tests\n");
209         return;
210     }
211
212     /* NULL szProductCodeOrPatchCode */
213     r = pMsiSourceListGetInfoA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
214                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
215     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
216
217     /* empty szProductCodeOrPatchCode */
218     r = pMsiSourceListGetInfoA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
219                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
220     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
221
222     /* garbage szProductCodeOrPatchCode */
223     r = pMsiSourceListGetInfoA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
224                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
225     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
226
227     /* guid without brackets */
228     r = pMsiSourceListGetInfoA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
229                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
230     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
231
232     /* guid with brackets */
233     r = pMsiSourceListGetInfoA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
234                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
235     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
236
237     /* same length as guid, but random */
238     r = pMsiSourceListGetInfoA("ADKD-2KSDFF2-DKK1KNFJASD9GLKWME-1I3KAD", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
239                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
240     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
241
242     /* invalid context */
243     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_NONE,
244                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
245     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
246
247     /* another invalid context */
248     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_ALLUSERMANAGED,
249                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
250     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
251
252     /* yet another invalid context */
253     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_ALL,
254                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
255     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
256
257     /* mix two valid contexts */
258     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED,
259                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
260     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
261
262     /* invalid option */
263     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
264                               4, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
265     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
266
267     /* NULL property */
268     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
269                               MSICODE_PRODUCT, NULL, NULL, NULL);
270     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
271
272     /* empty property */
273     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
274                               MSICODE_PRODUCT, "", NULL, NULL);
275     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
276
277     /* value is non-NULL while size is NULL */
278     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
279                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, NULL);
280     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
281
282     /* size is non-NULL while value is NULL */
283     size = MAX_PATH;
284     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
285                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
286     ok(r == ERROR_UNKNOWN_PRODUCT || r == ERROR_INVALID_PARAMETER,
287       "Expected ERROR_UNKNOWN_PRODUCT or ERROR_INVALID_PARAMETER, got %d\n", r);
288
289     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
290     lstrcatA(keypath, prod_squashed);
291
292     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
293     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
294
295     /* user product key exists */
296     size = MAX_PATH;
297     lstrcpyA(value, "aaa");
298     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
299                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
300     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
301     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
302
303     res = RegCreateKeyA(userkey, "SourceList", &hkey);
304     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
305
306     /* SourceList key exists */
307     size = MAX_PATH;
308     lstrcpyA(value, "aaa");
309     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
310                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
311     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
312     ok(size == 0, "Expected 0, got %d\n", size);
313     ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value);
314
315     data = "msitest.msi";
316     res = RegSetValueExA(hkey, "PackageName", 0, REG_SZ, (const BYTE *)data, lstrlenA(data) + 1);
317     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
318
319     /* PackageName value exists */
320     size = 0xdeadbeef;
321     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
322                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
323     ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER,
324            "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r);
325     ok(size == 11 || r != ERROR_SUCCESS, "Expected 11, got %d\n", size);
326
327     /* read the value, don't change size */
328         size = 11;
329     lstrcpyA(value, "aaa");
330     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
331                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
332     ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r);
333     ok(!lstrcmpA(value, "aaa"), "Expected 'aaa', got %s\n", value);
334     ok(size == 11, "Expected 11, got %d\n", size);
335
336     /* read the value, fix size */
337     size++;
338     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
339                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
340     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
341     ok(!lstrcmpA(value, "msitest.msi"), "Expected 'msitest.msi', got %s\n", value);
342     ok(size == 11, "Expected 11, got %d\n", size);
343
344     /* empty property now that product key exists */
345     size = MAX_PATH;
346     lstrcpyA(value, "aaa");
347     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
348                               MSICODE_PRODUCT, "", value, &size);
349     ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
350     ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
351     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
352
353     /* nonexistent property now that product key exists */
354     size = MAX_PATH;
355     lstrcpyA(value, "aaa");
356     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
357                               MSICODE_PRODUCT, "nonexistent", value, &size);
358     ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
359     ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
360     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
361
362     data = "tester";
363     res = RegSetValueExA(hkey, "nonexistent", 0, REG_SZ, (const BYTE *)data, lstrlenA(data) + 1);
364     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
365
366     /* nonexistent property now that nonexistent value exists */
367     size = MAX_PATH;
368     lstrcpyA(value, "aaa");
369     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
370                               MSICODE_PRODUCT, "nonexistent", value, &size);
371     ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
372     ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
373     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
374
375     /* invalid option now that product key exists */
376     size = MAX_PATH;
377     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
378                               4, INSTALLPROPERTY_PACKAGENAME, value, &size);
379     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
380     ok(size == 11, "Expected 11, got %d\n", size);
381
382     /* INSTALLPROPERTY_MEDIAPACKAGEPATH, media key does not exist */
383     size = MAX_PATH;
384     lstrcpyA(value, "aaa");
385     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
386                                MSICODE_PRODUCT, INSTALLPROPERTY_MEDIAPACKAGEPATH,
387                                value, &size);
388     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
389     ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value);
390     ok(size == 0, "Expected 0, got %d\n", size);
391
392     res = RegCreateKeyA(hkey, "Media", &media);
393     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
394
395     data = "path";
396     res = RegSetValueExA(media, "MediaPackage", 0, REG_SZ,
397                          (const BYTE *)data, lstrlenA(data) + 1);
398     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
399
400     /* INSTALLPROPERTY_MEDIAPACKAGEPATH */
401     size = MAX_PATH;
402     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
403                                MSICODE_PRODUCT, INSTALLPROPERTY_MEDIAPACKAGEPATH,
404                                value, &size);
405     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
406     ok(!lstrcmpA(value, "path"), "Expected \"path\", got \"%s\"\n", value);
407     ok(size == 4, "Expected 4, got %d\n", size);
408
409     /* INSTALLPROPERTY_DISKPROMPT */
410     data = "prompt";
411     res = RegSetValueExA(media, "DiskPrompt", 0, REG_SZ,
412                          (const BYTE *)data, lstrlenA(data) + 1);
413     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
414
415     size = MAX_PATH;
416     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
417                                MSICODE_PRODUCT, INSTALLPROPERTY_DISKPROMPT,
418                                value, &size);
419     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
420     ok(!lstrcmpA(value, "prompt"), "Expected \"prompt\", got \"%s\"\n", value);
421     ok(size == 6, "Expected 6, got %d\n", size);
422
423     data = "";
424     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
425                          (const BYTE *)data, lstrlenA(data) + 1);
426     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
427
428     /* INSTALLPROPERTY_LASTUSEDSOURCE, source is empty */
429     size = MAX_PATH;
430     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
431                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE,
432                                value, &size);
433     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
434     ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value);
435     ok(size == 0, "Expected 0, got %d\n", size);
436
437     data = "source";
438     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
439                          (const BYTE *)data, lstrlenA(data) + 1);
440     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
441
442     /* INSTALLPROPERTY_LASTUSEDSOURCE */
443     size = MAX_PATH;
444     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
445                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE,
446                                value, &size);
447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
448     ok(!lstrcmpA(value, "source"), "Expected \"source\", got \"%s\"\n", value);
449     ok(size == 6, "Expected 6, got %d\n", size);
450
451     /* INSTALLPROPERTY_LASTUSEDSOURCE, size is too short */
452     size = 4;
453     lstrcpyA(value, "aaa");
454     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
455                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE,
456                                value, &size);
457     ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r);
458     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got \"%s\"\n", value);
459     ok(size == 6, "Expected 6, got %d\n", size);
460
461     /* INSTALLPROPERTY_LASTUSEDSOURCE, size is exactly 6 */
462     size = 6;
463     lstrcpyA(value, "aaa");
464     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
465                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE,
466                                value, &size);
467     ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r);
468     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got \"%s\"\n", value);
469     ok(size == 6, "Expected 6, got %d\n", size);
470
471     data = "a;source";
472     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
473                          (const BYTE *)data, lstrlenA(data) + 1);
474     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
475
476     /* INSTALLPROPERTY_LASTUSEDSOURCE, one semi-colon */
477     size = MAX_PATH;
478     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
479                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE,
480                                value, &size);
481     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
482     ok(!lstrcmpA(value, "source"), "Expected \"source\", got \"%s\"\n", value);
483     ok(size == 6, "Expected 6, got %d\n", size);
484
485     data = "a:source";
486     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
487                          (const BYTE *)data, lstrlenA(data) + 1);
488     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
489
490     /* INSTALLPROPERTY_LASTUSEDSOURCE, one colon */
491     size = MAX_PATH;
492     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
493                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE,
494                                value, &size);
495     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
496     ok(!lstrcmpA(value, "a:source"), "Expected \"a:source\", got \"%s\"\n", value);
497     ok(size == 8, "Expected 8, got %d\n", size);
498
499     /* INSTALLPROPERTY_LASTUSEDTYPE, invalid source format */
500     size = MAX_PATH;
501     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
502                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE,
503                                value, &size);
504     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
505     ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value);
506     ok(size == 0, "Expected 0, got %d\n", size);
507
508     data = "x;y;z";
509     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
510                          (const BYTE *)data, lstrlenA(data) + 1);
511     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
512
513     /* INSTALLPROPERTY_LASTUSEDTYPE, invalid source format */
514     size = MAX_PATH;
515     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
516                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE,
517                                value, &size);
518     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
519     ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value);
520     ok(size == 0, "Expected 0, got %d\n", size);
521
522     data = "n;y;z";
523     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
524                          (const BYTE *)data, lstrlenA(data) + 1);
525     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
526
527     /* INSTALLPROPERTY_LASTUSEDTYPE */
528     size = MAX_PATH;
529     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
530                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE,
531                                value, &size);
532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
533     ok(!lstrcmpA(value, "n"), "Expected \"n\", got \"%s\"\n", value);
534     ok(size == 1, "Expected 1, got %d\n", size);
535
536     data = "negatory";
537     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
538                          (const BYTE *)data, lstrlenA(data) + 1);
539     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
540
541     /* INSTALLPROPERTY_LASTUSEDTYPE */
542     size = MAX_PATH;
543     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
544                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE,
545                                value, &size);
546     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
547     ok(!lstrcmpA(value, "n"), "Expected \"n\", got \"%s\"\n", value);
548     ok(size == 1, "Expected 1, got %d\n", size);
549
550     data = "megatron";
551     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
552                          (const BYTE *)data, lstrlenA(data) + 1);
553     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
554
555     /* INSTALLPROPERTY_LASTUSEDTYPE */
556     size = MAX_PATH;
557     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
558                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE,
559                                value, &size);
560     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
561     ok(!lstrcmpA(value, "m"), "Expected \"m\", got \"%s\"\n", value);
562     ok(size == 1, "Expected 1, got %d\n", size);
563
564     data = "useless";
565     res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ,
566                          (const BYTE *)data, lstrlenA(data) + 1);
567     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
568
569     /* INSTALLPROPERTY_LASTUSEDTYPE */
570     size = MAX_PATH;
571     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
572                                MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE,
573                                value, &size);
574     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
575     ok(!lstrcmpA(value, "u"), "Expected \"u\", got \"%s\"\n", value);
576     ok(size == 1, "Expected 1, got %d\n", size);
577
578     RegDeleteValueA(media, "MediaPackage");
579     RegDeleteValueA(media, "DiskPrompt");
580     RegDeleteKeyA(media, "");
581     RegDeleteValueA(hkey, "LastUsedSource");
582     RegDeleteValueA(hkey, "nonexistent");
583     RegDeleteValueA(hkey, "PackageName");
584     RegDeleteKeyA(hkey, "");
585     RegDeleteKeyA(userkey, "");
586     RegCloseKey(hkey);
587     RegCloseKey(userkey);
588
589     /* try a patch */
590     size = MAX_PATH;
591     lstrcpyA(value, "aaa");
592     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
593                               MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, value, &size);
594     ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r);
595     ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
596     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
597
598     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Patches\\");
599     lstrcatA(keypath, prod_squashed);
600
601     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
602     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
603
604     /* patch key exists
605      * NOTE: using prodcode guid, but it really doesn't matter
606      */
607     size = MAX_PATH;
608     lstrcpyA(value, "aaa");
609     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
610                               MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, value, &size);
611     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
612     ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
613     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
614
615     res = RegCreateKeyA(userkey, "SourceList", &hkey);
616     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
617
618     /* SourceList key exists */
619     size = MAX_PATH;
620     lstrcpyA(value, "aaa");
621     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
622                               MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, value, &size);
623     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
624     ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value);
625     ok(size == 0, "Expected 0, got %d\n", size);
626
627     RegDeleteKeyA(hkey, "");
628     RegDeleteKeyA(userkey, "");
629     RegCloseKey(hkey);
630     RegCloseKey(userkey);
631     LocalFree(usersid);
632 }
633
634 static LONG delete_key( HKEY key, LPCSTR subkey, REGSAM access )
635 {
636     if (pRegDeleteKeyExA)
637         return pRegDeleteKeyExA( key, subkey, access, 0 );
638     return RegDeleteKeyA( key, subkey );
639 }
640
641 static void test_MsiSourceListAddSourceEx(void)
642 {
643     CHAR prodcode[MAX_PATH];
644     CHAR prod_squashed[MAX_PATH];
645     CHAR keypath[MAX_PATH*2];
646     CHAR value[MAX_PATH];
647     LPSTR usersid;
648     LONG res;
649     UINT r;
650     HKEY prodkey, userkey, hkey, url, net;
651     DWORD size;
652     REGSAM access = KEY_ALL_ACCESS;
653     BOOL wow64;
654
655     if (!pMsiSourceListAddSourceExA)
656     {
657         win_skip("Skipping MsiSourceListAddSourceExA tests\n");
658         return;
659     }
660
661     create_test_guid(prodcode, prod_squashed);
662     if (!get_user_sid(&usersid))
663     {
664         skip("User SID not available -> skipping MsiSourceListAddSourceExA tests\n");
665         return;
666     }
667
668     if (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &wow64) && wow64)
669         access |= KEY_WOW64_64KEY;
670
671     /* GetLastError is not set by the function */
672
673     /* NULL szProductCodeOrPatchCode */
674     r = pMsiSourceListAddSourceExA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
675                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
676     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
677
678     /* empty szProductCodeOrPatchCode */
679     r = pMsiSourceListAddSourceExA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
680                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
681     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
682
683     /* garbage szProductCodeOrPatchCode */
684     r = pMsiSourceListAddSourceExA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
685                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
686     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
687
688     /* guid without brackets */
689     r = pMsiSourceListAddSourceExA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", usersid,
690                                   MSIINSTALLCONTEXT_USERUNMANAGED,
691                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
692     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
693
694     /* guid with brackets */
695     r = pMsiSourceListAddSourceExA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", usersid,
696                                   MSIINSTALLCONTEXT_USERUNMANAGED,
697                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
698     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
699
700     /* MSIINSTALLCONTEXT_USERUNMANAGED */
701
702     r = pMsiSourceListAddSourceExA(prodcode, usersid,
703                                   MSIINSTALLCONTEXT_USERUNMANAGED,
704                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
705     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
706
707     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
708     lstrcatA(keypath, prod_squashed);
709
710     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
711     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
712
713     /* user product key exists */
714     r = pMsiSourceListAddSourceExA(prodcode, usersid,
715                                   MSIINSTALLCONTEXT_USERUNMANAGED,
716                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
717     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
718
719     res = RegCreateKeyA(userkey, "SourceList", &url);
720     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
721     RegCloseKey(url);
722
723     /* SourceList key exists */
724     r = pMsiSourceListAddSourceExA(prodcode, usersid,
725                                   MSIINSTALLCONTEXT_USERUNMANAGED,
726                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
727     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
728
729     res = RegOpenKeyA(userkey, "SourceList\\URL", &url);
730     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
731
732     size = MAX_PATH;
733     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
734     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
735     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
736     ok(size == 11, "Expected 11, got %d\n", size);
737
738     /* add another source, index 0 */
739     r = pMsiSourceListAddSourceExA(prodcode, usersid,
740                                   MSIINSTALLCONTEXT_USERUNMANAGED,
741                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "another", 0);
742     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
743
744     size = MAX_PATH;
745     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
746     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
747     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
748     ok(size == 11, "Expected 11, got %d\n", size);
749
750     size = MAX_PATH;
751     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
752     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
753     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
754     ok(size == 9, "Expected 9, got %d\n", size);
755
756     /* add another source, index 1 */
757     r = pMsiSourceListAddSourceExA(prodcode, usersid,
758                                   MSIINSTALLCONTEXT_USERUNMANAGED,
759                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "third/", 1);
760     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
761
762     size = MAX_PATH;
763     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
764     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
765     ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
766     ok(size == 7, "Expected 7, got %d\n", size);
767
768     size = MAX_PATH;
769     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
770     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
771     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
772     ok(size == 11, "Expected 11, got %d\n", size);
773
774     size = MAX_PATH;
775     res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
776     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
777     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
778     ok(size == 9, "Expected 9, got %d\n", size);
779
780     /* add another source, index > N */
781     r = pMsiSourceListAddSourceExA(prodcode, usersid,
782                                   MSIINSTALLCONTEXT_USERUNMANAGED,
783                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "last/", 5);
784     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
785
786     size = MAX_PATH;
787     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
788     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
789     ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
790     ok(size == 7, "Expected 7, got %d\n", size);
791
792     size = MAX_PATH;
793     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
794     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
795     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
796     ok(size == 11, "Expected 11, got %d\n", size);
797
798     size = MAX_PATH;
799     res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
800     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
801     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
802     ok(size == 9, "Expected 9, got %d\n", size);
803
804     size = MAX_PATH;
805     res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size);
806     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
807     ok(!lstrcmpA(value, "last/"), "Expected 'last/', got %s\n", value);
808     ok(size == 6, "Expected 6, got %d\n", size);
809
810     /* just MSISOURCETYPE_NETWORK */
811     r = pMsiSourceListAddSourceExA(prodcode, usersid,
812                                   MSIINSTALLCONTEXT_USERUNMANAGED,
813                                   MSISOURCETYPE_NETWORK, "source", 0);
814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
815
816     res = RegOpenKeyA(userkey, "SourceList\\Net", &net);
817     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
818
819     size = MAX_PATH;
820     res = RegQueryValueExA(net, "1", NULL, NULL, (LPBYTE)value, &size);
821     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
822     ok(!lstrcmpA(value, "source\\"), "Expected 'source\\', got %s\n", value);
823     ok(size == 8, "Expected 8, got %d\n", size);
824
825     /* just MSISOURCETYPE_URL */
826     r = pMsiSourceListAddSourceExA(prodcode, usersid,
827                                   MSIINSTALLCONTEXT_USERUNMANAGED,
828                                   MSISOURCETYPE_URL, "source", 0);
829     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
830
831     size = MAX_PATH;
832     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
833     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
834     ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
835     ok(size == 7, "Expected 7, got %d\n", size);
836
837     size = MAX_PATH;
838     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
839     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
840     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
841     ok(size == 11, "Expected 11, got %d\n", size);
842
843     size = MAX_PATH;
844     res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
845     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
846     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
847     ok(size == 9, "Expected 9, got %d\n", size);
848
849     size = MAX_PATH;
850     res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size);
851     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
852     ok(!lstrcmpA(value, "last/"), "Expected 'last/', got %s\n", value);
853     ok(size == 6, "Expected 6, got %d\n", size);
854
855     size = MAX_PATH;
856     res = RegQueryValueExA(url, "5", NULL, NULL, (LPBYTE)value, &size);
857     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
858     ok(!lstrcmpA(value, "source/"), "Expected 'source/', got %s\n", value);
859     ok(size == 8, "Expected 8, got %d\n", size);
860
861     /* NULL szUserSid */
862     r = pMsiSourceListAddSourceExA(prodcode, NULL,
863                                   MSIINSTALLCONTEXT_USERUNMANAGED,
864                                   MSISOURCETYPE_NETWORK, "nousersid", 0);
865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
866
867     size = MAX_PATH;
868     res = RegQueryValueExA(net, "1", NULL, NULL, (LPBYTE)value, &size);
869     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
870     ok(!lstrcmpA(value, "source\\"), "Expected 'source\\', got %s\n", value);
871     ok(size == 8, "Expected 8, got %d\n", size);
872
873     size = MAX_PATH;
874     res = RegQueryValueExA(net, "2", NULL, NULL, (LPBYTE)value, &size);
875     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
876     ok(!lstrcmpA(value, "nousersid\\"), "Expected 'nousersid\\', got %s\n", value);
877     ok(size == 11, "Expected 11, got %d\n", size);
878
879     /* invalid options, must have source type */
880     r = pMsiSourceListAddSourceExA(prodcode, usersid,
881                                   MSIINSTALLCONTEXT_USERUNMANAGED,
882                                   MSICODE_PRODUCT, "source", 0);
883     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
884
885     r = pMsiSourceListAddSourceExA(prodcode, usersid,
886                                   MSIINSTALLCONTEXT_USERUNMANAGED,
887                                   MSICODE_PATCH, "source", 0);
888     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
889
890     /* NULL szSource */
891     r = pMsiSourceListAddSourceExA(prodcode, usersid,
892                                   MSIINSTALLCONTEXT_USERUNMANAGED,
893                                   MSISOURCETYPE_URL, NULL, 1);
894     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
895
896     /* empty szSource */
897     r = pMsiSourceListAddSourceExA(prodcode, usersid,
898                                   MSIINSTALLCONTEXT_USERUNMANAGED,
899                                   MSISOURCETYPE_URL, "", 1);
900     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
901
902     /* MSIINSTALLCONTEXT_USERMANAGED, non-NULL szUserSid */
903
904     r = pMsiSourceListAddSourceExA(prodcode, usersid,
905                                   MSIINSTALLCONTEXT_USERMANAGED,
906                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
907     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
908
909     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\");
910     lstrcatA(keypath, usersid);
911     lstrcatA(keypath, "\\Installer\\Products\\");
912     lstrcatA(keypath, prod_squashed);
913
914     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &prodkey, NULL);
915     if (res != ERROR_SUCCESS)
916     {
917         skip("Product key creation failed with error code %u\n", res);
918         goto machine_tests;
919     }
920
921     /* product key exists */
922     r = pMsiSourceListAddSourceExA(prodcode, usersid,
923                                   MSIINSTALLCONTEXT_USERMANAGED,
924                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
925     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
926
927     res = RegCreateKeyExA(prodkey, "SourceList", 0, NULL, 0, access, NULL, &hkey, NULL);
928     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
929     RegCloseKey(hkey);
930
931     /* SourceList exists */
932     r = pMsiSourceListAddSourceExA(prodcode, usersid,
933                                   MSIINSTALLCONTEXT_USERMANAGED,
934                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
935     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
936
937     res = RegOpenKeyExA(prodkey, "SourceList\\URL", 0, access, &url);
938     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
939
940     size = MAX_PATH;
941     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
942     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
943     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
944     ok(size == 11, "Expected 11, got %d\n", size);
945
946     RegCloseKey(url);
947
948     /* MSIINSTALLCONTEXT_USERMANAGED, NULL szUserSid */
949
950     r = pMsiSourceListAddSourceExA(prodcode, NULL,
951                                   MSIINSTALLCONTEXT_USERMANAGED,
952                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "another", 0);
953     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
954
955     res = RegOpenKeyExA(prodkey, "SourceList\\URL", 0, access, &url);
956     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
957
958     size = MAX_PATH;
959     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
960     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
961     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
962     ok(size == 11, "Expected 11, got %d\n", size);
963
964     size = MAX_PATH;
965     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
966     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
967     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
968     ok(size == 9, "Expected 9, got %d\n", size);
969
970     RegCloseKey(url);
971     RegCloseKey(prodkey);
972
973     /* MSIINSTALLCONTEXT_MACHINE */
974
975 machine_tests:
976     /* szUserSid must be NULL for MSIINSTALLCONTEXT_MACHINE */
977     r = pMsiSourceListAddSourceExA(prodcode, usersid,
978                                   MSIINSTALLCONTEXT_MACHINE,
979                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
980     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
981
982     r = pMsiSourceListAddSourceExA(prodcode, NULL,
983                                   MSIINSTALLCONTEXT_MACHINE,
984                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
985     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
986
987     lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\");
988     lstrcatA(keypath, prod_squashed);
989
990     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &prodkey, NULL);
991     if (res != ERROR_SUCCESS)
992     {
993         skip("Product key creation failed with error code %u\n", res);
994         LocalFree(usersid);
995         return;
996     }
997
998     /* product key exists */
999     r = pMsiSourceListAddSourceExA(prodcode, NULL,
1000                                   MSIINSTALLCONTEXT_MACHINE,
1001                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
1002     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
1003
1004     res = RegCreateKeyExA(prodkey, "SourceList", 0, NULL, 0, access, NULL, &hkey, NULL);
1005     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1006     RegCloseKey(hkey);
1007
1008     /* SourceList exists */
1009     r = pMsiSourceListAddSourceExA(prodcode, NULL,
1010                                   MSIINSTALLCONTEXT_MACHINE,
1011                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
1012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1013
1014     res = RegOpenKeyExA(prodkey, "SourceList\\URL", 0, access, &url);
1015     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1016
1017     size = MAX_PATH;
1018     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
1019     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1020     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
1021     ok(size == 11, "Expected 11, got %d\n", size);
1022
1023     RegCloseKey(url);
1024     RegCloseKey(prodkey);
1025     LocalFree(usersid);
1026 }
1027
1028 static void test_MsiSourceListEnumSources(void)
1029 {
1030     CHAR prodcode[MAX_PATH];
1031     CHAR prod_squashed[MAX_PATH];
1032     CHAR keypath[MAX_PATH*2];
1033     CHAR value[MAX_PATH];
1034     LPSTR usersid;
1035     LONG res;
1036     UINT r;
1037     HKEY prodkey, userkey;
1038     HKEY url, net, source;
1039     DWORD size;
1040     REGSAM access = KEY_ALL_ACCESS;
1041     BOOL wow64;
1042
1043     if (!pMsiSourceListEnumSourcesA)
1044     {
1045         win_skip("MsiSourceListEnumSourcesA is not available\n");
1046         return;
1047     }
1048
1049     create_test_guid(prodcode, prod_squashed);
1050     if (!get_user_sid(&usersid))
1051     {
1052         skip("User SID not available -> skipping MsiSourceListEnumSourcesA tests\n");
1053         return;
1054     }
1055
1056     if (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &wow64) && wow64)
1057         access |= KEY_WOW64_64KEY;
1058
1059     /* GetLastError is not set by the function */
1060
1061     /* NULL szProductCodeOrPatchCode */
1062     size = 0xdeadbeef;
1063     r = pMsiSourceListEnumSourcesA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1064                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1065     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1066     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
1067
1068     /* empty szProductCodeOrPatchCode */
1069     size = 0xdeadbeef;
1070     r = pMsiSourceListEnumSourcesA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1071                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1072     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1073     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
1074
1075     /* garbage szProductCodeOrPatchCode */
1076     size = 0xdeadbeef;
1077     r = pMsiSourceListEnumSourcesA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1078                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1079     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1080     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
1081
1082     /* guid without brackets */
1083     size = 0xdeadbeef;
1084     r = pMsiSourceListEnumSourcesA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA",
1085                                    usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1086                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1087     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1088     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
1089
1090     /* guid with brackets */
1091     size = 0xdeadbeef;
1092     r = pMsiSourceListEnumSourcesA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}",
1093                                    usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1094                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1095     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1096     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
1097
1098     /* MSIINSTALLCONTEXT_USERUNMANAGED */
1099
1100     size = MAX_PATH;
1101     lstrcpyA(value, "aaa");
1102     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1103                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1104                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1105     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1106     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1107     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1108
1109     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
1110     lstrcatA(keypath, prod_squashed);
1111
1112     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
1113     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1114
1115     /* user product key exists */
1116     size = MAX_PATH;
1117     lstrcpyA(value, "aaa");
1118     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1119                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1120                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1121     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
1122     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1123     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1124
1125     res = RegCreateKeyA(userkey, "SourceList", &source);
1126     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1127
1128     /* SourceList key exists */
1129     size = MAX_PATH;
1130     lstrcpyA(value, "aaa");
1131     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1132                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1133                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1134     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1135     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1136     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1137
1138     res = RegCreateKeyA(source, "URL", &url);
1139     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1140
1141     /* URL key exists */
1142     size = MAX_PATH;
1143     lstrcpyA(value, "aaa");
1144     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1145                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1146                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1147     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1148     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1149     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1150
1151     res = RegSetValueExA(url, "1", 0, REG_SZ, (LPBYTE)"first", 6);
1152     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1153
1154     res = RegSetValueExA(url, "2", 0, REG_SZ, (LPBYTE)"second", 7);
1155     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1156
1157     res = RegSetValueExA(url, "4", 0, REG_SZ, (LPBYTE)"fourth", 7);
1158     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1159
1160     /* sources exist */
1161     size = MAX_PATH;
1162     lstrcpyA(value, "aaa");
1163     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1164                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1165                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1166     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1167     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1168     ok(size == 5, "Expected 5, got %d\n", size);
1169
1170     /* try index 0 again */
1171     size = MAX_PATH;
1172     lstrcpyA(value, "aaa");
1173     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1174                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1175                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1176     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1177     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1178     ok(size == 5, "Expected 5, got %d\n", size);
1179
1180     /* both szSource and pcchSource are NULL, index 0 */
1181     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1182                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1183                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, NULL);
1184     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1185
1186     /* both szSource and pcchSource are NULL, index 1 */
1187     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1188                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1189                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, NULL, NULL);
1190     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1191
1192     /* size is exactly 5 */
1193     size = 5;
1194     lstrcpyA(value, "aaa");
1195     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1196                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1197                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1198     ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r);
1199     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got %s\n", value);
1200     ok(size == 5, "Expected 5, got %d\n", size);
1201
1202     /* szSource is non-NULL while pcchSource is NULL */
1203     lstrcpyA(value, "aaa");
1204     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1205                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1206                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, NULL);
1207     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1208     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got %s\n", value);
1209
1210     /* try index 1 after failure */
1211     size = MAX_PATH;
1212     lstrcpyA(value, "aaa");
1213     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1214                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1215                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, value, &size);
1216     ok(r == ERROR_INVALID_PARAMETER,
1217        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1218     ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got %s\n", value);
1219     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1220
1221     /* reset the enumeration */
1222     size = MAX_PATH;
1223     lstrcpyA(value, "aaa");
1224     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1225                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1226                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1227     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1228     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1229     ok(size == 5, "Expected 5, got %d\n", size);
1230
1231     /* try index 1 */
1232     size = MAX_PATH;
1233     lstrcpyA(value, "aaa");
1234     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1235                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1236                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, value, &size);
1237     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1238     ok(!lstrcmpA(value, "second"), "Expected \"second\", got %s\n", value);
1239     ok(size == 6, "Expected 6, got %d\n", size);
1240
1241     /* try index 1 again */
1242     size = MAX_PATH;
1243     lstrcpyA(value, "aaa");
1244     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1245                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1246                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, value, &size);
1247     ok(r == ERROR_INVALID_PARAMETER,
1248        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1249     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1250     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1251
1252     /* try index 2 */
1253     size = MAX_PATH;
1254     lstrcpyA(value, "aaa");
1255     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1256                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1257                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 2, value, &size);
1258     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1259     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1260     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1261
1262     /* try index < 0 */
1263     size = MAX_PATH;
1264     lstrcpyA(value, "aaa");
1265     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1266                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1267                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, -1, value, &size);
1268     ok(r == ERROR_INVALID_PARAMETER,
1269        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1270     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1271     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1272
1273     /* NULL szUserSid */
1274     size = MAX_PATH;
1275     lstrcpyA(value, "aaa");
1276     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1277                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1278                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1280     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1281     ok(size == 5, "Expected 5, got %d\n", size);
1282
1283     /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */
1284     size = MAX_PATH;
1285     lstrcpyA(value, "aaa");
1286     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1287                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1288                                    MSICODE_PRODUCT, 0, value, &size);
1289     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1290     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1291     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1292
1293     /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */
1294     size = MAX_PATH;
1295     lstrcpyA(value, "aaa");
1296     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1297                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1298                                    MSICODE_PATCH, 0, value, &size);
1299     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1300     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1301     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1302
1303     /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */
1304     size = MAX_PATH;
1305     lstrcpyA(value, "aaa");
1306     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1307                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1308                                    MSICODE_PRODUCT | MSICODE_PATCH | MSISOURCETYPE_URL,
1309                                    0, value, &size);
1310     ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_SUCCESS, got %d\n", r);
1311     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1312     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1313
1314     /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */
1315     size = MAX_PATH;
1316     lstrcpyA(value, "aaa");
1317     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1318                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1319                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL,
1320                                    0, value, &size);
1321     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1322     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1323     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1324
1325     RegDeleteValueA(url, "1");
1326     RegDeleteValueA(url, "2");
1327     RegDeleteValueA(url, "4");
1328     RegDeleteKeyA(url, "");
1329     RegCloseKey(url);
1330
1331     /* SourceList key exists */
1332     size = MAX_PATH;
1333     lstrcpyA(value, "aaa");
1334     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1335                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1336                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1337     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1338     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1339     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1340
1341     res = RegCreateKeyA(source, "Net", &net);
1342     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1343
1344     /* Net key exists */
1345     size = MAX_PATH;
1346     lstrcpyA(value, "aaa");
1347     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1348                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1349                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1350     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1351     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1352     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1353
1354     res = RegSetValueExA(net, "1", 0, REG_SZ, (LPBYTE)"first", 6);
1355     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1356
1357     /* sources exist */
1358     size = MAX_PATH;
1359     lstrcpyA(value, "aaa");
1360     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1361                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1362                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1363     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1364     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1365     ok(size == 5, "Expected 5, got %d\n", size);
1366
1367     RegDeleteValueA(net, "1");
1368     RegDeleteKeyA(net, "");
1369     RegCloseKey(net);
1370     RegDeleteKeyA(source, "");
1371     RegCloseKey(source);
1372     RegDeleteKeyA(userkey, "");
1373     RegCloseKey(userkey);
1374
1375     /* MSIINSTALLCONTEXT_USERMANAGED */
1376
1377     size = MAX_PATH;
1378     lstrcpyA(value, "aaa");
1379     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1380                                    MSIINSTALLCONTEXT_USERMANAGED,
1381                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1382     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1383     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1384     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1385
1386     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\");
1387     lstrcatA(keypath, usersid);
1388     lstrcatA(keypath, "\\Installer\\Products\\");
1389     lstrcatA(keypath, prod_squashed);
1390
1391     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &userkey, NULL);
1392     if (res != ERROR_SUCCESS)
1393     {
1394         skip("Product key creation failed with error code %u\n", res);
1395         goto machine_tests;
1396     }
1397
1398     /* user product key exists */
1399     size = MAX_PATH;
1400     lstrcpyA(value, "aaa");
1401     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1402                                    MSIINSTALLCONTEXT_USERMANAGED,
1403                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1404     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
1405     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1406     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1407
1408     res = RegCreateKeyExA(userkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
1409     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1410
1411     /* SourceList key exists */
1412     size = MAX_PATH;
1413     lstrcpyA(value, "aaa");
1414     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1415                                    MSIINSTALLCONTEXT_USERMANAGED,
1416                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1417     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1418     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1419     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1420
1421     res = RegCreateKeyExA(source, "URL", 0, NULL, 0, access, NULL, &url, NULL);
1422     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1423
1424     /* URL key exists */
1425     size = MAX_PATH;
1426     lstrcpyA(value, "aaa");
1427     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1428                                    MSIINSTALLCONTEXT_USERMANAGED,
1429                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1430     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1431     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1432     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1433
1434     res = RegSetValueExA(url, "1", 0, REG_SZ, (LPBYTE)"first", 6);
1435     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1436
1437     /* sources exist */
1438     size = MAX_PATH;
1439     lstrcpyA(value, "aaa");
1440     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1441                                    MSIINSTALLCONTEXT_USERMANAGED,
1442                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1443     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1444     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1445     ok(size == 5, "Expected 5, got %d\n", size);
1446
1447     /* NULL szUserSid */
1448     size = MAX_PATH;
1449     lstrcpyA(value, "aaa");
1450     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1451                                    MSIINSTALLCONTEXT_USERMANAGED,
1452                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1454     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1455     ok(size == 5, "Expected 5, got %d\n", size);
1456
1457     RegDeleteValueA(url, "1");
1458     delete_key(url, "", access);
1459     RegCloseKey(url);
1460
1461     /* SourceList key exists */
1462     size = MAX_PATH;
1463     lstrcpyA(value, "aaa");
1464     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1465                                    MSIINSTALLCONTEXT_USERMANAGED,
1466                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1467     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1468     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1469     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1470
1471     res = RegCreateKeyExA(source, "Net", 0, NULL, 0, access, NULL, &net, NULL);
1472     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1473
1474     /* Net key exists */
1475     size = MAX_PATH;
1476     lstrcpyA(value, "aaa");
1477     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1478                                    MSIINSTALLCONTEXT_USERMANAGED,
1479                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1480     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1481     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1482     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1483
1484     res = RegSetValueExA(net, "1", 0, REG_SZ, (LPBYTE)"first", 6);
1485     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1486
1487     /* sources exist */
1488     size = MAX_PATH;
1489     lstrcpyA(value, "aaa");
1490     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1491                                    MSIINSTALLCONTEXT_USERMANAGED,
1492                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1493     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1494     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1495     ok(size == 5, "Expected 5, got %d\n", size);
1496
1497     RegDeleteValueA(net, "1");
1498     delete_key(net, "", access);
1499     RegCloseKey(net);
1500     delete_key(source, "", access);
1501     RegCloseKey(source);
1502     delete_key(userkey, "", access);
1503     RegCloseKey(userkey);
1504
1505     /* MSIINSTALLCONTEXT_MACHINE */
1506
1507 machine_tests:
1508     /* szUserSid is non-NULL */
1509     size = MAX_PATH;
1510     lstrcpyA(value, "aaa");
1511     r = pMsiSourceListEnumSourcesA(prodcode, usersid,
1512                                    MSIINSTALLCONTEXT_MACHINE,
1513                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1514     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1515     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1516     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1517
1518     /* szUserSid is NULL */
1519     size = MAX_PATH;
1520     lstrcpyA(value, "aaa");
1521     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1522                                    MSIINSTALLCONTEXT_MACHINE,
1523                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1524     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1525     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1526     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1527
1528     lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\");
1529     lstrcatA(keypath, prod_squashed);
1530
1531     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &prodkey, NULL);
1532     if (res != ERROR_SUCCESS)
1533     {
1534         skip("Product key creation failed with error code %u\n", res);
1535         LocalFree(usersid);
1536         return;
1537     }
1538
1539     /* user product key exists */
1540     size = MAX_PATH;
1541     lstrcpyA(value, "aaa");
1542     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1543                                    MSIINSTALLCONTEXT_MACHINE,
1544                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1545     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
1546     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1547     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1548
1549     res = RegCreateKeyExA(prodkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
1550     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1551
1552     /* SourceList key exists */
1553     size = MAX_PATH;
1554     lstrcpyA(value, "aaa");
1555     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1556                                    MSIINSTALLCONTEXT_MACHINE,
1557                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1558     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1559     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1560     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1561
1562     res = RegCreateKeyExA(source, "URL", 0, NULL, 0, access, NULL, &url, NULL);
1563     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1564
1565     /* URL key exists */
1566     size = MAX_PATH;
1567     lstrcpyA(value, "aaa");
1568     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1569                                    MSIINSTALLCONTEXT_MACHINE,
1570                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1571     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1572     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1573     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1574
1575     res = RegSetValueExA(url, "1", 0, REG_SZ, (LPBYTE)"first", 6);
1576     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1577
1578     /* sources exist */
1579     size = MAX_PATH;
1580     lstrcpyA(value, "aaa");
1581     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1582                                    MSIINSTALLCONTEXT_MACHINE,
1583                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1584     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1585     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1586     ok(size == 5, "Expected 5, got %d\n", size);
1587
1588     /* NULL szUserSid */
1589     size = MAX_PATH;
1590     lstrcpyA(value, "aaa");
1591     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1592                                    MSIINSTALLCONTEXT_MACHINE,
1593                                    MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
1594     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1595     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1596     ok(size == 5, "Expected 5, got %d\n", size);
1597
1598     RegDeleteValueA(url, "1");
1599     delete_key(url, "", access);
1600     RegCloseKey(url);
1601
1602     /* SourceList key exists */
1603     size = MAX_PATH;
1604     lstrcpyA(value, "aaa");
1605     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1606                                    MSIINSTALLCONTEXT_MACHINE,
1607                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1608     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1609     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1610     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1611
1612     res = RegCreateKeyExA(source, "Net", 0, NULL, 0, access, NULL, &net, NULL);
1613     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1614
1615     /* Net key exists */
1616     size = MAX_PATH;
1617     lstrcpyA(value, "aaa");
1618     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1619                                    MSIINSTALLCONTEXT_MACHINE,
1620                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1621     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1622     ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value);
1623     ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size);
1624
1625     res = RegSetValueExA(net, "1", 0, REG_SZ, (LPBYTE)"first", 6);
1626     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1627
1628     /* sources exist */
1629     size = MAX_PATH;
1630     lstrcpyA(value, "aaa");
1631     r = pMsiSourceListEnumSourcesA(prodcode, NULL,
1632                                    MSIINSTALLCONTEXT_MACHINE,
1633                                    MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size);
1634     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1635     ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value);
1636     ok(size == 5, "Expected 5, got %d\n", size);
1637
1638     RegDeleteValueA(net, "1");
1639     delete_key(net, "", access);
1640     RegCloseKey(net);
1641     delete_key(source, "", access);
1642     RegCloseKey(source);
1643     delete_key(prodkey, "", access);
1644     RegCloseKey(prodkey);
1645     LocalFree(usersid);
1646 }
1647
1648 static void test_MsiSourceListSetInfo(void)
1649 {
1650     CHAR prodcode[MAX_PATH];
1651     CHAR prod_squashed[MAX_PATH];
1652     CHAR keypath[MAX_PATH*2];
1653     HKEY prodkey, userkey;
1654     HKEY net, url, media, source;
1655     LPSTR usersid;
1656     LONG res;
1657     UINT r;
1658     REGSAM access = KEY_ALL_ACCESS;
1659     BOOL wow64;
1660
1661     if (!pMsiSourceListSetInfoA)
1662     {
1663         win_skip("MsiSourceListSetInfoA is not available\n");
1664         return;
1665     }
1666
1667     create_test_guid(prodcode, prod_squashed);
1668     if (!get_user_sid(&usersid))
1669     {
1670         skip("User SID not available -> skipping MsiSourceListSetInfoA tests\n");
1671         return;
1672     }
1673
1674     if (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &wow64) && wow64)
1675         access |= KEY_WOW64_64KEY;
1676
1677     /* GetLastError is not set by the function */
1678
1679     /* NULL szProductCodeOrPatchCode */
1680     r = pMsiSourceListSetInfoA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1681                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1682                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1683     ok(r == ERROR_INVALID_PARAMETER,
1684        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1685
1686     /* empty szProductCodeOrPatchCode */
1687     r = pMsiSourceListSetInfoA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1688                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1689                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1690     ok(r == ERROR_INVALID_PARAMETER,
1691        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1692
1693     /* garbage szProductCodeOrPatchCode */
1694     r = pMsiSourceListSetInfoA("garbage", usersid,
1695                                MSIINSTALLCONTEXT_USERUNMANAGED,
1696                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1697                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1698     ok(r == ERROR_INVALID_PARAMETER,
1699        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1700
1701     /* guid without brackets */
1702     r = pMsiSourceListSetInfoA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA",
1703                                usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1704                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1705                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1706     ok(r == ERROR_INVALID_PARAMETER,
1707        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1708
1709     /* guid with brackets */
1710     r = pMsiSourceListSetInfoA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}",
1711                                usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
1712                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1713                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1714     ok(r == ERROR_UNKNOWN_PRODUCT,
1715        "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1716
1717     /* dwOptions is MSICODE_PRODUCT */
1718     r = pMsiSourceListSetInfoA(prodcode, usersid,
1719                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1720                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1721     ok(r == ERROR_UNKNOWN_PRODUCT,
1722        "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1723
1724     /* dwOptions is MSICODE_PATCH */
1725     r = pMsiSourceListSetInfoA(prodcode, usersid,
1726                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PATCH,
1727                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1728     ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r);
1729
1730     /* dwOptions is both MSICODE_PRODUCT and MSICODE_PATCH */
1731     r = pMsiSourceListSetInfoA(prodcode, usersid,
1732                                MSIINSTALLCONTEXT_USERUNMANAGED,
1733                                MSICODE_PRODUCT | MSICODE_PATCH | MSISOURCETYPE_URL,
1734                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1735     ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r);
1736
1737     /* dwOptions has both MSISOURCETYPE_NETWORK and MSISOURCETYPE_URL */
1738     r = pMsiSourceListSetInfoA(prodcode, NULL,
1739                                MSIINSTALLCONTEXT_USERUNMANAGED,
1740                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL,
1741                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1742     ok(r == ERROR_UNKNOWN_PRODUCT,
1743        "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1744
1745     /* LastUsedSource and dwOptions has both
1746      * MSISOURCETYPE_NETWORK and MSISOURCETYPE_URL
1747      */
1748     r = pMsiSourceListSetInfoA(prodcode, NULL,
1749                                MSIINSTALLCONTEXT_USERUNMANAGED,
1750                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL,
1751                                INSTALLPROPERTY_LASTUSEDSOURCE, "path");
1752     ok(r == ERROR_UNKNOWN_PRODUCT,
1753        "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1754
1755     /* LastUsedSource and dwOptions has no source type */
1756     r = pMsiSourceListSetInfoA(prodcode, NULL,
1757                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1758                                INSTALLPROPERTY_LASTUSEDSOURCE, "path");
1759     ok(r == ERROR_UNKNOWN_PRODUCT,
1760        "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
1761
1762     /* MSIINSTALLCONTEXT_USERUNMANAGED */
1763
1764     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
1765     lstrcatA(keypath, prod_squashed);
1766
1767     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
1768     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1769
1770     /* user product key exists */
1771     r = pMsiSourceListSetInfoA(prodcode, NULL,
1772                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1773                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1774     ok(r == ERROR_BAD_CONFIGURATION,
1775        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
1776
1777     res = RegCreateKeyA(userkey, "SourceList", &source);
1778     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1779
1780     /* SourceList key exists, no source type */
1781     r = pMsiSourceListSetInfoA(prodcode, NULL,
1782                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1783                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1784     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1785
1786     /* Media key is created by MsiSourceListSetInfo */
1787     res = RegOpenKeyA(source, "Media", &media);
1788     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1789     CHECK_REG_STR(media, "MediaPackage", "path");
1790
1791     /* set the info again */
1792     r = pMsiSourceListSetInfoA(prodcode, NULL,
1793                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1794                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path2");
1795     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1796     CHECK_REG_STR(media, "MediaPackage", "path2");
1797
1798     /* NULL szProperty */
1799     r = pMsiSourceListSetInfoA(prodcode, NULL,
1800                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1801                                NULL, "path");
1802     ok(r == ERROR_INVALID_PARAMETER,
1803        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1804
1805     /* empty szProperty */
1806     r = pMsiSourceListSetInfoA(prodcode, NULL,
1807                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1808                                "", "path");
1809     ok(r == ERROR_UNKNOWN_PROPERTY,
1810        "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
1811
1812     /* NULL szValue */
1813     r = pMsiSourceListSetInfoA(prodcode, NULL,
1814                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1815                                INSTALLPROPERTY_MEDIAPACKAGEPATH, NULL);
1816     ok(r == ERROR_UNKNOWN_PROPERTY,
1817        "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
1818
1819     /* empty szValue */
1820     r = pMsiSourceListSetInfoA(prodcode, NULL,
1821                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1822                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "");
1823     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1824     CHECK_REG_STR(media, "MediaPackage", "");
1825
1826     /* INSTALLPROPERTY_MEDIAPACKAGEPATH, MSISOURCETYPE_NETWORK */
1827     r = pMsiSourceListSetInfoA(prodcode, NULL,
1828                                MSIINSTALLCONTEXT_USERUNMANAGED,
1829                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1830                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1831     ok(r == ERROR_INVALID_PARAMETER,
1832        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1833
1834     /* INSTALLPROPERTY_MEDIAPACKAGEPATH, MSISOURCETYPE_URL */
1835     r = pMsiSourceListSetInfoA(prodcode, NULL,
1836                                MSIINSTALLCONTEXT_USERUNMANAGED,
1837                                MSICODE_PRODUCT | MSISOURCETYPE_URL,
1838                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1839     ok(r == ERROR_INVALID_PARAMETER,
1840        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1841
1842     /* INSTALLPROPERTY_DISKPROMPT */
1843     r = pMsiSourceListSetInfoA(prodcode, NULL,
1844                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1845                                INSTALLPROPERTY_DISKPROMPT, "prompt");
1846     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1847     CHECK_REG_STR(media, "DiskPrompt", "prompt");
1848
1849     /* INSTALLPROPERTY_DISKPROMPT, MSISOURCETYPE_NETWORK */
1850     r = pMsiSourceListSetInfoA(prodcode, NULL,
1851                                MSIINSTALLCONTEXT_USERUNMANAGED,
1852                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1853                                INSTALLPROPERTY_DISKPROMPT, "prompt");
1854     ok(r == ERROR_INVALID_PARAMETER,
1855        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1856
1857     /* INSTALLPROPERTY_DISKPROMPT, MSISOURCETYPE_URL */
1858     r = pMsiSourceListSetInfoA(prodcode, NULL,
1859                                MSIINSTALLCONTEXT_USERUNMANAGED,
1860                                MSICODE_PRODUCT | MSISOURCETYPE_URL,
1861                                INSTALLPROPERTY_DISKPROMPT, "prompt");
1862     ok(r == ERROR_INVALID_PARAMETER,
1863        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1864
1865     /* INSTALLPROPERTY_LASTUSEDSOURCE */
1866     r = pMsiSourceListSetInfoA(prodcode, NULL,
1867                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1868                                INSTALLPROPERTY_LASTUSEDSOURCE, "source");
1869     ok(r == ERROR_INVALID_PARAMETER,
1870        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1871
1872     /* INSTALLPROPERTY_LASTUSEDSOURCE, MSISOURCETYPE_NETWORK */
1873     r = pMsiSourceListSetInfoA(prodcode, NULL,
1874                                MSIINSTALLCONTEXT_USERUNMANAGED,
1875                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1876                                INSTALLPROPERTY_LASTUSEDSOURCE, "source");
1877     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1878
1879     /* Net key is created by MsiSourceListSetInfo */
1880     res = RegOpenKeyA(source, "Net", &net);
1881     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1882     CHECK_REG_STR(net, "1", "source\\")
1883     CHECK_REG_STR(source, "LastUsedSource", "n;1;source");
1884
1885     /* source has forward slash */
1886     r = pMsiSourceListSetInfoA(prodcode, NULL,
1887                                MSIINSTALLCONTEXT_USERUNMANAGED,
1888                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1889                                INSTALLPROPERTY_LASTUSEDSOURCE, "source/");
1890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1891     CHECK_REG_STR(net, "1", "source\\");
1892     CHECK_REG_STR(net, "2", "source/\\");
1893     CHECK_REG_STR(source, "LastUsedSource", "n;2;source/");
1894
1895     /* INSTALLPROPERTY_LASTUSEDSOURCE, MSISOURCETYPE_URL */
1896     r = pMsiSourceListSetInfoA(prodcode, NULL,
1897                                MSIINSTALLCONTEXT_USERUNMANAGED,
1898                                MSICODE_PRODUCT | MSISOURCETYPE_URL,
1899                                INSTALLPROPERTY_LASTUSEDSOURCE, "source");
1900     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1901
1902     /* URL key is created by MsiSourceListSetInfo */
1903     res = RegOpenKeyA(source, "URL", &url);
1904     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1905     CHECK_REG_STR(url, "1", "source/");
1906     CHECK_REG_STR(source, "LastUsedSource", "u;1;source");
1907
1908     /* source has backslash */
1909     r = pMsiSourceListSetInfoA(prodcode, NULL,
1910                                MSIINSTALLCONTEXT_USERUNMANAGED,
1911                                MSICODE_PRODUCT | MSISOURCETYPE_URL,
1912                                INSTALLPROPERTY_LASTUSEDSOURCE, "source\\");
1913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1914     CHECK_REG_STR(url, "1", "source/");
1915     CHECK_REG_STR(url, "2", "source\\/");
1916     CHECK_REG_STR(source, "LastUsedSource", "u;2;source\\");
1917
1918     /* INSTALLPROPERTY_LASTUSEDSOURCE, MSISOURCETYPE_MEDIA */
1919     r = pMsiSourceListSetInfoA(prodcode, NULL,
1920                                MSIINSTALLCONTEXT_USERUNMANAGED,
1921                                MSICODE_PRODUCT | MSISOURCETYPE_MEDIA,
1922                                INSTALLPROPERTY_LASTUSEDSOURCE, "source");
1923     ok(r == ERROR_INVALID_PARAMETER,
1924        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1925
1926     /* INSTALLPROPERTY_PACKAGENAME */
1927     r = pMsiSourceListSetInfoA(prodcode, NULL,
1928                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1929                                INSTALLPROPERTY_PACKAGENAME, "name");
1930     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1931     CHECK_REG_STR(source, "PackageName", "name");
1932
1933     /* INSTALLPROPERTY_PACKAGENAME, MSISOURCETYPE_NETWORK */
1934     r = pMsiSourceListSetInfoA(prodcode, NULL,
1935                                MSIINSTALLCONTEXT_USERUNMANAGED,
1936                                MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
1937                                INSTALLPROPERTY_PACKAGENAME, "name");
1938     ok(r == ERROR_INVALID_PARAMETER,
1939        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1940
1941     /* INSTALLPROPERTY_PACKAGENAME, MSISOURCETYPE_URL */
1942     r = pMsiSourceListSetInfoA(prodcode, NULL,
1943                                MSIINSTALLCONTEXT_USERUNMANAGED,
1944                                MSICODE_PRODUCT | MSISOURCETYPE_URL,
1945                                INSTALLPROPERTY_PACKAGENAME, "name");
1946     ok(r == ERROR_INVALID_PARAMETER,
1947        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
1948
1949     /* INSTALLPROPERTY_LASTUSEDTYPE */
1950     r = pMsiSourceListSetInfoA(prodcode, NULL,
1951                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1952                                INSTALLPROPERTY_LASTUSEDTYPE, "type");
1953     ok(r == ERROR_UNKNOWN_PROPERTY,
1954        "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
1955
1956     /* definitely unknown property */
1957     r = pMsiSourceListSetInfoA(prodcode, NULL,
1958                                MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
1959                                "unknown", "val");
1960     ok(r == ERROR_UNKNOWN_PROPERTY,
1961        "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
1962
1963     RegDeleteValueA(net, "1");
1964     RegDeleteKeyA(net, "");
1965     RegCloseKey(net);
1966     RegDeleteValueA(url, "1");
1967     RegDeleteKeyA(url, "");
1968     RegCloseKey(url);
1969     RegDeleteValueA(media, "MediaPackage");
1970     RegDeleteValueA(media, "DiskPrompt");
1971     RegDeleteKeyA(media, "");
1972     RegCloseKey(media);
1973     RegDeleteValueA(source, "PackageName");
1974     RegDeleteKeyA(source, "");
1975     RegCloseKey(source);
1976     RegDeleteKeyA(userkey, "");
1977     RegCloseKey(userkey);
1978
1979     /* MSIINSTALLCONTEXT_USERMANAGED */
1980
1981     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\");
1982     lstrcatA(keypath, usersid);
1983     lstrcatA(keypath, "\\Installer\\Products\\");
1984     lstrcatA(keypath, prod_squashed);
1985
1986     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &userkey, NULL);
1987     if (res != ERROR_SUCCESS)
1988     {
1989         skip("Product key creation failed with error code %u\n", res);
1990         goto machine_tests;
1991     }
1992
1993     /* user product key exists */
1994     r = pMsiSourceListSetInfoA(prodcode, NULL,
1995                                MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
1996                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
1997     ok(r == ERROR_BAD_CONFIGURATION,
1998        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
1999
2000     res = RegCreateKeyExA(userkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
2001     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2002
2003     /* SourceList key exists, no source type */
2004     r = pMsiSourceListSetInfoA(prodcode, NULL,
2005                                MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
2006                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
2007     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2008
2009     /* Media key is created by MsiSourceListSetInfo */
2010     res = RegOpenKeyExA(source, "Media", 0, access, &media);
2011     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2012     CHECK_REG_STR(media, "MediaPackage", "path");
2013
2014     RegDeleteValueA(media, "MediaPackage");
2015     delete_key(media, "", access);
2016     RegCloseKey(media);
2017     delete_key(source, "", access);
2018     RegCloseKey(source);
2019     delete_key(userkey, "", access);
2020     RegCloseKey(userkey);
2021
2022     /* MSIINSTALLCONTEXT_MACHINE */
2023
2024 machine_tests:
2025     lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\");
2026     lstrcatA(keypath, prod_squashed);
2027
2028     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &prodkey, NULL);
2029     if (res != ERROR_SUCCESS)
2030     {
2031         skip("Product key creation failed with error code %u\n", res);
2032         LocalFree(usersid);
2033         return;
2034     }
2035
2036     /* user product key exists */
2037     r = pMsiSourceListSetInfoA(prodcode, NULL,
2038                                MSIINSTALLCONTEXT_MACHINE, MSICODE_PRODUCT,
2039                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
2040     ok(r == ERROR_BAD_CONFIGURATION,
2041        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
2042
2043     res = RegCreateKeyExA(prodkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
2044     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2045
2046     /* SourceList key exists, no source type */
2047     r = pMsiSourceListSetInfoA(prodcode, NULL,
2048                                MSIINSTALLCONTEXT_MACHINE, MSICODE_PRODUCT,
2049                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
2050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2051
2052     /* Media key is created by MsiSourceListSetInfo */
2053     res = RegOpenKeyExA(source, "Media", 0, access, &media);
2054     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2055     CHECK_REG_STR(media, "MediaPackage", "path");
2056
2057     /* szUserSid is non-NULL */
2058     r = pMsiSourceListSetInfoA(prodcode, usersid,
2059                                MSIINSTALLCONTEXT_MACHINE, MSICODE_PRODUCT,
2060                                INSTALLPROPERTY_MEDIAPACKAGEPATH, "path");
2061     ok(r == ERROR_INVALID_PARAMETER,
2062        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2063
2064     RegDeleteValueA(media, "MediaPackage");
2065     delete_key(media, "", access);
2066     RegCloseKey(media);
2067     delete_key(source, "", access);
2068     RegCloseKey(source);
2069     delete_key(prodkey, "", access);
2070     RegCloseKey(prodkey);
2071     LocalFree(usersid);
2072 }
2073
2074 static void test_MsiSourceListAddMediaDisk(void)
2075 {
2076     CHAR prodcode[MAX_PATH];
2077     CHAR prod_squashed[MAX_PATH];
2078     CHAR keypath[MAX_PATH*2];
2079     HKEY prodkey, userkey;
2080     HKEY media, source;
2081     LPSTR usersid;
2082     LONG res;
2083     UINT r;
2084     REGSAM access = KEY_ALL_ACCESS;
2085     BOOL wow64;
2086
2087     if (!pMsiSourceListAddMediaDiskA)
2088     {
2089         win_skip("MsiSourceListAddMediaDiskA is not available\n");
2090         return;
2091     }
2092
2093     create_test_guid(prodcode, prod_squashed);
2094     if (!get_user_sid(&usersid))
2095     {
2096         skip("User SID not available -> skipping MsiSourceListAddMediaDiskA tests\n");
2097         return;
2098     }
2099
2100     if (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &wow64) && wow64)
2101         access |= KEY_WOW64_64KEY;
2102
2103     /* GetLastError is not set by the function */
2104
2105     /* NULL szProductCodeOrPatchCode */
2106     r = pMsiSourceListAddMediaDiskA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2107                                     MSICODE_PRODUCT, 1, "label", "prompt");
2108     ok(r == ERROR_INVALID_PARAMETER,
2109        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2110
2111     /* empty szProductCodeOrPatchCode */
2112     r = pMsiSourceListAddMediaDiskA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2113                                     MSICODE_PRODUCT, 1, "label", "prompt");
2114     ok(r == ERROR_INVALID_PARAMETER,
2115        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2116
2117     /* garbage szProductCodeOrPatchCode */
2118     r = pMsiSourceListAddMediaDiskA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2119                                     MSICODE_PRODUCT, 1, "label", "prompt");
2120     ok(r == ERROR_INVALID_PARAMETER,
2121        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2122
2123     /* guid without brackets */
2124     r = pMsiSourceListAddMediaDiskA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA",
2125                                     usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2126                                     MSICODE_PRODUCT, 1, "label", "prompt");
2127     ok(r == ERROR_INVALID_PARAMETER,
2128        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2129
2130     /* guid with brackets */
2131     r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}",
2132                                     usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2133                                     MSICODE_PRODUCT, 1, "label", "prompt");
2134     ok(r == ERROR_UNKNOWN_PRODUCT,
2135        "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
2136
2137     /* dwOptions has MSISOURCETYPE_NETWORK */
2138     r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}",
2139                                     usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2140                                     MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
2141                                     1, "label", "prompt");
2142     ok(r == ERROR_INVALID_PARAMETER,
2143        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2144
2145     /* dwOptions has MSISOURCETYPE_URL */
2146     r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}",
2147                                     usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2148                                     MSICODE_PRODUCT | MSISOURCETYPE_URL,
2149                                     1, "label", "prompt");
2150     ok(r == ERROR_INVALID_PARAMETER,
2151        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2152
2153     /* dwOptions has MSISOURCETYPE_MEDIA */
2154     r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}",
2155                                     usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2156                                     MSICODE_PRODUCT | MSISOURCETYPE_MEDIA,
2157                                     1, "label", "prompt");
2158     ok(r == ERROR_INVALID_PARAMETER,
2159        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2160
2161     /* MSIINSTALLCONTEXT_USERUNMANAGED */
2162
2163     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
2164     lstrcatA(keypath, prod_squashed);
2165
2166     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
2167     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2168
2169     /* user product key exists */
2170     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2171                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2172                                     MSICODE_PRODUCT, 1, "label", "prompt");
2173     ok(r == ERROR_BAD_CONFIGURATION,
2174        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
2175
2176     res = RegCreateKeyA(userkey, "SourceList", &source);
2177     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2178
2179     /* SourceList key exists */
2180     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2181                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2182                                     MSICODE_PRODUCT, 1, "label", "prompt");
2183     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2184
2185     /* Media subkey is created by MsiSourceListAddMediaDisk */
2186     res = RegOpenKeyA(source, "Media", &media);
2187     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2188
2189     CHECK_REG_STR(media, "1", "label;prompt");
2190
2191     /* dwDiskId is random */
2192     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2193                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2194                                     MSICODE_PRODUCT, 42, "label42", "prompt42");
2195     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2196
2197     CHECK_REG_STR(media, "1", "label;prompt");
2198     CHECK_REG_STR(media, "42", "label42;prompt42");
2199
2200     /* dwDiskId is 0 */
2201     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2202                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2203                                     MSICODE_PRODUCT, 0, "label0", "prompt0");
2204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2205
2206     CHECK_REG_STR(media, "0", "label0;prompt0");
2207     CHECK_REG_STR(media, "1", "label;prompt");
2208     CHECK_REG_STR(media, "42", "label42;prompt42");
2209
2210     /* dwDiskId is < 0 */
2211     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2212                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2213                                     MSICODE_PRODUCT, -1, "label-1", "prompt-1");
2214     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2215
2216     CHECK_REG_STR(media, "-1", "label-1;prompt-1");
2217     CHECK_REG_STR(media, "0", "label0;prompt0");
2218     CHECK_REG_STR(media, "1", "label;prompt");
2219     CHECK_REG_STR(media, "42", "label42;prompt42");
2220
2221     /* update dwDiskId 1 */
2222     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2223                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2224                                     MSICODE_PRODUCT, 1, "newlabel", "newprompt");
2225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2226
2227     CHECK_REG_STR(media, "-1", "label-1;prompt-1");
2228     CHECK_REG_STR(media, "0", "label0;prompt0");
2229     CHECK_REG_STR(media, "1", "newlabel;newprompt");
2230     CHECK_REG_STR(media, "42", "label42;prompt42");
2231
2232     /* update dwDiskId 1, szPrompt is NULL */
2233     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2234                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2235                                     MSICODE_PRODUCT, 1, "etiqueta", NULL);
2236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2237
2238     CHECK_REG_STR(media, "-1", "label-1;prompt-1");
2239     CHECK_REG_STR(media, "0", "label0;prompt0");
2240     CHECK_REG_STR(media, "1", "etiqueta;");
2241     CHECK_REG_STR(media, "42", "label42;prompt42");
2242
2243     /* update dwDiskId 1, szPrompt is empty */
2244     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2245                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2246                                     MSICODE_PRODUCT, 1, "etikett", "");
2247     ok(r == ERROR_INVALID_PARAMETER,
2248        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2249
2250     /* update dwDiskId 1, szVolumeLabel is NULL */
2251     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2252                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2253                                     MSICODE_PRODUCT, 1, NULL, "provocar");
2254     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2255
2256     CHECK_REG_STR(media, "-1", "label-1;prompt-1");
2257     CHECK_REG_STR(media, "0", "label0;prompt0");
2258     CHECK_REG_STR(media, "1", ";provocar");
2259     CHECK_REG_STR(media, "42", "label42;prompt42");
2260
2261     /* update dwDiskId 1, szVolumeLabel is empty */
2262     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2263                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2264                                     MSICODE_PRODUCT, 1, "", "provoquer");
2265     ok(r == ERROR_INVALID_PARAMETER,
2266        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2267
2268     /* szUserSid is NULL */
2269     r = pMsiSourceListAddMediaDiskA(prodcode, NULL,
2270                                     MSIINSTALLCONTEXT_USERUNMANAGED,
2271                                     MSICODE_PRODUCT, 1, NULL, "provoquer");
2272     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2273
2274     CHECK_REG_STR(media, "-1", "label-1;prompt-1");
2275     CHECK_REG_STR(media, "0", "label0;prompt0");
2276     CHECK_REG_STR(media, "1", ";provoquer");
2277     CHECK_REG_STR(media, "42", "label42;prompt42");
2278
2279     RegDeleteValueA(media, "-1");
2280     RegDeleteValueA(media, "0");
2281     RegDeleteValueA(media, "1");
2282     RegDeleteValueA(media, "42");
2283     RegDeleteKeyA(media, "");
2284     RegCloseKey(media);
2285     RegDeleteKeyA(source, "");
2286     RegCloseKey(source);
2287     RegDeleteKeyA(userkey, "");
2288     RegCloseKey(userkey);
2289
2290     /* MSIINSTALLCONTEXT_USERMANAGED */
2291
2292     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\");
2293     lstrcatA(keypath, usersid);
2294     lstrcatA(keypath, "\\Installer\\Products\\");
2295     lstrcatA(keypath, prod_squashed);
2296
2297     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &userkey, NULL);
2298     if (res != ERROR_SUCCESS)
2299     {
2300         skip("Product key creation failed with error code %u\n", res);
2301         goto machine_tests;
2302     }
2303
2304     /* user product key exists */
2305     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2306                                     MSIINSTALLCONTEXT_USERMANAGED,
2307                                     MSICODE_PRODUCT, 1, "label", "prompt");
2308     ok(r == ERROR_BAD_CONFIGURATION,
2309        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
2310
2311     res = RegCreateKeyExA(userkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
2312     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2313
2314     /* SourceList key exists */
2315     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2316                                     MSIINSTALLCONTEXT_USERMANAGED,
2317                                     MSICODE_PRODUCT, 1, "label", "prompt");
2318     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2319
2320     /* Media subkey is created by MsiSourceListAddMediaDisk */
2321     res = RegOpenKeyExA(source, "Media", 0, access, &media);
2322     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2323
2324     CHECK_REG_STR(media, "1", "label;prompt");
2325
2326     RegDeleteValueA(media, "1");
2327     delete_key(media, "", access);
2328     RegCloseKey(media);
2329     delete_key(source, "", access);
2330     RegCloseKey(source);
2331     delete_key(userkey, "", access);
2332     RegCloseKey(userkey);
2333
2334     /* MSIINSTALLCONTEXT_MACHINE */
2335
2336 machine_tests:
2337     lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\");
2338     lstrcatA(keypath, prod_squashed);
2339
2340     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &prodkey, NULL);
2341     if (res != ERROR_SUCCESS)
2342     {
2343         skip("Product key creation failed with error code %u\n", res);
2344         LocalFree(usersid);
2345         return;
2346     }
2347
2348     /* machine product key exists */
2349     r = pMsiSourceListAddMediaDiskA(prodcode, NULL,
2350                                     MSIINSTALLCONTEXT_MACHINE,
2351                                     MSICODE_PRODUCT, 1, "label", "prompt");
2352     ok(r == ERROR_BAD_CONFIGURATION,
2353        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
2354
2355     res = RegCreateKeyExA(prodkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
2356     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2357
2358     /* SourceList key exists */
2359     r = pMsiSourceListAddMediaDiskA(prodcode, NULL,
2360                                     MSIINSTALLCONTEXT_MACHINE,
2361                                     MSICODE_PRODUCT, 1, "label", "prompt");
2362     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2363
2364     /* Media subkey is created by MsiSourceListAddMediaDisk */
2365     res = RegOpenKeyExA(source, "Media", 0, access, &media);
2366     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2367
2368     CHECK_REG_STR(media, "1", "label;prompt");
2369
2370     /* szUserSid is non-NULL */
2371     r = pMsiSourceListAddMediaDiskA(prodcode, usersid,
2372                                     MSIINSTALLCONTEXT_MACHINE,
2373                                     MSICODE_PRODUCT, 1, "label", "prompt");
2374     ok(r == ERROR_INVALID_PARAMETER,
2375        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2376
2377     RegDeleteValueA(media, "1");
2378     delete_key(media, "", access);
2379     RegCloseKey(media);
2380     delete_key(source, "", access);
2381     RegCloseKey(source);
2382     delete_key(prodkey, "", access);
2383     RegCloseKey(prodkey);
2384     LocalFree(usersid);
2385 }
2386
2387 static void test_MsiSourceListEnumMediaDisks(void)
2388 {
2389     CHAR prodcode[MAX_PATH];
2390     CHAR prod_squashed[MAX_PATH];
2391     CHAR keypath[MAX_PATH*2];
2392     CHAR label[MAX_PATH];
2393     CHAR prompt[MAX_PATH];
2394     HKEY prodkey, userkey, media, source;
2395     DWORD labelsz, promptsz, val, id;
2396     LPSTR usersid;
2397     LONG res;
2398     UINT r;
2399     REGSAM access = KEY_ALL_ACCESS;
2400     BOOL wow64;
2401
2402     if (!pMsiSourceListEnumMediaDisksA)
2403     {
2404         win_skip("MsiSourceListEnumMediaDisksA is not available\n");
2405         return;
2406     }
2407
2408     create_test_guid(prodcode, prod_squashed);
2409     if (!get_user_sid(&usersid))
2410     {
2411         skip("User SID not available -> skipping MsiSourceListEnumMediaDisksA tests\n");
2412         return;
2413     }
2414
2415     if (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &wow64) && wow64)
2416         access |= KEY_WOW64_64KEY;
2417
2418     /* GetLastError is not set by the function */
2419
2420     /* NULL szProductCodeOrPatchCode */
2421     labelsz = sizeof(label);
2422     promptsz = sizeof(prompt);
2423     r = pMsiSourceListEnumMediaDisksA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2424                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2425                                       prompt, &promptsz);
2426     ok(r == ERROR_INVALID_PARAMETER,
2427        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2428
2429     /* empty szProductCodeOrPatchCode */
2430     labelsz = sizeof(label);
2431     promptsz = sizeof(prompt);
2432     r = pMsiSourceListEnumMediaDisksA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2433                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2434                                       prompt, &promptsz);
2435     ok(r == ERROR_INVALID_PARAMETER,
2436        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2437
2438     /* garbage szProductCodeOrPatchCode */
2439     labelsz = sizeof(label);
2440     promptsz = sizeof(prompt);
2441     r = pMsiSourceListEnumMediaDisksA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2442                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2443                                       prompt, &promptsz);
2444     ok(r == ERROR_INVALID_PARAMETER,
2445        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2446
2447     /* guid without brackets */
2448     labelsz = sizeof(label);
2449     promptsz = sizeof(prompt);
2450     r = pMsiSourceListEnumMediaDisksA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA",
2451                                       usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2452                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2453                                       prompt, &promptsz);
2454     ok(r == ERROR_INVALID_PARAMETER,
2455        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2456
2457     /* guid with brackets */
2458     labelsz = sizeof(label);
2459     promptsz = sizeof(prompt);
2460     r = pMsiSourceListEnumMediaDisksA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}",
2461                                       usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2462                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2463                                       prompt, &promptsz);
2464     ok(r == ERROR_UNKNOWN_PRODUCT,
2465        "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
2466
2467     /* dwOptions has MSISOURCETYPE_NETWORK */
2468     labelsz = sizeof(label);
2469     promptsz = sizeof(prompt);
2470     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2471                                       MSICODE_PRODUCT | MSISOURCETYPE_NETWORK,
2472                                       0, &id, label, &labelsz,
2473                                       prompt, &promptsz);
2474     ok(r == ERROR_INVALID_PARAMETER,
2475        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2476
2477     /* dwOptions has MSISOURCETYPE_URL */
2478     labelsz = sizeof(label);
2479     promptsz = sizeof(prompt);
2480     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2481                                       MSICODE_PRODUCT | MSISOURCETYPE_URL,
2482                                       0, &id, label, &labelsz,
2483                                       prompt, &promptsz);
2484     ok(r == ERROR_INVALID_PARAMETER,
2485        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2486
2487     /* dwIndex is non-zero */
2488     labelsz = sizeof(label);
2489     promptsz = sizeof(prompt);
2490     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2491                                       MSICODE_PRODUCT, 1, &id, label, &labelsz,
2492                                       prompt, &promptsz);
2493     ok(r == ERROR_INVALID_PARAMETER,
2494        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2495
2496     /* MSIINSTALLCONTEXT_USERUNMANAGED */
2497
2498     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
2499     lstrcatA(keypath, prod_squashed);
2500
2501     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
2502     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2503
2504     /* user product key exists */
2505     labelsz = sizeof(label);
2506     promptsz = sizeof(prompt);
2507     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2508                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2509                                       prompt, &promptsz);
2510     ok(r == ERROR_BAD_CONFIGURATION,
2511        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
2512
2513     res = RegCreateKeyA(userkey, "SourceList", &source);
2514     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2515
2516     /* SourceList key exists */
2517     id = 0xbeef;
2518     lstrcpyA(label, "aaa");
2519     labelsz = 0xdeadbeef;
2520     lstrcpyA(prompt, "bbb");
2521     promptsz = 0xdeadbeef;
2522     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2523                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2524                                       prompt, &promptsz);
2525     ok(r == ERROR_NO_MORE_ITEMS,
2526        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2527     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
2528     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2529     ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz);
2530     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2531     ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz);
2532
2533     res = RegCreateKeyA(source, "Media", &media);
2534     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2535
2536     /* Media key exists */
2537     id = 0xbeef;
2538     lstrcpyA(label, "aaa");
2539     labelsz = 0xdeadbeef;
2540     lstrcpyA(prompt, "bbb");
2541     promptsz = 0xdeadbeef;
2542     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2543                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2544                                       prompt, &promptsz);
2545     ok(r == ERROR_NO_MORE_ITEMS,
2546        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2547     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
2548     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2549     ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz);
2550     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2551     ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz);
2552
2553     res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)"label;prompt", 13);
2554     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2555
2556     /* disk exists */
2557     id = 0;
2558     lstrcpyA(label, "aaa");
2559     labelsz = MAX_PATH;
2560     lstrcpyA(prompt, "bbb");
2561     promptsz = MAX_PATH;
2562     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2563                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2564                                       prompt, &promptsz);
2565     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2566     ok(id == 1, "Expected 1, got %d\n", id);
2567     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2568     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2569     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2570     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2571
2572     res = RegSetValueExA(media, "2", 0, REG_SZ, (LPBYTE)"one;two", 8);
2573     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2574
2575     /* now disk 2 exists, get the sizes */
2576     id = 0;
2577     labelsz = MAX_PATH;
2578     promptsz = MAX_PATH;
2579     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2580                                       MSICODE_PRODUCT, 1, &id, NULL, &labelsz,
2581                                       NULL, &promptsz);
2582     ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER,
2583       "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r);
2584     if (r == ERROR_SUCCESS)
2585     {
2586         ok(id == 2, "Expected 2, got %d\n", id);
2587         ok(labelsz == 3, "Expected 3, got %d\n", labelsz);
2588         ok(promptsz == 3, "Expected 3, got %d\n", promptsz);
2589     }
2590
2591     /* now fill in the values */
2592     id = 0xbeef;
2593     lstrcpyA(label, "aaa");
2594     labelsz = MAX_PATH;
2595     lstrcpyA(prompt, "bbb");
2596     promptsz = MAX_PATH;
2597     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2598                                       MSICODE_PRODUCT, 1, &id, label, &labelsz,
2599                                       prompt, &promptsz);
2600     ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER,
2601        "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r);
2602     if (r == ERROR_SUCCESS)
2603     {
2604         ok(id == 2, "Expected 2, got %d\n", id);
2605         ok(!lstrcmpA(label, "one"), "Expected \"one\", got \"%s\"\n", label);
2606         ok(labelsz == 3, "Expected 3, got %d\n", labelsz);
2607         ok(!lstrcmpA(prompt, "two"), "Expected \"two\", got \"%s\"\n", prompt);
2608         ok(promptsz == 3, "Expected 3, got %d\n", promptsz);
2609     }
2610     else if (r == ERROR_INVALID_PARAMETER)
2611     {
2612         ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
2613         ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2614         ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz);
2615         ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2616         ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz);
2617     }
2618
2619     res = RegSetValueExA(media, "4", 0, REG_SZ, (LPBYTE)"three;four", 11);
2620     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2621
2622     /* disks 1, 2, 4 exist, reset the enumeration */
2623     id = 0;
2624     lstrcpyA(label, "aaa");
2625     labelsz = MAX_PATH;
2626     lstrcpyA(prompt, "bbb");
2627     promptsz = MAX_PATH;
2628     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2629                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2630                                       prompt, &promptsz);
2631     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2632     ok(id == 1, "Expected 1, got %d\n", id);
2633     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2634     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2635     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2636     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2637
2638     /* disks 1, 2, 4 exist, index 1 */
2639     id = 0;
2640     lstrcpyA(label, "aaa");
2641     labelsz = MAX_PATH;
2642     lstrcpyA(prompt, "bbb");
2643     promptsz = MAX_PATH;
2644     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2645                                       MSICODE_PRODUCT, 1, &id, label, &labelsz,
2646                                       prompt, &promptsz);
2647     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2648     ok(id == 2, "Expected 2, got %d\n", id);
2649     ok(!lstrcmpA(label, "one"), "Expected \"one\", got \"%s\"\n", label);
2650     ok(labelsz == 3, "Expected 3, got %d\n", labelsz);
2651     ok(!lstrcmpA(prompt, "two"), "Expected \"two\", got \"%s\"\n", prompt);
2652     ok(promptsz == 3, "Expected 3, got %d\n", promptsz);
2653
2654     /* disks 1, 2, 4 exist, index 2 */
2655     id = 0;
2656     lstrcpyA(label, "aaa");
2657     labelsz = MAX_PATH;
2658     lstrcpyA(prompt, "bbb");
2659     promptsz = MAX_PATH;
2660     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2661                                       MSICODE_PRODUCT, 2, &id, label, &labelsz,
2662                                       prompt, &promptsz);
2663     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2664     ok(id == 4, "Expected 4, got %d\n", id);
2665     ok(!lstrcmpA(label, "three"), "Expected \"three\", got \"%s\"\n", label);
2666     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2667     ok(!lstrcmpA(prompt, "four"), "Expected \"four\", got \"%s\"\n", prompt);
2668     ok(promptsz == 4, "Expected 4, got %d\n", promptsz);
2669
2670     /* disks 1, 2, 4 exist, index 3, invalid */
2671     id = 0xbeef;
2672     lstrcpyA(label, "aaa");
2673     labelsz = MAX_PATH;
2674     lstrcpyA(prompt, "bbb");
2675     promptsz = MAX_PATH;
2676     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2677                                       MSICODE_PRODUCT, 3, &id, label, &labelsz,
2678                                       prompt, &promptsz);
2679     ok(r == ERROR_NO_MORE_ITEMS,
2680        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2681     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
2682     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2683     ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz);
2684     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2685     ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz);
2686
2687     /* disks 1, 2, 4 exist, reset the enumeration */
2688     id = 0;
2689     lstrcpyA(label, "aaa");
2690     labelsz = MAX_PATH;
2691     lstrcpyA(prompt, "bbb");
2692     promptsz = MAX_PATH;
2693     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2694                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2695                                       prompt, &promptsz);
2696     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2697     ok(id == 1, "Expected 1, got %d\n", id);
2698     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2699     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2700     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2701     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2702
2703     /* try index 0 again */
2704     id = 0;
2705     lstrcpyA(label, "aaa");
2706     labelsz = MAX_PATH;
2707     lstrcpyA(prompt, "bbb");
2708     promptsz = MAX_PATH;
2709     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2710                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2711                                       prompt, &promptsz);
2712     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2713     ok(id == 1, "Expected 1, got %d\n", id);
2714     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2715     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2716     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2717     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2718
2719     /* jump to index 2 */
2720     id = 0xbeef;
2721     lstrcpyA(label, "aaa");
2722     labelsz = MAX_PATH;
2723     lstrcpyA(prompt, "bbb");
2724     promptsz = MAX_PATH;
2725     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2726                                       MSICODE_PRODUCT, 2, &id, label, &labelsz,
2727                                       prompt, &promptsz);
2728     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2729     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
2730     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2731     ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz);
2732     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2733     ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz);
2734
2735     /* after error, try index 1 */
2736     id = 0xbeef;
2737     lstrcpyA(label, "aaa");
2738     labelsz = MAX_PATH;
2739     lstrcpyA(prompt, "bbb");
2740     promptsz = MAX_PATH;
2741     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2742                                       MSICODE_PRODUCT, 1, &id, label, &labelsz,
2743                                       prompt, &promptsz);
2744     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2745     ok(id == 2, "Expected 2, got %d\n", id);
2746     ok(!lstrcmpA(label, "one"), "Expected \"one\", got \"%s\"\n", label);
2747     ok(labelsz == 3, "Expected 3, got %d\n", labelsz);
2748     ok(!lstrcmpA(prompt, "two"), "Expected \"two\", got \"%s\"\n", prompt);
2749     ok(promptsz == 3, "Expected 3, got %d\n", promptsz);
2750
2751     /* try index 1 again */
2752     id = 0xbeef;
2753     lstrcpyA(label, "aaa");
2754     labelsz = MAX_PATH;
2755     lstrcpyA(prompt, "bbb");
2756     promptsz = MAX_PATH;
2757     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2758                                       MSICODE_PRODUCT, 1, &id, label, &labelsz,
2759                                       prompt, &promptsz);
2760     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2761     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
2762     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2763     ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz);
2764     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2765     ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz);
2766
2767     /* NULL pdwDiskId */
2768     lstrcpyA(label, "aaa");
2769     labelsz = MAX_PATH;
2770     lstrcpyA(prompt, "bbb");
2771     promptsz = MAX_PATH;
2772     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2773                                       MSICODE_PRODUCT, 0, NULL, label, &labelsz,
2774                                       prompt, &promptsz);
2775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2776     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2777     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2778     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2779     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2780
2781     /* szVolumeLabel is NULL */
2782     id = 0;
2783     labelsz = MAX_PATH;
2784     lstrcpyA(prompt, "bbb");
2785     promptsz = MAX_PATH;
2786     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2787                                       MSICODE_PRODUCT, 0, &id, NULL, &labelsz,
2788                                       prompt, &promptsz);
2789     ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER,
2790       "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r);
2791     if (r == ERROR_SUCCESS)
2792     {
2793         ok(id == 1, "Expected 1, got %d\n", id);
2794         ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2795         ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2796         ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2797     }
2798
2799     /* szVolumeLabel and pcchVolumeLabel are NULL */
2800     id = 0;
2801     lstrcpyA(prompt, "bbb");
2802     promptsz = MAX_PATH;
2803     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2804                                       MSICODE_PRODUCT, 0, &id, NULL, NULL,
2805                                       prompt, &promptsz);
2806     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2807     ok(id == 1, "Expected 1, got %d\n", id);
2808     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2809     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2810
2811     /* szVolumeLabel is non-NULL while pcchVolumeLabel is NULL */
2812     id = 0xbeef;
2813     lstrcpyA(label, "aaa");
2814     lstrcpyA(prompt, "bbb");
2815     promptsz = MAX_PATH;
2816     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2817                                       MSICODE_PRODUCT, 0, &id, label, NULL,
2818                                       prompt, &promptsz);
2819     ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER,
2820       "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r);
2821     if (r == ERROR_SUCCESS)
2822     {
2823         ok(id == 1, "Expected 1, got %d\n", id);
2824         ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2825         ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2826         ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2827     }
2828
2829     /* szDiskPrompt is NULL */
2830     id = 0;
2831     lstrcpyA(label, "aaa");
2832     labelsz = MAX_PATH;
2833     promptsz = MAX_PATH;
2834     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2835                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2836                                       NULL, &promptsz);
2837     ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER, "Expected ERROR_SUCCESS, got %d\n", r);
2838     if (r == ERROR_SUCCESS)
2839     {
2840         ok(id == 1, "Expected 1, got %d\n", id);
2841         ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2842         ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2843         ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2844     }
2845
2846     /* szDiskPrompt and pcchDiskPrompt are NULL */
2847     id = 0;
2848     lstrcpyA(label, "aaa");
2849     labelsz = MAX_PATH;
2850     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2851                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2852                                       NULL, NULL);
2853     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2854     ok(id == 1, "Expected 1, got %d\n", id);
2855     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2856     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2857
2858     /* szDiskPrompt is non-NULL while pcchDiskPrompt is NULL */
2859     id = 0xbeef;
2860     lstrcpyA(label, "aaa");
2861     labelsz = MAX_PATH;
2862     lstrcpyA(prompt, "bbb");
2863     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2864                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2865                                       prompt, NULL);
2866     ok(r == ERROR_INVALID_PARAMETER,
2867        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2868     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
2869     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2870     ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz);
2871     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2872
2873     /* pcchVolumeLabel is exactly 5 */
2874     lstrcpyA(label, "aaa");
2875     labelsz = 5;
2876     lstrcpyA(prompt, "bbb");
2877     promptsz = MAX_PATH;
2878     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2879                                       MSICODE_PRODUCT, 0, NULL, label, &labelsz,
2880                                       prompt, &promptsz);
2881     ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r);
2882     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2883     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2884     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2885     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2886
2887     /* pcchDiskPrompt is exactly 6 */
2888     lstrcpyA(label, "aaa");
2889     labelsz = MAX_PATH;
2890     lstrcpyA(prompt, "bbb");
2891     promptsz = 6;
2892     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2893                                       MSICODE_PRODUCT, 0, NULL, label, &labelsz,
2894                                       prompt, &promptsz);
2895     ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r);
2896     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
2897     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2898     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
2899     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2900
2901     res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)"label", 13);
2902     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2903
2904     /* no semicolon */
2905     id = 0;
2906     lstrcpyA(label, "aaa");
2907     labelsz = MAX_PATH;
2908     lstrcpyA(prompt, "bbb");
2909     promptsz = MAX_PATH;
2910     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2911                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2912                                       prompt, &promptsz);
2913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2914     ok(id == 1, "Expected 1, got %d\n", id);
2915     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2916     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2917     ok(!lstrcmpA(prompt, "label"), "Expected \"label\", got \"%s\"\n", prompt);
2918     ok(promptsz == 5, "Expected 5, got %d\n", promptsz);
2919
2920     res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)"label;", 13);
2921     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2922
2923     /* semicolon, no disk prompt */
2924     id = 0;
2925     lstrcpyA(label, "aaa");
2926     labelsz = MAX_PATH;
2927     lstrcpyA(prompt, "bbb");
2928     promptsz = MAX_PATH;
2929     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2930                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2931                                       prompt, &promptsz);
2932     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2933     ok(id == 1, "Expected 1, got %d\n", id);
2934     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
2935     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
2936     ok(!lstrcmpA(prompt, ""), "Expected \"\", got \"%s\"\n", prompt);
2937     ok(promptsz == 0, "Expected 0, got %d\n", promptsz);
2938
2939     res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)";prompt", 13);
2940     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2941
2942     /* semicolon, label doesn't exist */
2943     id = 0;
2944     lstrcpyA(label, "aaa");
2945     labelsz = MAX_PATH;
2946     lstrcpyA(prompt, "bbb");
2947     promptsz = MAX_PATH;
2948     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2949                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2950                                       prompt, &promptsz);
2951     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2952     ok(id == 1, "Expected 1, got %d\n", id);
2953     ok(!lstrcmpA(label, ""), "Expected \"\", got \"%s\"\n", label);
2954     ok(labelsz == 0, "Expected 0, got %d\n", labelsz);
2955     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
2956     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
2957
2958     res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)";", 13);
2959     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2960
2961     /* semicolon, neither label nor disk prompt exist */
2962     id = 0;
2963     lstrcpyA(label, "aaa");
2964     labelsz = MAX_PATH;
2965     lstrcpyA(prompt, "bbb");
2966     promptsz = MAX_PATH;
2967     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2968                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2969                                       prompt, &promptsz);
2970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2971     ok(id == 1, "Expected 1, got %d\n", id);
2972     ok(!lstrcmpA(label, ""), "Expected \"\", got \"%s\"\n", label);
2973     ok(labelsz == 0, "Expected 0, got %d\n", labelsz);
2974     ok(!lstrcmpA(prompt, ""), "Expected \"\", got \"%s\"\n", prompt);
2975     ok(promptsz == 0, "Expected 0, got %d\n", promptsz);
2976
2977     val = 42;
2978     res = RegSetValueExA(media, "1", 0, REG_DWORD, (LPBYTE)&val, sizeof(DWORD));
2979     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2980
2981     /* type is REG_DWORD */
2982     id = 0;
2983     lstrcpyA(label, "aaa");
2984     labelsz = MAX_PATH;
2985     lstrcpyA(prompt, "bbb");
2986     promptsz = MAX_PATH;
2987     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
2988                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
2989                                       prompt, &promptsz);
2990     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2991     ok(id == 1, "Expected 1, got %d\n", id);
2992     ok(!lstrcmpA(label, "#42"), "Expected \"#42\", got \"%s\"\n", label);
2993     ok(labelsz == 3, "Expected 3, got %d\n", labelsz);
2994     ok(!lstrcmpA(prompt, "#42"), "Expected \"#42\", got \"%s\"\n", prompt);
2995     ok(promptsz == 3, "Expected 3, got %d\n", promptsz);
2996
2997     RegDeleteValueA(media, "1");
2998     RegDeleteValueA(media, "2");
2999     RegDeleteValueA(media, "4");
3000     RegDeleteKeyA(media, "");
3001     RegCloseKey(media);
3002     RegDeleteKeyA(source, "");
3003     RegCloseKey(source);
3004     RegDeleteKeyA(userkey, "");
3005     RegCloseKey(userkey);
3006
3007     /* MSIINSTALLCONTEXT_USERMANAGED */
3008
3009     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\");
3010     lstrcatA(keypath, usersid);
3011     lstrcatA(keypath, "\\Installer\\Products\\");
3012     lstrcatA(keypath, prod_squashed);
3013
3014     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &userkey, NULL);
3015     if (res != ERROR_SUCCESS)
3016     {
3017         skip("Product key creation failed with error code %u\n", res);
3018         goto machine_tests;
3019     }
3020
3021     /* user product key exists */
3022     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED,
3023                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3024                                       prompt, &promptsz);
3025     ok(r == ERROR_BAD_CONFIGURATION,
3026        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
3027
3028     res = RegCreateKeyExA(userkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
3029     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3030
3031     /* SourceList key exists */
3032     id = 0xbeef;
3033     lstrcpyA(label, "aaa");
3034     labelsz = 0xdeadbeef;
3035     lstrcpyA(prompt, "bbb");
3036     promptsz = 0xdeadbeef;
3037     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED,
3038                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3039                                       prompt, &promptsz);
3040     ok(r == ERROR_NO_MORE_ITEMS,
3041        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3042     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
3043     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
3044     ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz);
3045     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
3046     ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz);
3047
3048     res = RegCreateKeyExA(source, "Media", 0, NULL, 0, access, NULL, &media, NULL);
3049     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3050
3051     /* Media key exists */
3052     id = 0xbeef;
3053     lstrcpyA(label, "aaa");
3054     labelsz = 0xdeadbeef;
3055     lstrcpyA(prompt, "bbb");
3056     promptsz = 0xdeadbeef;
3057     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED,
3058                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3059                                       prompt, &promptsz);
3060     ok(r == ERROR_NO_MORE_ITEMS,
3061        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3062     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
3063     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
3064     ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz);
3065     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
3066     ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz);
3067
3068     res = RegSetValueExA(media, "2", 0, REG_SZ, (LPBYTE)"label;prompt", 13);
3069     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3070
3071     /* disk exists, but no id 1 */
3072     id = 0;
3073     lstrcpyA(label, "aaa");
3074     labelsz = MAX_PATH;
3075     lstrcpyA(prompt, "bbb");
3076     promptsz = MAX_PATH;
3077     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED,
3078                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3079                                       prompt, &promptsz);
3080     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3081     ok(id == 2, "Expected 2, got %d\n", id);
3082     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
3083     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
3084     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
3085     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
3086
3087     RegDeleteValueA(media, "2");
3088     delete_key(media, "", access);
3089     RegCloseKey(media);
3090     delete_key(source, "", access);
3091     RegCloseKey(source);
3092     delete_key(userkey, "", access);
3093     RegCloseKey(userkey);
3094
3095     /* MSIINSTALLCONTEXT_MACHINE */
3096
3097 machine_tests:
3098     lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\");
3099     lstrcatA(keypath, prod_squashed);
3100
3101     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &prodkey, NULL);
3102     if (res != ERROR_SUCCESS)
3103     {
3104         skip("Product key creation failed with error code %u\n", res);
3105         LocalFree(usersid);
3106         return;
3107     }
3108
3109     /* machine product key exists */
3110     r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE,
3111                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3112                                       prompt, &promptsz);
3113     ok(r == ERROR_BAD_CONFIGURATION,
3114        "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
3115
3116     res = RegCreateKeyExA(prodkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
3117     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3118
3119     /* SourceList key exists */
3120     id = 0xbeef;
3121     lstrcpyA(label, "aaa");
3122     labelsz = 0xdeadbeef;
3123     lstrcpyA(prompt, "bbb");
3124     promptsz = 0xdeadbeef;
3125     r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE,
3126                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3127                                       prompt, &promptsz);
3128     ok(r == ERROR_NO_MORE_ITEMS,
3129        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3130     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
3131     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
3132     ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz);
3133     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
3134     ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz);
3135
3136     res = RegCreateKeyExA(source, "Media", 0, NULL, 0, access, NULL, &media, NULL);
3137     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3138
3139     /* Media key exists */
3140     id = 0xbeef;
3141     lstrcpyA(label, "aaa");
3142     labelsz = 0xdeadbeef;
3143     lstrcpyA(prompt, "bbb");
3144     promptsz = 0xdeadbeef;
3145     r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE,
3146                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3147                                       prompt, &promptsz);
3148     ok(r == ERROR_NO_MORE_ITEMS,
3149        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3150     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
3151     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
3152     ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz);
3153     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
3154     ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz);
3155
3156     res = RegSetValueExA(media, "2", 0, REG_SZ, (LPBYTE)"label;prompt", 13);
3157     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3158
3159     /* disk exists, but no id 1 */
3160     id = 0;
3161     lstrcpyA(label, "aaa");
3162     labelsz = MAX_PATH;
3163     lstrcpyA(prompt, "bbb");
3164     promptsz = MAX_PATH;
3165     r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE,
3166                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3167                                       prompt, &promptsz);
3168     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3169     ok(id == 2, "Expected 2, got %d\n", id);
3170     ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label);
3171     ok(labelsz == 5, "Expected 5, got %d\n", labelsz);
3172     ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt);
3173     ok(promptsz == 6, "Expected 6, got %d\n", promptsz);
3174
3175     /* szUserSid is non-NULL */
3176     id = 0xbeef;
3177     lstrcpyA(label, "aaa");
3178     labelsz = MAX_PATH;
3179     lstrcpyA(prompt, "bbb");
3180     promptsz = MAX_PATH;
3181     r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_MACHINE,
3182                                       MSICODE_PRODUCT, 0, &id, label, &labelsz,
3183                                       prompt, &promptsz);
3184     ok(r == ERROR_INVALID_PARAMETER,
3185        "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3186     ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id);
3187     ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label);
3188     ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz);
3189     ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt);
3190     ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz);
3191
3192     RegDeleteValueA(media, "2");
3193     delete_key(media, "", access);
3194     RegCloseKey(media);
3195     delete_key(source, "", access);
3196     RegCloseKey(source);
3197     delete_key(prodkey, "", access);
3198     RegCloseKey(prodkey);
3199     LocalFree(usersid);
3200 }
3201
3202 static void test_MsiSourceListAddSource(void)
3203 {
3204     CHAR prodcode[MAX_PATH];
3205     CHAR prod_squashed[MAX_PATH];
3206     CHAR keypath[MAX_PATH*2];
3207     CHAR username[MAX_PATH];
3208     LPSTR usersid, ptr;
3209     LONG res;
3210     UINT r;
3211     HKEY prodkey, userkey, net, source;
3212     DWORD size;
3213     REGSAM access = KEY_ALL_ACCESS;
3214     BOOL wow64;
3215
3216     if (!pMsiSourceListAddSourceA)
3217     {
3218         win_skip("Skipping MsiSourceListAddSourceA tests\n");
3219         return;
3220     }
3221
3222     create_test_guid(prodcode, prod_squashed);
3223     if (!get_user_sid(&usersid))
3224     {
3225         skip("User SID not available -> skipping MsiSourceListAddSourceA tests\n");
3226         return;
3227     }
3228
3229     /* MACHINENAME\username */
3230     size = MAX_PATH;
3231     if (pGetUserNameExA != NULL)
3232         pGetUserNameExA(NameSamCompatible, username, &size);
3233     else
3234     {
3235         GetComputerNameA(username, &size);
3236         lstrcatA(username, "\\");
3237         ptr = username + lstrlenA(username);
3238         size = MAX_PATH - (ptr - username);
3239         GetUserNameA(ptr, &size);
3240     }
3241     trace("username: %s\n", username);
3242
3243     if (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &wow64) && wow64)
3244         access |= KEY_WOW64_64KEY;
3245
3246     /* GetLastError is not set by the function */
3247
3248     /* NULL szProduct */
3249     r = pMsiSourceListAddSourceA(NULL, username, 0, "source");
3250     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3251
3252     /* empty szProduct */
3253     r = pMsiSourceListAddSourceA("", username, 0, "source");
3254     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3255
3256     /* garbage szProduct */
3257     r = pMsiSourceListAddSourceA("garbage", username, 0, "source");
3258     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3259
3260     /* guid without brackets */
3261     r = pMsiSourceListAddSourceA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", username, 0, "source");
3262     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3263
3264     /* guid with brackets */
3265     r = pMsiSourceListAddSourceA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", username, 0, "source");
3266     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
3267
3268     /* dwReserved is not 0 */
3269     r = pMsiSourceListAddSourceA(prodcode, username, 42, "source");
3270     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3271
3272     /* szSource is NULL */
3273     r = pMsiSourceListAddSourceA(prodcode, username, 0, NULL);
3274     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3275
3276     /* szSource is empty */
3277     r = pMsiSourceListAddSourceA(prodcode, username, 0, "");
3278     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
3279
3280     /* MSIINSTALLCONTEXT_USERMANAGED */
3281
3282     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3283     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
3284
3285     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\");
3286     lstrcatA(keypath, usersid);
3287     lstrcatA(keypath, "\\Installer\\Products\\");
3288     lstrcatA(keypath, prod_squashed);
3289
3290     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &userkey, NULL);
3291     if (res != ERROR_SUCCESS)
3292     {
3293         skip("Product key creation failed with error code %u\n", res);
3294         goto userunmanaged_tests;
3295     }
3296
3297     /* user product key exists */
3298     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3299     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
3300
3301     res = RegCreateKeyExA(userkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
3302     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3303
3304     /* SourceList key exists */
3305     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3307
3308     /* Net key is created */
3309     res = RegOpenKeyExA(source, "Net", 0, access, &net);
3310     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3311
3312     /* LastUsedSource does not exist and it is not created */
3313     res = RegQueryValueExA(source, "LastUsedSource", 0, NULL, NULL, NULL);
3314     ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
3315
3316     CHECK_REG_STR(net, "1", "source\\");
3317
3318     RegDeleteValueA(net, "1");
3319     delete_key(net, "", access);
3320     RegCloseKey(net);
3321
3322     res = RegSetValueExA(source, "LastUsedSource", 0, REG_SZ, (LPBYTE)"blah", 5);
3323     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3324
3325     /* LastUsedSource value exists */
3326     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3327     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3328
3329     /* Net key is created */
3330     res = RegOpenKeyExA(source, "Net", 0, access, &net);
3331     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3332
3333     CHECK_REG_STR(source, "LastUsedSource", "blah");
3334     CHECK_REG_STR(net, "1", "source\\");
3335
3336     RegDeleteValueA(net, "1");
3337     delete_key(net, "", access);
3338     RegCloseKey(net);
3339
3340     res = RegSetValueExA(source, "LastUsedSource", 0, REG_SZ, (LPBYTE)"5", 2);
3341     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3342
3343     /* LastUsedSource is an integer */
3344     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3345     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3346
3347     /* Net key is created */
3348     res = RegOpenKeyExA(source, "Net", 0, access, &net);
3349     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3350
3351     CHECK_REG_STR(source, "LastUsedSource", "5");
3352     CHECK_REG_STR(net, "1", "source\\");
3353
3354     /* Add a second source, has trailing backslash */
3355     r = pMsiSourceListAddSourceA(prodcode, username, 0, "another\\");
3356     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3357
3358     CHECK_REG_STR(source, "LastUsedSource", "5");
3359     CHECK_REG_STR(net, "1", "source\\");
3360     CHECK_REG_STR(net, "2", "another\\");
3361
3362     res = RegSetValueExA(source, "LastUsedSource", 0, REG_SZ, (LPBYTE)"2", 2);
3363     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3364
3365     /* LastUsedSource is in the source list */
3366     r = pMsiSourceListAddSourceA(prodcode, username, 0, "third/");
3367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3368
3369     CHECK_REG_STR(source, "LastUsedSource", "2");
3370     CHECK_REG_STR(net, "1", "source\\");
3371     CHECK_REG_STR(net, "2", "another\\");
3372     CHECK_REG_STR(net, "3", "third/\\");
3373
3374     RegDeleteValueA(net, "1");
3375     RegDeleteValueA(net, "2");
3376     RegDeleteValueA(net, "3");
3377     delete_key(net, "", access);
3378     RegCloseKey(net);
3379     delete_key(source, "", access);
3380     RegCloseKey(source);
3381     delete_key(userkey, "", access);
3382     RegCloseKey(userkey);
3383
3384     /* MSIINSTALLCONTEXT_USERUNMANAGED */
3385
3386 userunmanaged_tests:
3387     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3388     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
3389
3390     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
3391     lstrcatA(keypath, prod_squashed);
3392
3393     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
3394     if (res != ERROR_SUCCESS)
3395     {
3396         skip("Product key creation failed with error code %u\n", res);
3397         goto machine_tests;
3398     }
3399
3400     /* user product key exists */
3401     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3402     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
3403
3404     res = RegCreateKeyA(userkey, "SourceList", &source);
3405     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3406
3407     /* SourceList key exists */
3408     r = pMsiSourceListAddSourceA(prodcode, username, 0, "source");
3409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3410
3411     /* Net key is created */
3412     res = RegOpenKeyA(source, "Net", &net);
3413     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3414
3415     CHECK_REG_STR(net, "1", "source\\");
3416
3417     RegDeleteValueA(net, "1");
3418     RegDeleteKeyA(net, "");
3419     RegCloseKey(net);
3420     RegDeleteKeyA(source, "");
3421     RegCloseKey(source);
3422     RegDeleteKeyA(userkey, "");
3423     RegCloseKey(userkey);
3424
3425     /* MSIINSTALLCONTEXT_MACHINE */
3426
3427 machine_tests:
3428     r = pMsiSourceListAddSourceA(prodcode, NULL, 0, "source");
3429     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
3430
3431     lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\");
3432     lstrcatA(keypath, prod_squashed);
3433
3434     res = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &prodkey, NULL);
3435     if (res != ERROR_SUCCESS)
3436     {
3437         skip("Product key creation failed with error code %u\n", res);
3438         LocalFree(usersid);
3439         return;
3440     }
3441
3442     /* machine product key exists */
3443     r = pMsiSourceListAddSourceA(prodcode, NULL, 0, "source");
3444     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
3445
3446     res = RegCreateKeyExA(prodkey, "SourceList", 0, NULL, 0, access, NULL, &source, NULL);
3447     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3448
3449     /* SourceList key exists */
3450     r = pMsiSourceListAddSourceA(prodcode, NULL, 0, "source");
3451     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3452
3453     /* Net key is created */
3454     res = RegOpenKeyExA(source, "Net", 0, access, &net);
3455     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
3456
3457     CHECK_REG_STR(net, "1", "source\\");
3458
3459     /* empty szUserName */
3460     r = pMsiSourceListAddSourceA(prodcode, "", 0, "another");
3461     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3462
3463     CHECK_REG_STR(net, "1", "source\\");
3464     CHECK_REG_STR(net, "2", "another\\");
3465
3466     RegDeleteValueA(net, "2");
3467     RegDeleteValueA(net, "1");
3468     delete_key(net, "", access);
3469     RegCloseKey(net);
3470     delete_key(source, "", access);
3471     RegCloseKey(source);
3472     delete_key(prodkey, "", access);
3473     RegCloseKey(prodkey);
3474     LocalFree(usersid);
3475 }
3476
3477 START_TEST(source)
3478 {
3479     init_functionpointers();
3480
3481     test_MsiSourceListGetInfo();
3482     test_MsiSourceListAddSourceEx();
3483     test_MsiSourceListEnumSources();
3484     test_MsiSourceListSetInfo();
3485     test_MsiSourceListAddMediaDisk();
3486     test_MsiSourceListEnumMediaDisks();
3487     test_MsiSourceListAddSource();
3488 }