xref: /reactos/dll/win32/msi/source.c (revision 69931a4a)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Aric Stewart for CodeWeavers
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 #include <stdarg.h>
22 
23 #define COBJMACROS
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "winnls.h"
29 #include "shlwapi.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "wincrypt.h"
35 #include "winver.h"
36 #include "winuser.h"
37 #include "sddl.h"
38 
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40 
41 /*
42  * These apis are defined in MSI 3.0
43  */
44 
45 typedef struct tagMediaInfo
46 {
47     struct list entry;
48     LPWSTR  path;
49     WCHAR   szIndex[10];
50     DWORD   index;
51 } media_info;
52 
53 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
54                           MSIINSTALLCONTEXT context, BOOL create)
55 {
56     HKEY rootkey = 0;
57     UINT rc = ERROR_FUNCTION_FAILED;
58 
59     if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
60     {
61         if (dwOptions & MSICODE_PATCH)
62             rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
63         else
64             rc = MSIREG_OpenProductKey(szProduct, NULL, context,
65                                        &rootkey, create);
66     }
67     else if (context == MSIINSTALLCONTEXT_USERMANAGED)
68     {
69         if (dwOptions & MSICODE_PATCH)
70             rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
71         else
72             rc = MSIREG_OpenProductKey(szProduct, NULL, context,
73                                        &rootkey, create);
74     }
75     else if (context == MSIINSTALLCONTEXT_MACHINE)
76     {
77         if (dwOptions & MSICODE_PATCH)
78             rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
79         else
80             rc = MSIREG_OpenProductKey(szProduct, NULL, context,
81                                        &rootkey, create);
82     }
83 
84     if (rc != ERROR_SUCCESS)
85     {
86         if (dwOptions & MSICODE_PATCH)
87             return ERROR_UNKNOWN_PATCH;
88         else
89             return ERROR_UNKNOWN_PRODUCT;
90     }
91 
92     if (create)
93         rc = RegCreateKeyW(rootkey, L"SourceList", key);
94     else
95     {
96         rc = RegOpenKeyW(rootkey, L"SourceList", key);
97         if (rc != ERROR_SUCCESS)
98             rc = ERROR_BAD_CONFIGURATION;
99     }
100     RegCloseKey(rootkey);
101 
102     return rc;
103 }
104 
105 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
106 {
107     UINT rc;
108 
109     if (create)
110         rc = RegCreateKeyW(rootkey, L"Media", key);
111     else
112         rc = RegOpenKeyW(rootkey, L"Media", key);
113 
114     return rc;
115 }
116 
117 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
118 {
119     UINT rc;
120 
121     if (create)
122         rc = RegCreateKeyW(rootkey, L"Net", key);
123     else
124         rc = RegOpenKeyW(rootkey, L"Net", key);
125 
126     return rc;
127 }
128 
129 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
130 {
131     UINT rc;
132 
133     if (create)
134         rc = RegCreateKeyW(rootkey, L"URL", key);
135     else
136         rc = RegOpenKeyW(rootkey, L"URL", key);
137 
138     return rc;
139 }
140 
141 /******************************************************************
142  *  MsiSourceListEnumMediaDisksA   (MSI.@)
143  */
144 UINT WINAPI MsiSourceListEnumMediaDisksA( const char *szProductCodeOrPatchCode, const char *szUserSid,
145                                           MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex,
146                                           DWORD *pdwDiskId, char *szVolumeLabel, DWORD *pcchVolumeLabel,
147                                           char *szDiskPrompt, DWORD *pcchDiskPrompt )
148 {
149     WCHAR *product = NULL, *usersid = NULL, *volume = NULL, *prompt = NULL;
150     UINT r = ERROR_INVALID_PARAMETER;
151 
152     TRACE( "%s, %s, %d, %#lx, %lu, %p, %p, %p, %p, %p\n", debugstr_a(szProductCodeOrPatchCode),
153            debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId, szVolumeLabel, pcchVolumeLabel,
154            szDiskPrompt, pcchDiskPrompt );
155 
156     if (szDiskPrompt && !pcchDiskPrompt)
157         return ERROR_INVALID_PARAMETER;
158 
159     if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode);
160     if (szUserSid) usersid = strdupAtoW(szUserSid);
161 
162     /* FIXME: add tests for an invalid format */
163 
164     if (pcchVolumeLabel)
165         volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR));
166 
167     if (pcchDiskPrompt)
168         prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR));
169 
170     if (volume) *volume = '\0';
171     if (prompt) *prompt = '\0';
172     r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions,
173                                      dwIndex, pdwDiskId, volume, pcchVolumeLabel,
174                                      prompt, pcchDiskPrompt);
175     if (r != ERROR_SUCCESS)
176         goto done;
177 
178     if (szVolumeLabel && pcchVolumeLabel)
179         WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel,
180                             *pcchVolumeLabel + 1, NULL, NULL);
181 
182     if (szDiskPrompt)
183         WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt,
184                             *pcchDiskPrompt + 1, NULL, NULL);
185 
186 done:
187     msi_free(product);
188     msi_free(usersid);
189     msi_free(volume);
190     msi_free(prompt);
191 
192     return r;
193 }
194 
195 /******************************************************************
196  *  MsiSourceListEnumMediaDisksW   (MSI.@)
197  */
198 UINT WINAPI MsiSourceListEnumMediaDisksW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid,
199                                           MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex,
200                                           DWORD *pdwDiskId, WCHAR *szVolumeLabel, DWORD *pcchVolumeLabel,
201                                           WCHAR *szDiskPrompt, DWORD *pcchDiskPrompt )
202 {
203     WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11];
204     WCHAR *value = NULL, *data = NULL, *ptr, *ptr2;
205     HKEY source, media;
206     DWORD valuesz, datasz = 0, type, numvals, size;
207     LONG res;
208     UINT r;
209     static DWORD index = 0;
210 
211     TRACE( "%s, %s, %d, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(szProductCodeOrPatchCode),
212            debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel, pcchVolumeLabel,
213            szDiskPrompt, pcchDiskPrompt );
214 
215     if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc ))
216         return ERROR_INVALID_PARAMETER;
217 
218     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
219         return ERROR_INVALID_PARAMETER;
220 
221     if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
222         return ERROR_INVALID_PARAMETER;
223 
224     if (szDiskPrompt && !pcchDiskPrompt)
225         return ERROR_INVALID_PARAMETER;
226 
227     if (dwIndex == 0)
228         index = 0;
229 
230     if (dwIndex != index)
231         return ERROR_INVALID_PARAMETER;
232 
233     r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE);
234     if (r != ERROR_SUCCESS)
235         return r;
236 
237     r = OpenMediaSubkey(source, &media, FALSE);
238     if (r != ERROR_SUCCESS)
239     {
240         RegCloseKey(source);
241         return ERROR_NO_MORE_ITEMS;
242     }
243 
244     res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
245                            NULL, &numvals, &valuesz, &datasz, NULL, NULL);
246     if (res != ERROR_SUCCESS)
247     {
248         r = ERROR_BAD_CONFIGURATION;
249         goto done;
250     }
251 
252     value = msi_alloc(++valuesz * sizeof(WCHAR));
253     data = msi_alloc(++datasz * sizeof(WCHAR));
254     if (!value || !data)
255     {
256         r = ERROR_OUTOFMEMORY;
257         goto done;
258     }
259 
260     r = RegEnumValueW(media, dwIndex, value, &valuesz,
261                       NULL, &type, (LPBYTE)data, &datasz);
262     if (r != ERROR_SUCCESS)
263         goto done;
264 
265     if (pdwDiskId)
266         *pdwDiskId = wcstol(value, NULL, 10);
267 
268     ptr2 = data;
269     ptr = wcschr(data, ';');
270     if (!ptr)
271         ptr = data;
272     else
273         *ptr = '\0';
274 
275     if (pcchVolumeLabel)
276     {
277         if (type == REG_DWORD)
278         {
279             swprintf(convert, ARRAY_SIZE(convert), L"#%d", *data);
280             size = lstrlenW(convert);
281             ptr2 = convert;
282         }
283         else
284             size = lstrlenW(data);
285 
286         if (size >= *pcchVolumeLabel)
287             r = ERROR_MORE_DATA;
288         else if (szVolumeLabel)
289             lstrcpyW(szVolumeLabel, ptr2);
290 
291         *pcchVolumeLabel = size;
292     }
293 
294     if (pcchDiskPrompt)
295     {
296         if (!*ptr)
297             ptr++;
298 
299         if (type == REG_DWORD)
300         {
301             swprintf(convert, ARRAY_SIZE(convert), L"#%d", *ptr);
302             size = lstrlenW(convert);
303             ptr = convert;
304         }
305         else
306             size = lstrlenW(ptr);
307 
308         if (size >= *pcchDiskPrompt)
309             r = ERROR_MORE_DATA;
310         else if (szDiskPrompt)
311             lstrcpyW(szDiskPrompt, ptr);
312 
313         *pcchDiskPrompt = size;
314     }
315 
316     index++;
317 
318 done:
319     msi_free(value);
320     msi_free(data);
321     RegCloseKey(source);
322 
323     return r;
324 }
325 
326 /******************************************************************
327  *  MsiSourceListEnumSourcesA   (MSI.@)
328  */
329 UINT WINAPI MsiSourceListEnumSourcesA( const char *szProductCodeOrPatch, const char *szUserSid,
330                                        MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, char *szSource,
331                                        DWORD *pcchSource )
332 {
333     WCHAR *product = NULL, *usersid = NULL, *source = NULL;
334     DWORD len = 0;
335     UINT r = ERROR_INVALID_PARAMETER;
336     static DWORD index = 0;
337 
338     TRACE( "%s, %s, %d, %#lx, %lu, %p, %p)\n", debugstr_a(szProductCodeOrPatch), debugstr_a(szUserSid), dwContext,
339            dwOptions, dwIndex, szSource, pcchSource );
340 
341     if (dwIndex == 0)
342         index = 0;
343 
344     if (szSource && !pcchSource)
345         goto done;
346 
347     if (dwIndex != index)
348         goto done;
349 
350     if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
351     if (szUserSid) usersid = strdupAtoW(szUserSid);
352 
353     r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
354                                   dwIndex, NULL, &len);
355     if (r != ERROR_SUCCESS)
356         goto done;
357 
358     source = msi_alloc(++len * sizeof(WCHAR));
359     if (!source)
360     {
361         r = ERROR_OUTOFMEMORY;
362         goto done;
363     }
364 
365     *source = '\0';
366     r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
367                                   dwIndex, source, &len);
368     if (r != ERROR_SUCCESS)
369         goto done;
370 
371     len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
372     if (pcchSource && *pcchSource >= len)
373         WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
374     else if (szSource)
375         r = ERROR_MORE_DATA;
376 
377     if (pcchSource)
378         *pcchSource = len - 1;
379 
380 done:
381     msi_free(product);
382     msi_free(usersid);
383     msi_free(source);
384 
385     if (r == ERROR_SUCCESS)
386     {
387         if (szSource || !pcchSource) index++;
388     }
389     else if (dwIndex > index)
390         index = 0;
391 
392     return r;
393 }
394 
395 /******************************************************************
396  *  MsiSourceListEnumSourcesW   (MSI.@)
397  */
398 UINT WINAPI MsiSourceListEnumSourcesW( const WCHAR *szProductCodeOrPatch, const WCHAR *szUserSid,
399                                        MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, WCHAR *szSource,
400                                        DWORD *pcchSource )
401 {
402     WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32];
403     HKEY source = NULL, subkey = NULL;
404     LONG res;
405     UINT r = ERROR_INVALID_PARAMETER;
406     static DWORD index = 0;
407 
408     TRACE( "%s, %s, %d, %#lx, %lu, %p, %p\n", debugstr_w(szProductCodeOrPatch), debugstr_w(szUserSid), dwContext,
409            dwOptions, dwIndex, szSource, pcchSource );
410 
411     if (dwIndex == 0)
412         index = 0;
413 
414     if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc ))
415         goto done;
416 
417     if (szSource && !pcchSource)
418         goto done;
419 
420     if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
421         goto done;
422 
423     if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
424         goto done;
425 
426     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
427         goto done;
428 
429     if (dwIndex != index)
430         goto done;
431 
432     r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE );
433     if (r != ERROR_SUCCESS)
434         goto done;
435 
436     if (dwOptions & MSISOURCETYPE_NETWORK)
437         r = OpenNetworkSubkey(source, &subkey, FALSE);
438     else if (dwOptions & MSISOURCETYPE_URL)
439         r = OpenURLSubkey(source, &subkey, FALSE);
440 
441     if (r != ERROR_SUCCESS)
442     {
443         r = ERROR_NO_MORE_ITEMS;
444         goto done;
445     }
446 
447     swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex + 1);
448 
449     res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
450     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
451         r = ERROR_NO_MORE_ITEMS;
452 
453 done:
454     RegCloseKey(subkey);
455     RegCloseKey(source);
456 
457     if (r == ERROR_SUCCESS)
458     {
459         if (szSource || !pcchSource) index++;
460     }
461     else if (dwIndex > index)
462         index = 0;
463 
464     return r;
465 }
466 
467 /******************************************************************
468  *  MsiSourceListGetInfoA   (MSI.@)
469  */
470 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
471                                    MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
472                                    LPCSTR szProperty, LPSTR szValue,
473                                    LPDWORD pcchValue)
474 {
475     UINT ret;
476     LPWSTR product = NULL;
477     LPWSTR usersid = NULL;
478     LPWSTR property = NULL;
479     LPWSTR value = NULL;
480     DWORD len = 0;
481 
482     if (szValue && !pcchValue)
483         return ERROR_INVALID_PARAMETER;
484 
485     if (szProduct) product = strdupAtoW(szProduct);
486     if (szUserSid) usersid = strdupAtoW(szUserSid);
487     if (szProperty) property = strdupAtoW(szProperty);
488 
489     ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
490                                 property, NULL, &len);
491     if (ret != ERROR_SUCCESS)
492         goto done;
493 
494     value = msi_alloc(++len * sizeof(WCHAR));
495     if (!value)
496         return ERROR_OUTOFMEMORY;
497 
498     *value = '\0';
499     ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
500                                 property, value, &len);
501     if (ret != ERROR_SUCCESS)
502         goto done;
503 
504     len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
505     if (*pcchValue >= len)
506         WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
507     else if (szValue)
508         ret = ERROR_MORE_DATA;
509 
510     *pcchValue = len - 1;
511 
512 done:
513     msi_free(product);
514     msi_free(usersid);
515     msi_free(property);
516     msi_free(value);
517     return ret;
518 }
519 
520 /******************************************************************
521  *  MsiSourceListGetInfoW   (MSI.@)
522  */
523 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
524                                    MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
525                                    LPCWSTR szProperty, LPWSTR szValue,
526                                    LPDWORD pcchValue)
527 {
528     WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE];
529     HKEY sourcekey, media;
530     DWORD size;
531     UINT rc;
532 
533     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
534 
535     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
536         return ERROR_INVALID_PARAMETER;
537 
538     if (szValue && !pcchValue)
539         return ERROR_INVALID_PARAMETER;
540 
541     if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
542         dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
543         dwContext != MSIINSTALLCONTEXT_MACHINE)
544         return ERROR_INVALID_PARAMETER;
545 
546     if (!szProperty)
547         return ERROR_INVALID_PARAMETER;
548 
549     if (szUserSid)
550         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
551 
552     rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
553     if (rc != ERROR_SUCCESS)
554         return rc;
555 
556     if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
557         !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
558     {
559         rc = OpenMediaSubkey(sourcekey, &media, FALSE);
560         if (rc != ERROR_SUCCESS)
561         {
562             RegCloseKey(sourcekey);
563             return ERROR_SUCCESS;
564         }
565 
566         if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
567             szProperty = L"MediaPackage";
568 
569         RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
570         RegCloseKey(media);
571     }
572     else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
573              !wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
574     {
575         rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
576                               0, 0, NULL, &size);
577         if (rc != ERROR_SUCCESS)
578         {
579             static WCHAR szEmpty[] = L"";
580             rc = ERROR_SUCCESS;
581             source = NULL;
582             ptr = szEmpty;
583             goto output_out;
584         }
585 
586         source = msi_alloc(size);
587         RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
588                          0, 0, (LPBYTE)source, &size);
589 
590         if (!*source)
591         {
592             msi_free(source);
593             RegCloseKey(sourcekey);
594             return ERROR_SUCCESS;
595         }
596 
597         if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
598         {
599             if (*source != 'n' && *source != 'u' && *source != 'm')
600             {
601                 msi_free(source);
602                 RegCloseKey(sourcekey);
603                 return ERROR_SUCCESS;
604             }
605 
606             ptr = source;
607             source[1] = '\0';
608         }
609         else
610         {
611             ptr = wcsrchr(source, ';');
612             if (!ptr)
613                 ptr = source;
614             else
615                 ptr++;
616         }
617 output_out:
618         if (szValue)
619         {
620             if (lstrlenW(ptr) < *pcchValue)
621                 lstrcpyW(szValue, ptr);
622             else
623                 rc = ERROR_MORE_DATA;
624         }
625 
626         *pcchValue = lstrlenW(ptr);
627         msi_free(source);
628     }
629     else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
630     {
631         *pcchValue = *pcchValue * sizeof(WCHAR);
632         rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
633                               (LPBYTE)szValue, pcchValue);
634         if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
635         {
636             *pcchValue = 0;
637             rc = ERROR_SUCCESS;
638         }
639         else
640         {
641             if (*pcchValue)
642                 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
643             if (szValue)
644                 szValue[*pcchValue] = '\0';
645         }
646     }
647     else
648     {
649         FIXME("Unknown property %s\n",debugstr_w(szProperty));
650         rc = ERROR_UNKNOWN_PROPERTY;
651     }
652 
653     RegCloseKey(sourcekey);
654     return rc;
655 }
656 
657 /******************************************************************
658  *  MsiSourceListSetInfoA   (MSI.@)
659  */
660 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
661                                   MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
662                                   LPCSTR szProperty, LPCSTR szValue)
663 {
664     UINT ret;
665     LPWSTR product = NULL;
666     LPWSTR usersid = NULL;
667     LPWSTR property = NULL;
668     LPWSTR value = NULL;
669 
670     if (szProduct) product = strdupAtoW(szProduct);
671     if (szUserSid) usersid = strdupAtoW(szUserSid);
672     if (szProperty) property = strdupAtoW(szProperty);
673     if (szValue) value = strdupAtoW(szValue);
674 
675     ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
676                                 property, value);
677 
678     msi_free(product);
679     msi_free(usersid);
680     msi_free(property);
681     msi_free(value);
682 
683     return ret;
684 }
685 
686 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
687                               MSIINSTALLCONTEXT context, DWORD options,
688                               LPCWSTR value)
689 {
690     HKEY source;
691     LPWSTR buffer;
692     WCHAR typechar;
693     DWORD size;
694     UINT r;
695     int index = 1;
696 
697     if (options & MSISOURCETYPE_NETWORK)
698         typechar = 'n';
699     else if (options & MSISOURCETYPE_URL)
700         typechar = 'u';
701     else if (options & MSISOURCETYPE_MEDIA)
702         typechar = 'm';
703     else
704         return ERROR_INVALID_PARAMETER;
705 
706     if (!(options & MSISOURCETYPE_MEDIA))
707     {
708         r = MsiSourceListAddSourceExW(product, usersid, context,
709                                       options, value, 0);
710         if (r != ERROR_SUCCESS)
711             return r;
712 
713         index = 0;
714         while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
715                                               index, NULL, NULL)) == ERROR_SUCCESS)
716             index++;
717 
718         if (r != ERROR_NO_MORE_ITEMS)
719             return r;
720     }
721 
722     size = lstrlenW(L"%c;%d;%s") + lstrlenW(value) + 7;
723     buffer = msi_alloc(size * sizeof(WCHAR));
724     if (!buffer)
725         return ERROR_OUTOFMEMORY;
726 
727     r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
728     if (r != ERROR_SUCCESS)
729     {
730         msi_free(buffer);
731         return r;
732     }
733 
734     swprintf(buffer, size, L"%c;%d;%s", typechar, index, value);
735 
736     size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
737     r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
738                        REG_SZ, (LPBYTE)buffer, size);
739     msi_free(buffer);
740 
741     RegCloseKey(source);
742     return r;
743 }
744 
745 /******************************************************************
746  *  MsiSourceListSetInfoW   (MSI.@)
747  */
748 UINT WINAPI MsiSourceListSetInfoW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
749                                    DWORD dwOptions, const WCHAR *szProperty, const WCHAR *szValue )
750 {
751     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
752     HKEY sourcekey, media;
753     LPCWSTR property;
754     UINT rc;
755 
756     TRACE( "%s, %s, %d, %#lx, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
757            debugstr_w(szProperty), debugstr_w(szValue) );
758 
759     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
760         return ERROR_INVALID_PARAMETER;
761 
762     if (!szProperty)
763         return ERROR_INVALID_PARAMETER;
764 
765     if (!szValue)
766         return ERROR_UNKNOWN_PROPERTY;
767 
768     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
769         return ERROR_INVALID_PARAMETER;
770 
771     if (dwOptions & MSICODE_PATCH)
772     {
773         FIXME("Unhandled options MSICODE_PATCH\n");
774         return ERROR_UNKNOWN_PATCH;
775     }
776 
777     property = szProperty;
778     if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
779         property = L"MediaPackage";
780 
781     rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
782     if (rc != ERROR_SUCCESS)
783         return rc;
784 
785     if (wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
786         dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
787     {
788         RegCloseKey(sourcekey);
789         return ERROR_INVALID_PARAMETER;
790     }
791 
792     if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
793         !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
794     {
795         rc = OpenMediaSubkey(sourcekey, &media, TRUE);
796         if (rc == ERROR_SUCCESS)
797         {
798             rc = msi_reg_set_val_str(media, property, szValue);
799             RegCloseKey(media);
800         }
801     }
802     else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
803     {
804         DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
805         rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
806                 REG_SZ, (const BYTE *)szValue, size);
807         if (rc != ERROR_SUCCESS)
808             rc = ERROR_UNKNOWN_PROPERTY;
809     }
810     else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
811     {
812         if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
813             rc = ERROR_INVALID_PARAMETER;
814         else
815             rc = msi_set_last_used_source(szProduct, szUserSid, dwContext,
816                                           dwOptions, szValue);
817     }
818     else
819         rc = ERROR_UNKNOWN_PROPERTY;
820 
821     RegCloseKey(sourcekey);
822     return rc;
823 }
824 
825 /******************************************************************
826  *  MsiSourceListAddSourceW (MSI.@)
827  */
828 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
829         DWORD dwReserved, LPCWSTR szSource)
830 {
831     WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
832     INT ret;
833     DWORD sidsize = 0, domsize = 0, context;
834     HKEY hkey = 0;
835     UINT r;
836 
837     TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
838 
839     if (!szSource || !*szSource)
840         return ERROR_INVALID_PARAMETER;
841 
842     if (dwReserved != 0)
843         return ERROR_INVALID_PARAMETER;
844 
845     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
846         return ERROR_INVALID_PARAMETER;
847 
848     if (!szUserName || !*szUserName)
849         context = MSIINSTALLCONTEXT_MACHINE;
850     else
851     {
852         if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
853         {
854             PSID psid = msi_alloc(sidsize);
855 
856             if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
857                 ConvertSidToStringSidW(psid, &sidstr);
858 
859             msi_free(psid);
860         }
861 
862         r = MSIREG_OpenProductKey(szProduct, NULL,
863                                   MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
864         if (r == ERROR_SUCCESS)
865             context = MSIINSTALLCONTEXT_USERMANAGED;
866         else
867         {
868             r = MSIREG_OpenProductKey(szProduct, NULL,
869                                       MSIINSTALLCONTEXT_USERUNMANAGED,
870                                       &hkey, FALSE);
871             if (r != ERROR_SUCCESS)
872                 return ERROR_UNKNOWN_PRODUCT;
873 
874             context = MSIINSTALLCONTEXT_USERUNMANAGED;
875         }
876 
877         RegCloseKey(hkey);
878     }
879 
880     ret = MsiSourceListAddSourceExW(szProduct, sidstr,
881         context, MSISOURCETYPE_NETWORK, szSource, 0);
882 
883     if (sidstr)
884         LocalFree(sidstr);
885 
886     return ret;
887 }
888 
889 /******************************************************************
890  *  MsiSourceListAddSourceA (MSI.@)
891  */
892 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
893         DWORD dwReserved, LPCSTR szSource)
894 {
895     INT ret;
896     LPWSTR szwproduct;
897     LPWSTR szwusername;
898     LPWSTR szwsource;
899 
900     szwproduct = strdupAtoW( szProduct );
901     szwusername = strdupAtoW( szUserName );
902     szwsource = strdupAtoW( szSource );
903 
904     ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
905 
906     msi_free(szwproduct);
907     msi_free(szwusername);
908     msi_free(szwsource);
909 
910     return ret;
911 }
912 
913 /******************************************************************
914  *  MsiSourceListAddSourceExA (MSI.@)
915  */
916 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
917         MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
918 {
919     UINT ret;
920     LPWSTR product, usersid, source;
921 
922     product = strdupAtoW(szProduct);
923     usersid = strdupAtoW(szUserSid);
924     source = strdupAtoW(szSource);
925 
926     ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
927                                     dwOptions, source, dwIndex);
928 
929     msi_free(product);
930     msi_free(usersid);
931     msi_free(source);
932 
933     return ret;
934 }
935 
936 static void free_source_list(struct list *sourcelist)
937 {
938     while (!list_empty(sourcelist))
939     {
940         media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
941         list_remove(&info->entry);
942         msi_free(info->path);
943         msi_free(info);
944     }
945 }
946 
947 static void add_source_to_list(struct list *sourcelist, media_info *info,
948                                DWORD *index)
949 {
950     media_info *iter;
951     BOOL found = FALSE;
952 
953     if (index) *index = 0;
954 
955     if (list_empty(sourcelist))
956     {
957         list_add_head(sourcelist, &info->entry);
958         return;
959     }
960 
961     LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
962     {
963         if (!found && info->index < iter->index)
964         {
965             found = TRUE;
966             list_add_before(&iter->entry, &info->entry);
967         }
968 
969         /* update the rest of the list */
970         if (found)
971             swprintf(iter->szIndex, ARRAY_SIZE(iter->szIndex), L"%d", ++iter->index);
972         else if (index)
973             (*index)++;
974     }
975 
976     if (!found)
977         list_add_after(&iter->entry, &info->entry);
978 }
979 
980 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
981 {
982     UINT r = ERROR_SUCCESS;
983     DWORD index = 0;
984     WCHAR name[10];
985     DWORD size, val_size;
986     media_info *entry;
987 
988     *count = 0;
989 
990     while (r == ERROR_SUCCESS)
991     {
992         size = ARRAY_SIZE(name);
993         r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
994         if (r != ERROR_SUCCESS)
995             return r;
996 
997         entry = msi_alloc(sizeof(media_info));
998         if (!entry)
999             goto error;
1000 
1001         entry->path = msi_alloc(val_size);
1002         if (!entry->path)
1003         {
1004             msi_free(entry);
1005             goto error;
1006         }
1007 
1008         lstrcpyW(entry->szIndex, name);
1009         entry->index = wcstol(name, NULL, 10);
1010 
1011         size++;
1012         r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1013                           NULL, (LPBYTE)entry->path, &val_size);
1014         if (r != ERROR_SUCCESS)
1015         {
1016             msi_free(entry->path);
1017             msi_free(entry);
1018             goto error;
1019         }
1020 
1021         index = ++(*count);
1022         add_source_to_list(sourcelist, entry, NULL);
1023     }
1024 
1025 error:
1026     *count = -1;
1027     free_source_list(sourcelist);
1028     return ERROR_OUTOFMEMORY;
1029 }
1030 
1031 /******************************************************************
1032  *  MsiSourceListAddSourceExW (MSI.@)
1033  */
1034 UINT WINAPI MsiSourceListAddSourceExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1035                                        DWORD dwOptions, const WCHAR *szSource, DWORD dwIndex )
1036 {
1037     HKEY sourcekey, typekey;
1038     UINT rc;
1039     struct list sourcelist;
1040     media_info *info;
1041     WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1042     LPCWSTR postfix;
1043     DWORD size, count, index;
1044 
1045     TRACE( "%s, %s, %d, %#lx, %s, %lu\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1046            debugstr_w(szSource), dwIndex );
1047 
1048     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1049         return ERROR_INVALID_PARAMETER;
1050 
1051     if (!szSource || !*szSource)
1052         return ERROR_INVALID_PARAMETER;
1053 
1054     if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1055         return ERROR_INVALID_PARAMETER;
1056 
1057     if (dwOptions & MSICODE_PATCH)
1058     {
1059         FIXME("Unhandled options MSICODE_PATCH\n");
1060         return ERROR_FUNCTION_FAILED;
1061     }
1062 
1063     if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1064         return ERROR_INVALID_PARAMETER;
1065 
1066     rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1067     if (rc != ERROR_SUCCESS)
1068         return rc;
1069 
1070     if (dwOptions & MSISOURCETYPE_NETWORK)
1071         rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1072     else if (dwOptions & MSISOURCETYPE_URL)
1073         rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1074     else if (dwOptions & MSISOURCETYPE_MEDIA)
1075         rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1076     else
1077     {
1078         ERR( "unknown media type: %#lx\n", dwOptions );
1079         RegCloseKey(sourcekey);
1080         return ERROR_FUNCTION_FAILED;
1081     }
1082     if (rc != ERROR_SUCCESS)
1083     {
1084         ERR("can't open subkey %u\n", rc);
1085         RegCloseKey(sourcekey);
1086         return rc;
1087     }
1088 
1089     postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? L"\\" : L"/";
1090     if (szSource[lstrlenW(szSource) - 1] == *postfix)
1091         source = strdupW(szSource);
1092     else
1093     {
1094         size = lstrlenW(szSource) + 2;
1095         source = msi_alloc(size * sizeof(WCHAR));
1096         lstrcpyW(source, szSource);
1097         lstrcatW(source, postfix);
1098     }
1099 
1100     list_init(&sourcelist);
1101     rc = fill_source_list(&sourcelist, typekey, &count);
1102     if (rc != ERROR_NO_MORE_ITEMS)
1103         goto done;
1104 
1105     size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1106 
1107     if (count == 0)
1108     {
1109         rc = RegSetValueExW(typekey, L"1", 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1110         goto done;
1111     }
1112     else if (dwIndex > count || dwIndex == 0)
1113     {
1114         swprintf(name, ARRAY_SIZE(name), L"%d", count + 1);
1115         rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1116         goto done;
1117     }
1118     else
1119     {
1120         swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex);
1121         info = msi_alloc(sizeof(media_info));
1122         if (!info)
1123         {
1124             rc = ERROR_OUTOFMEMORY;
1125             goto done;
1126         }
1127 
1128         info->path = strdupW(source);
1129         lstrcpyW(info->szIndex, name);
1130         info->index = dwIndex;
1131         add_source_to_list(&sourcelist, info, &index);
1132 
1133         LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
1134         {
1135             if (info->index < index)
1136                 continue;
1137 
1138             size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1139             rc = RegSetValueExW(typekey, info->szIndex, 0,
1140                                 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1141             if (rc != ERROR_SUCCESS)
1142                 goto done;
1143         }
1144     }
1145 
1146 done:
1147     free_source_list(&sourcelist);
1148     msi_free(source);
1149     RegCloseKey(typekey);
1150     RegCloseKey(sourcekey);
1151     return rc;
1152 }
1153 
1154 /******************************************************************
1155  *  MsiSourceListAddMediaDiskA (MSI.@)
1156  */
1157 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1158         MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1159         LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1160 {
1161     UINT r;
1162     LPWSTR product = NULL;
1163     LPWSTR usersid = NULL;
1164     LPWSTR volume = NULL;
1165     LPWSTR prompt = NULL;
1166 
1167     if (szProduct) product = strdupAtoW(szProduct);
1168     if (szUserSid) usersid = strdupAtoW(szUserSid);
1169     if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1170     if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1171 
1172     r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1173                                      dwDiskId, volume, prompt);
1174 
1175     msi_free(product);
1176     msi_free(usersid);
1177     msi_free(volume);
1178     msi_free(prompt);
1179 
1180     return r;
1181 }
1182 
1183 /******************************************************************
1184  *  MsiSourceListAddMediaDiskW (MSI.@)
1185  */
1186 UINT WINAPI MsiSourceListAddMediaDiskW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1187                                         DWORD dwOptions, DWORD dwDiskId, const WCHAR *szVolumeLabel,
1188                                         const WCHAR *szDiskPrompt )
1189 {
1190     HKEY sourcekey, mediakey;
1191     UINT rc;
1192     WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1193     DWORD size;
1194 
1195     TRACE( "%s, %s, %d, %#lx, %lu, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1196            dwDiskId, debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt) );
1197 
1198     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1199         return ERROR_INVALID_PARAMETER;
1200 
1201     if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1202         return ERROR_INVALID_PARAMETER;
1203 
1204     if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1205         return ERROR_INVALID_PARAMETER;
1206 
1207     if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1208         return ERROR_INVALID_PARAMETER;
1209 
1210     if (dwOptions & MSICODE_PATCH)
1211     {
1212         FIXME("Unhandled options MSICODE_PATCH\n");
1213         return ERROR_FUNCTION_FAILED;
1214     }
1215 
1216     rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1217     if (rc != ERROR_SUCCESS)
1218         return rc;
1219 
1220     OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1221 
1222     swprintf(szIndex, ARRAY_SIZE(szIndex), L"%d", dwDiskId);
1223 
1224     size = 2;
1225     if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1226     if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1227 
1228     size *= sizeof(WCHAR);
1229     buffer = msi_alloc(size);
1230     *buffer = '\0';
1231 
1232     if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1233     lstrcatW(buffer, L";");
1234     if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1235 
1236     RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1237     msi_free(buffer);
1238 
1239     RegCloseKey(sourcekey);
1240     RegCloseKey(mediakey);
1241 
1242     return ERROR_SUCCESS;
1243 }
1244 
1245 /******************************************************************
1246  *  MsiSourceListClearAllA (MSI.@)
1247  */
1248 UINT WINAPI MsiSourceListClearAllA( const char *szProduct, const char *szUserName, DWORD dwReserved )
1249 {
1250     FIXME( "%s, %s, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved );
1251     return ERROR_SUCCESS;
1252 }
1253 
1254 /******************************************************************
1255  *  MsiSourceListClearAllW (MSI.@)
1256  */
1257 UINT WINAPI MsiSourceListClearAllW( const WCHAR *szProduct, const WCHAR *szUserName, DWORD dwReserved )
1258 {
1259     FIXME( "%s, %s, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved );
1260     return ERROR_SUCCESS;
1261 }
1262 
1263 /******************************************************************
1264  *  MsiSourceListClearAllExA (MSI.@)
1265  */
1266 UINT WINAPI MsiSourceListClearAllExA( const char *szProduct, const char *szUserSid, MSIINSTALLCONTEXT dwContext,
1267                                       DWORD dwOptions )
1268 {
1269     FIXME( "%s, %s, %d, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserSid), dwContext, dwOptions );
1270     return ERROR_SUCCESS;
1271 }
1272 
1273 /******************************************************************
1274  *  MsiSourceListClearAllExW (MSI.@)
1275  */
1276 UINT WINAPI MsiSourceListClearAllExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1277                                       DWORD dwOptions )
1278 {
1279     FIXME( "%s, %s, %d, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions );
1280     return ERROR_SUCCESS;
1281 }
1282 
1283 /******************************************************************
1284  *  MsiSourceListClearSourceA (MSI.@)
1285  */
1286 UINT WINAPI MsiSourceListClearSourceA( const char *szProductCodeOrPatchCode, const char *szUserSid,
1287                                        MSIINSTALLCONTEXT dwContext, DWORD dwOptions, const char *szSource )
1288 {
1289     FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), dwContext,
1290            dwOptions, debugstr_a(szSource) );
1291     return ERROR_SUCCESS;
1292 }
1293 
1294 /******************************************************************
1295  *  MsiSourceListClearSourceW (MSI.@)
1296  */
1297 UINT WINAPI MsiSourceListClearSourceW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid,
1298                                        MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource )
1299 {
1300     FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), dwContext,
1301            dwOptions, debugstr_w(szSource) );
1302     return ERROR_SUCCESS;
1303 }
1304 
1305 /******************************************************************
1306  *  MsiSourceListForceResolutionA (MSI.@)
1307  */
1308 UINT WINAPI MsiSourceListForceResolutionA( const char *product, const char *user, DWORD reserved )
1309 {
1310     FIXME( "%s, %s, %#lx\n", debugstr_a(product), debugstr_a(user), reserved );
1311     return ERROR_SUCCESS;
1312 }
1313 
1314 /******************************************************************
1315  *  MsiSourceListForceResolutionW (MSI.@)
1316  */
1317 UINT WINAPI MsiSourceListForceResolutionW( const WCHAR *product, const WCHAR *user, DWORD reserved )
1318 {
1319     FIXME( "%s, %s, %#lx\n", debugstr_w(product), debugstr_w(user), reserved );
1320     return ERROR_SUCCESS;
1321 }
1322