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