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