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