msi/tests: Tweaked so it does not look like things are misspelled.
[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
31 #include "wine/test.h"
32
33 static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*);
34 static UINT (WINAPI *pMsiSourceListGetInfoA)
35     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD);
36 static UINT (WINAPI *pMsiSourceListAddSourceExA)
37     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, DWORD);
38
39 static void init_functionpointers(void)
40 {
41     HMODULE hmsi = GetModuleHandleA("msi.dll");
42     HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
43
44     pMsiSourceListGetInfoA = (void*)GetProcAddress(hmsi, "MsiSourceListGetInfoA");
45     pMsiSourceListAddSourceExA = (void*)GetProcAddress(hmsi, "MsiSourceListAddSourceExA");
46     pConvertSidToStringSidA = (void*)GetProcAddress(hadvapi32, "ConvertSidToStringSidA");
47 }
48
49 /* copied from dlls/msi/registry.c */
50 static BOOL squash_guid(LPCWSTR in, LPWSTR out)
51 {
52     DWORD i,n=1;
53     GUID guid;
54
55     if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
56         return FALSE;
57
58     for(i=0; i<8; i++)
59         out[7-i] = in[n++];
60     n++;
61     for(i=0; i<4; i++)
62         out[11-i] = in[n++];
63     n++;
64     for(i=0; i<4; i++)
65         out[15-i] = in[n++];
66     n++;
67     for(i=0; i<2; i++)
68     {
69         out[17+i*2] = in[n++];
70         out[16+i*2] = in[n++];
71     }
72     n++;
73     for( ; i<8; i++)
74     {
75         out[17+i*2] = in[n++];
76         out[16+i*2] = in[n++];
77     }
78     out[32]=0;
79     return TRUE;
80 }
81
82 static void create_test_guid(LPSTR prodcode, LPSTR squashed)
83 {
84     WCHAR guidW[MAX_PATH];
85     WCHAR squashedW[MAX_PATH];
86     GUID guid;
87     HRESULT hr;
88     int size;
89
90     hr = CoCreateGuid(&guid);
91     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
92
93     size = StringFromGUID2(&guid, (LPOLESTR)guidW, MAX_PATH);
94     ok(size == 39, "Expected 39, got %d\n", hr);
95
96     WideCharToMultiByte(CP_ACP, 0, guidW, size, prodcode, MAX_PATH, NULL, NULL);
97     squash_guid(guidW, squashedW);
98     WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL);
99 }
100
101 static void get_user_sid(LPSTR *usersid)
102 {
103     HANDLE token;
104     BYTE buf[1024];
105     DWORD size;
106     PTOKEN_USER user;
107
108     OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
109     size = sizeof(buf);
110     GetTokenInformation(token, TokenUser, (void *)buf, size, &size);
111     user = (PTOKEN_USER)buf;
112     pConvertSidToStringSidA(user->User.Sid, usersid);
113 }
114
115 static void test_MsiSourceListGetInfo(void)
116 {
117     CHAR prodcode[MAX_PATH];
118     CHAR prod_squashed[MAX_PATH];
119     CHAR keypath[MAX_PATH*2];
120     CHAR value[MAX_PATH];
121     LPSTR usersid;
122     LPCSTR data;
123     LONG res;
124     UINT r;
125     HKEY userkey, hkey;
126     DWORD size;
127
128     create_test_guid(prodcode, prod_squashed);
129     get_user_sid(&usersid);
130
131     /* NULL szProductCodeOrPatchCode */
132     r = pMsiSourceListGetInfoA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
133                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
134     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
135
136     /* empty szProductCodeOrPatchCode */
137     r = pMsiSourceListGetInfoA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
138                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
139     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
140
141     /* garbage szProductCodeOrPatchCode */
142     r = pMsiSourceListGetInfoA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
143                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
144     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
145
146     /*  szProductCodeOrPatchCode */
147     r = pMsiSourceListGetInfoA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
148                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
149     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
150
151     /* guid without brackets */
152     r = pMsiSourceListGetInfoA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
153                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
154     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
155
156     /* guid with brackets */
157     r = pMsiSourceListGetInfoA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
158                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
159     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
160
161     /* same length as guid, but random */
162     r = pMsiSourceListGetInfoA("ADKD-2KSDFF2-DKK1KNFJASD9GLKWME-1I3KAD", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
163                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
164     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
165
166     /* invalid context */
167     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_NONE,
168                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
169     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
170
171     /* another invalid context */
172     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_ALLUSERMANAGED,
173                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
174     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
175
176     /* yet another invalid context */
177     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_ALL,
178                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
179     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
180
181     /* mix two valid contexts */
182     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED,
183                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
184     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
185
186     /* invalid option */
187     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
188                               4, INSTALLPROPERTY_PACKAGENAME, NULL, NULL);
189     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
190
191     /* NULL property */
192     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
193                               MSICODE_PRODUCT, NULL, NULL, NULL);
194     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
195
196     /* empty property */
197     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
198                               MSICODE_PRODUCT, "", NULL, NULL);
199     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
200
201     /* value is non-NULL while size is NULL */
202     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
203                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, NULL);
204     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
205
206     /* size is non-NULL while value is NULL */
207     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
208                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
209     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
210
211     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
212     lstrcatA(keypath, prod_squashed);
213
214     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
215     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
216
217     /* user product key exists */
218     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
219                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
220     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
221
222     res = RegCreateKeyA(userkey, "SourceList", &hkey);
223     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
224
225     /* SourceList key exists */
226     size = 0xdeadbeef;
227     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
228                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
229     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
230     ok(size == 0, "Expected 0, got %d\n", size);
231
232     data = "msitest.msi";
233     res = RegSetValueExA(hkey, "PackageName", 0, REG_SZ, (const BYTE *)data, lstrlenA(data) + 1);
234     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
235
236     /* PackageName value exists */
237     size = 0xdeadbeef;
238     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
239                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
241     ok(size == 11, "Expected 11, got %d\n", size);
242
243     /* read the value, don't change size */
244     lstrcpyA(value, "aaa");
245     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
246                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
247     ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r);
248     ok(!lstrcmpA(value, "aaa"), "Expected 'aaa', got %s\n", value);
249     ok(size == 11, "Expected 11, got %d\n", size);
250
251     /* read the value, fix size */
252     size++;
253     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
254                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
256     ok(!lstrcmpA(value, "msitest.msi"), "Expected 'msitest.msi', got %s\n", value);
257     ok(size == 11, "Expected 11, got %d\n", size);
258
259     /* empty property now that product key exists */
260     size = 0xdeadbeef;
261     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
262                               MSICODE_PRODUCT, "", NULL, &size);
263     ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
264     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
265
266     /* nonexistent property now that product key exists */
267     size = 0xdeadbeef;
268     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
269                               MSICODE_PRODUCT, "nonexistent", NULL, &size);
270     ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
271     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
272
273     data = "tester";
274     res = RegSetValueExA(hkey, "nonexistent", 0, REG_SZ, (const BYTE *)data, lstrlenA(data) + 1);
275     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
276
277     /* nonexistent property now that nonexistent value exists */
278     size = 0xdeadbeef;
279     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
280                               MSICODE_PRODUCT, "nonexistent", NULL, &size);
281     ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r);
282     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
283
284     /* invalid option now that product key exists */
285     size = 0xdeadbeef;
286     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
287                               4, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
288     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
289     ok(size == 11, "Expected 11, got %d\n", size);
290
291     RegDeleteValueA(hkey, "nonexistent");
292     RegDeleteValueA(hkey, "PackageName");
293     RegDeleteKeyA(hkey, "");
294     RegDeleteKeyA(userkey, "");
295     RegCloseKey(hkey);
296     RegCloseKey(userkey);
297
298     /* try a patch */
299     size = 0xdeadbeef;
300     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
301                               MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
302     ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r);
303     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
304
305     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Patches\\");
306     lstrcatA(keypath, prod_squashed);
307
308     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
309     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
310
311     /* patch key exists
312      * NOTE: using prodcode guid, but it really doesn't matter
313      */
314     size = 0xdeadbeef;
315     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
316                               MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
317     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
318     ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
319
320     res = RegCreateKeyA(userkey, "SourceList", &hkey);
321     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
322
323     /* SourceList key exists */
324     size = 0xdeadbeef;
325     r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
326                               MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
327     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
328     ok(size == 0, "Expected 0, got %d\n", size);
329
330     RegDeleteKeyA(hkey, "");
331     RegDeleteKeyA(userkey, "");
332     RegCloseKey(hkey);
333     RegCloseKey(userkey);
334 }
335
336 static void test_MsiSourceListAddSourceEx(void)
337 {
338     CHAR prodcode[MAX_PATH];
339     CHAR prod_squashed[MAX_PATH];
340     CHAR keypath[MAX_PATH*2];
341     CHAR value[MAX_PATH];
342     LPSTR usersid;
343     LONG res;
344     UINT r;
345     HKEY prodkey, userkey, hkey;
346     HKEY url, net;
347     DWORD size;
348
349     if (!pMsiSourceListAddSourceExA)
350     {
351         skip("Skipping MsiSourceListAddSourceEx tests\n");
352         return;
353     }
354
355     create_test_guid(prodcode, prod_squashed);
356     get_user_sid(&usersid);
357
358     /* GetLastError is not set by the function */
359
360     /* NULL szProductCodeOrPatchCode */
361     r = pMsiSourceListAddSourceExA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
362                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
363     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
364
365     /* empty szProductCodeOrPatchCode */
366     r = pMsiSourceListAddSourceExA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
367                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
368     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
369
370     /* garbage szProductCodeOrPatchCode */
371     r = pMsiSourceListAddSourceExA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED,
372                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
373     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
374
375     /* guid without brackets */
376     r = pMsiSourceListAddSourceExA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", usersid,
377                                   MSIINSTALLCONTEXT_USERUNMANAGED,
378                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
379     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
380
381     /* guid with brackets */
382     r = pMsiSourceListAddSourceExA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", usersid,
383                                   MSIINSTALLCONTEXT_USERUNMANAGED,
384                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
385     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
386
387     /* MSIINSTALLCONTEXT_USERUNMANAGED */
388
389     r = pMsiSourceListAddSourceExA(prodcode, usersid,
390                                   MSIINSTALLCONTEXT_USERUNMANAGED,
391                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
392     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
393
394     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
395     lstrcatA(keypath, prod_squashed);
396
397     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
398     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
399
400     /* user product key exists */
401     r = pMsiSourceListAddSourceExA(prodcode, usersid,
402                                   MSIINSTALLCONTEXT_USERUNMANAGED,
403                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
404     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
405
406     res = RegCreateKeyA(userkey, "SourceList", &url);
407     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
408     RegCloseKey(url);
409
410     /* SourceList key exists */
411     r = pMsiSourceListAddSourceExA(prodcode, usersid,
412                                   MSIINSTALLCONTEXT_USERUNMANAGED,
413                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
414     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
415
416     res = RegOpenKeyA(userkey, "SourceList\\URL", &url);
417     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
418
419     size = MAX_PATH;
420     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
421     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
422     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
423     ok(size == 11, "Expected 11, got %d\n", size);
424
425     /* add another source, index 0 */
426     r = pMsiSourceListAddSourceExA(prodcode, usersid,
427                                   MSIINSTALLCONTEXT_USERUNMANAGED,
428                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "another", 0);
429     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
430
431     size = MAX_PATH;
432     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
433     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
434     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
435     ok(size == 11, "Expected 11, got %d\n", size);
436
437     size = MAX_PATH;
438     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
439     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
440     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
441     ok(size == 9, "Expected 9, got %d\n", size);
442
443     /* add another source, index 1 */
444     r = pMsiSourceListAddSourceExA(prodcode, usersid,
445                                   MSIINSTALLCONTEXT_USERUNMANAGED,
446                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "third/", 1);
447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
448
449     size = MAX_PATH;
450     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
451     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
452     ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
453     ok(size == 7, "Expected 7, got %d\n", size);
454
455     size = MAX_PATH;
456     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
457     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
458     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
459     ok(size == 11, "Expected 11, got %d\n", size);
460
461     size = MAX_PATH;
462     res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
463     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
464     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
465     ok(size == 9, "Expected 9, got %d\n", size);
466
467     /* add another source, index > N */
468     r = pMsiSourceListAddSourceExA(prodcode, usersid,
469                                   MSIINSTALLCONTEXT_USERUNMANAGED,
470                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "last/", 5);
471     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
472
473     size = MAX_PATH;
474     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
475     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
476     ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
477     ok(size == 7, "Expected 7, got %d\n", size);
478
479     size = MAX_PATH;
480     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
481     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
482     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
483     ok(size == 11, "Expected 11, got %d\n", size);
484
485     size = MAX_PATH;
486     res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
487     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
488     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
489     ok(size == 9, "Expected 9, got %d\n", size);
490
491     size = MAX_PATH;
492     res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size);
493     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
494     ok(!lstrcmpA(value, "last/"), "Expected 'last/', got %s\n", value);
495     ok(size == 6, "Expected 6, got %d\n", size);
496
497     /* just MSISOURCETYPE_NETWORK */
498     r = pMsiSourceListAddSourceExA(prodcode, usersid,
499                                   MSIINSTALLCONTEXT_USERUNMANAGED,
500                                   MSISOURCETYPE_NETWORK, "source", 0);
501     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
502
503     res = RegOpenKeyA(userkey, "SourceList\\Net", &net);
504     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
505
506     size = MAX_PATH;
507     res = RegQueryValueExA(net, "1", NULL, NULL, (LPBYTE)value, &size);
508     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
509     ok(!lstrcmpA(value, "source\\"), "Expected 'source\\', got %s\n", value);
510     ok(size == 8, "Expected 8, got %d\n", size);
511
512     /* just MSISOURCETYPE_URL */
513     r = pMsiSourceListAddSourceExA(prodcode, usersid,
514                                   MSIINSTALLCONTEXT_USERUNMANAGED,
515                                   MSISOURCETYPE_URL, "source", 0);
516     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
517
518     size = MAX_PATH;
519     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
520     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
521     ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
522     ok(size == 7, "Expected 7, got %d\n", size);
523
524     size = MAX_PATH;
525     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
526     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
527     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
528     ok(size == 11, "Expected 11, got %d\n", size);
529
530     size = MAX_PATH;
531     res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
532     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
533     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
534     ok(size == 9, "Expected 9, got %d\n", size);
535
536     size = MAX_PATH;
537     res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size);
538     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
539     ok(!lstrcmpA(value, "last/"), "Expected 'last/', got %s\n", value);
540     ok(size == 6, "Expected 6, got %d\n", size);
541
542     size = MAX_PATH;
543     res = RegQueryValueExA(url, "5", NULL, NULL, (LPBYTE)value, &size);
544     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
545     ok(!lstrcmpA(value, "source/"), "Expected 'source/', got %s\n", value);
546     ok(size == 8, "Expected 8, got %d\n", size);
547
548     /* NULL szUserSid */
549     r = pMsiSourceListAddSourceExA(prodcode, NULL,
550                                   MSIINSTALLCONTEXT_USERUNMANAGED,
551                                   MSISOURCETYPE_NETWORK, "nousersid", 0);
552     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
553
554     size = MAX_PATH;
555     res = RegQueryValueExA(net, "1", NULL, NULL, (LPBYTE)value, &size);
556     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
557     ok(!lstrcmpA(value, "source\\"), "Expected 'source\\', got %s\n", value);
558     ok(size == 8, "Expected 8, got %d\n", size);
559
560     size = MAX_PATH;
561     res = RegQueryValueExA(net, "2", NULL, NULL, (LPBYTE)value, &size);
562     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
563     ok(!lstrcmpA(value, "nousersid\\"), "Expected 'nousersid\\', got %s\n", value);
564     ok(size == 11, "Expected 11, got %d\n", size);
565
566     /* invalid options, must have source type */
567     r = pMsiSourceListAddSourceExA(prodcode, usersid,
568                                   MSIINSTALLCONTEXT_USERUNMANAGED,
569                                   MSICODE_PRODUCT, "source", 0);
570     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
571
572     r = pMsiSourceListAddSourceExA(prodcode, usersid,
573                                   MSIINSTALLCONTEXT_USERUNMANAGED,
574                                   MSICODE_PATCH, "source", 0);
575     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
576
577     /* NULL szSource */
578     r = pMsiSourceListAddSourceExA(prodcode, usersid,
579                                   MSIINSTALLCONTEXT_USERUNMANAGED,
580                                   MSISOURCETYPE_URL, NULL, 1);
581     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
582
583     /* empty szSource */
584     r = pMsiSourceListAddSourceExA(prodcode, usersid,
585                                   MSIINSTALLCONTEXT_USERUNMANAGED,
586                                   MSISOURCETYPE_URL, "", 1);
587     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
588
589     /* MSIINSTALLCONTEXT_USERMANAGED, non-NULL szUserSid */
590
591     r = pMsiSourceListAddSourceExA(prodcode, usersid,
592                                   MSIINSTALLCONTEXT_USERMANAGED,
593                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
594     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
595
596     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\");
597     lstrcatA(keypath, usersid);
598     lstrcatA(keypath, "\\Installer\\Products\\");
599     lstrcatA(keypath, prod_squashed);
600
601     res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey);
602     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
603
604     /* product key exists */
605     r = pMsiSourceListAddSourceExA(prodcode, usersid,
606                                   MSIINSTALLCONTEXT_USERMANAGED,
607                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
608     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
609
610     res = RegCreateKeyA(prodkey, "SourceList", &hkey);
611     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
612     RegCloseKey(hkey);
613
614     /* SourceList exists */
615     r = pMsiSourceListAddSourceExA(prodcode, usersid,
616                                   MSIINSTALLCONTEXT_USERMANAGED,
617                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
618     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
619
620     res = RegOpenKeyA(prodkey, "SourceList\\URL", &url);
621     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
622
623     size = MAX_PATH;
624     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
625     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
626     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
627     ok(size == 11, "Expected 11, got %d\n", size);
628
629     RegCloseKey(url);
630
631     /* MSIINSTALLCONTEXT_USERMANAGED, NULL szUserSid */
632
633     r = pMsiSourceListAddSourceExA(prodcode, NULL,
634                                   MSIINSTALLCONTEXT_USERMANAGED,
635                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "another", 0);
636     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
637
638     res = RegOpenKeyA(prodkey, "SourceList\\URL", &url);
639     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
640
641     size = MAX_PATH;
642     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
643     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
644     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
645     ok(size == 11, "Expected 11, got %d\n", size);
646
647     size = MAX_PATH;
648     res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
649     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
650     ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
651     ok(size == 9, "Expected 9, got %d\n", size);
652
653     RegCloseKey(url);
654     RegCloseKey(prodkey);
655
656     /* MSIINSTALLCONTEXT_MACHINE */
657
658     /* szUserSid must be NULL for MSIINSTALLCONTEXT_MACHINE */
659     r = pMsiSourceListAddSourceExA(prodcode, usersid,
660                                   MSIINSTALLCONTEXT_MACHINE,
661                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
662     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
663
664     r = pMsiSourceListAddSourceExA(prodcode, NULL,
665                                   MSIINSTALLCONTEXT_MACHINE,
666                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
667     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
668
669     lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\");
670     lstrcatA(keypath, prod_squashed);
671
672     res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey);
673     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
674
675     /* product key exists */
676     r = pMsiSourceListAddSourceExA(prodcode, NULL,
677                                   MSIINSTALLCONTEXT_MACHINE,
678                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
679     ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r);
680
681     res = RegCreateKeyA(prodkey, "SourceList", &hkey);
682     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
683     RegCloseKey(hkey);
684
685     /* SourceList exists */
686     r = pMsiSourceListAddSourceExA(prodcode, NULL,
687                                   MSIINSTALLCONTEXT_MACHINE,
688                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, "C:\\source", 0);
689     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
690
691     res = RegOpenKeyA(prodkey, "SourceList\\URL", &url);
692     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
693
694     size = MAX_PATH;
695     res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
696     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
697     ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
698     ok(size == 11, "Expected 11, got %d\n", size);
699
700     RegCloseKey(url);
701     RegCloseKey(prodkey);
702     HeapFree(GetProcessHeap(), 0, usersid);
703 }
704
705 START_TEST(source)
706 {
707     init_functionpointers();
708
709     test_MsiSourceListGetInfo();
710     test_MsiSourceListAddSourceEx();
711 }