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