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