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