xref: /reactos/dll/win32/msi/source.c (revision f4be6dc3)
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 struct media_info
46 {
47     struct list entry;
48     LPWSTR  path;
49     WCHAR   szIndex[10];
50     DWORD   index;
51 };
52 
OpenSourceKey(LPCWSTR szProduct,HKEY * key,DWORD dwOptions,MSIINSTALLCONTEXT context,BOOL create)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 
OpenMediaSubkey(HKEY rootkey,HKEY * key,BOOL create)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 
OpenNetworkSubkey(HKEY rootkey,HKEY * key,BOOL create)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 
OpenURLSubkey(HKEY rootkey,HKEY * key,BOOL create)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  */
MsiSourceListEnumMediaDisksA(const char * szProductCodeOrPatchCode,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,DWORD * pdwDiskId,char * szVolumeLabel,DWORD * pcchVolumeLabel,char * szDiskPrompt,DWORD * pcchDiskPrompt)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 = malloc(*pcchVolumeLabel * sizeof(WCHAR));
166 
167     if (pcchDiskPrompt)
168         prompt = malloc(*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     free(product);
188     free(usersid);
189     free(volume);
190     free(prompt);
191 
192     return r;
193 }
194 
195 /******************************************************************
196  *  MsiSourceListEnumMediaDisksW   (MSI.@)
197  */
MsiSourceListEnumMediaDisksW(const WCHAR * szProductCodeOrPatchCode,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,DWORD * pdwDiskId,WCHAR * szVolumeLabel,DWORD * pcchVolumeLabel,WCHAR * szDiskPrompt,DWORD * pcchDiskPrompt)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 = malloc(++valuesz * sizeof(WCHAR));
253     data = malloc(++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     free(value);
320     free(data);
321     RegCloseKey(source);
322 
323     return r;
324 }
325 
326 /******************************************************************
327  *  MsiSourceListEnumSourcesA   (MSI.@)
328  */
MsiSourceListEnumSourcesA(const char * szProductCodeOrPatch,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,char * szSource,DWORD * pcchSource)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 = malloc(++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     free(product);
382     free(usersid);
383     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  */
MsiSourceListEnumSourcesW(const WCHAR * szProductCodeOrPatch,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,WCHAR * szSource,DWORD * pcchSource)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  */
MsiSourceListGetInfoA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCSTR szProperty,LPSTR szValue,LPDWORD pcchValue)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 = malloc(++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     free(product);
514     free(usersid);
515     free(property);
516     free(value);
517     return ret;
518 }
519 
520 /******************************************************************
521  *  MsiSourceListGetInfoW   (MSI.@)
522  */
MsiSourceListGetInfoW(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCWSTR szProperty,LPWSTR szValue,LPDWORD pcchValue)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 = malloc(size);
587         RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
588                          0, 0, (LPBYTE)source, &size);
589 
590         if (!*source)
591         {
592             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                 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         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  */
MsiSourceListSetInfoA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCSTR szProperty,LPCSTR szValue)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     free(product);
679     free(usersid);
680     free(property);
681     free(value);
682 
683     return ret;
684 }
685 
msi_set_last_used_source(LPCWSTR product,LPCWSTR usersid,MSIINSTALLCONTEXT context,DWORD options,LPCWSTR value)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 = malloc(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         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     free(buffer);
740 
741     RegCloseKey(source);
742     return r;
743 }
744 
745 /******************************************************************
746  *  MsiSourceListSetInfoW   (MSI.@)
747  */
MsiSourceListSetInfoW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,const WCHAR * szProperty,const WCHAR * szValue)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  */
MsiSourceListAddSourceW(LPCWSTR szProduct,LPCWSTR szUserName,DWORD dwReserved,LPCWSTR szSource)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 = malloc(sidsize);
855 
856             if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
857                 ConvertSidToStringSidW(psid, &sidstr);
858 
859             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  */
MsiSourceListAddSourceA(LPCSTR szProduct,LPCSTR szUserName,DWORD dwReserved,LPCSTR szSource)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     free(szwproduct);
907     free(szwusername);
908     free(szwsource);
909 
910     return ret;
911 }
912 
913 /******************************************************************
914  *  MsiSourceListAddSourceExA (MSI.@)
915  */
MsiSourceListAddSourceExA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCSTR szSource,DWORD dwIndex)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     free(product);
930     free(usersid);
931     free(source);
932 
933     return ret;
934 }
935 
free_source_list(struct list * sourcelist)936 static void free_source_list(struct list *sourcelist)
937 {
938     while (!list_empty(sourcelist))
939     {
940         struct media_info *info = LIST_ENTRY(list_head(sourcelist), struct media_info, entry);
941         list_remove(&info->entry);
942         free(info->path);
943         free(info);
944     }
945 }
946 
add_source_to_list(struct list * sourcelist,struct media_info * info,DWORD * index)947 static void add_source_to_list(struct list *sourcelist, struct media_info *info, DWORD *index)
948 {
949     struct media_info *iter;
950     BOOL found = FALSE;
951 
952     if (index) *index = 0;
953 
954     if (list_empty(sourcelist))
955     {
956         list_add_head(sourcelist, &info->entry);
957         return;
958     }
959 
960     LIST_FOR_EACH_ENTRY(iter, sourcelist, struct media_info, entry)
961     {
962         if (!found && info->index < iter->index)
963         {
964             found = TRUE;
965             list_add_before(&iter->entry, &info->entry);
966         }
967 
968         /* update the rest of the list */
969         if (found)
970             swprintf(iter->szIndex, ARRAY_SIZE(iter->szIndex), L"%d", ++iter->index);
971         else if (index)
972             (*index)++;
973     }
974 
975     if (!found)
976         list_add_after(&iter->entry, &info->entry);
977 }
978 
fill_source_list(struct list * sourcelist,HKEY sourcekey,DWORD * count)979 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
980 {
981     UINT r = ERROR_SUCCESS;
982     DWORD index = 0;
983     WCHAR name[10];
984     DWORD size, val_size;
985     struct media_info *entry;
986 
987     *count = 0;
988 
989     while (r == ERROR_SUCCESS)
990     {
991         size = ARRAY_SIZE(name);
992         r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
993         if (r != ERROR_SUCCESS)
994             return r;
995 
996         entry = malloc(sizeof(*entry));
997         if (!entry)
998             goto error;
999 
1000         entry->path = malloc(val_size);
1001         if (!entry->path)
1002         {
1003             free(entry);
1004             goto error;
1005         }
1006 
1007         lstrcpyW(entry->szIndex, name);
1008         entry->index = wcstol(name, NULL, 10);
1009 
1010         size++;
1011         r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1012                           NULL, (LPBYTE)entry->path, &val_size);
1013         if (r != ERROR_SUCCESS)
1014         {
1015             free(entry->path);
1016             free(entry);
1017             goto error;
1018         }
1019 
1020         index = ++(*count);
1021         add_source_to_list(sourcelist, entry, NULL);
1022     }
1023 
1024 error:
1025     *count = -1;
1026     free_source_list(sourcelist);
1027     return ERROR_OUTOFMEMORY;
1028 }
1029 
1030 /******************************************************************
1031  *  MsiSourceListAddSourceExW (MSI.@)
1032  */
MsiSourceListAddSourceExW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,const WCHAR * szSource,DWORD dwIndex)1033 UINT WINAPI MsiSourceListAddSourceExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1034                                        DWORD dwOptions, const WCHAR *szSource, DWORD dwIndex )
1035 {
1036     HKEY sourcekey, typekey;
1037     UINT rc;
1038     struct list sourcelist;
1039     struct media_info *info;
1040     WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1041     LPCWSTR postfix;
1042     DWORD size, count, index;
1043 
1044     TRACE( "%s, %s, %d, %#lx, %s, %lu\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1045            debugstr_w(szSource), dwIndex );
1046 
1047     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1048         return ERROR_INVALID_PARAMETER;
1049 
1050     if (!szSource || !*szSource)
1051         return ERROR_INVALID_PARAMETER;
1052 
1053     if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1054         return ERROR_INVALID_PARAMETER;
1055 
1056     if (dwOptions & MSICODE_PATCH)
1057     {
1058         FIXME("Unhandled options MSICODE_PATCH\n");
1059         return ERROR_FUNCTION_FAILED;
1060     }
1061 
1062     if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1063         return ERROR_INVALID_PARAMETER;
1064 
1065     rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1066     if (rc != ERROR_SUCCESS)
1067         return rc;
1068 
1069     if (dwOptions & MSISOURCETYPE_NETWORK)
1070         rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1071     else if (dwOptions & MSISOURCETYPE_URL)
1072         rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1073     else if (dwOptions & MSISOURCETYPE_MEDIA)
1074         rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1075     else
1076     {
1077         ERR( "unknown media type: %#lx\n", dwOptions );
1078         RegCloseKey(sourcekey);
1079         return ERROR_FUNCTION_FAILED;
1080     }
1081     if (rc != ERROR_SUCCESS)
1082     {
1083         ERR("can't open subkey %u\n", rc);
1084         RegCloseKey(sourcekey);
1085         return rc;
1086     }
1087 
1088     postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? L"\\" : L"/";
1089     if (szSource[lstrlenW(szSource) - 1] == *postfix)
1090         source = wcsdup(szSource);
1091     else
1092     {
1093         size = lstrlenW(szSource) + 2;
1094         source = malloc(size * sizeof(WCHAR));
1095         lstrcpyW(source, szSource);
1096         lstrcatW(source, postfix);
1097     }
1098 
1099     list_init(&sourcelist);
1100     rc = fill_source_list(&sourcelist, typekey, &count);
1101     if (rc != ERROR_NO_MORE_ITEMS)
1102         goto done;
1103 
1104     size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1105 
1106     if (count == 0)
1107     {
1108         rc = RegSetValueExW(typekey, L"1", 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1109         goto done;
1110     }
1111     else if (dwIndex > count || dwIndex == 0)
1112     {
1113         swprintf(name, ARRAY_SIZE(name), L"%d", count + 1);
1114         rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1115         goto done;
1116     }
1117     else
1118     {
1119         swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex);
1120         info = malloc(sizeof(*info));
1121         if (!info)
1122         {
1123             rc = ERROR_OUTOFMEMORY;
1124             goto done;
1125         }
1126 
1127         info->path = wcsdup(source);
1128         lstrcpyW(info->szIndex, name);
1129         info->index = dwIndex;
1130         add_source_to_list(&sourcelist, info, &index);
1131 
1132         LIST_FOR_EACH_ENTRY(info, &sourcelist, struct media_info, entry)
1133         {
1134             if (info->index < index)
1135                 continue;
1136 
1137             size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1138             rc = RegSetValueExW(typekey, info->szIndex, 0,
1139                                 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1140             if (rc != ERROR_SUCCESS)
1141                 goto done;
1142         }
1143     }
1144 
1145 done:
1146     free_source_list(&sourcelist);
1147     free(source);
1148     RegCloseKey(typekey);
1149     RegCloseKey(sourcekey);
1150     return rc;
1151 }
1152 
1153 /******************************************************************
1154  *  MsiSourceListAddMediaDiskA (MSI.@)
1155  */
MsiSourceListAddMediaDiskA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwDiskId,LPCSTR szVolumeLabel,LPCSTR szDiskPrompt)1156 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1157         MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1158         LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1159 {
1160     UINT r;
1161     LPWSTR product = NULL;
1162     LPWSTR usersid = NULL;
1163     LPWSTR volume = NULL;
1164     LPWSTR prompt = NULL;
1165 
1166     if (szProduct) product = strdupAtoW(szProduct);
1167     if (szUserSid) usersid = strdupAtoW(szUserSid);
1168     if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1169     if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1170 
1171     r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1172                                      dwDiskId, volume, prompt);
1173 
1174     free(product);
1175     free(usersid);
1176     free(volume);
1177     free(prompt);
1178 
1179     return r;
1180 }
1181 
1182 /******************************************************************
1183  *  MsiSourceListAddMediaDiskW (MSI.@)
1184  */
MsiSourceListAddMediaDiskW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwDiskId,const WCHAR * szVolumeLabel,const WCHAR * szDiskPrompt)1185 UINT WINAPI MsiSourceListAddMediaDiskW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1186                                         DWORD dwOptions, DWORD dwDiskId, const WCHAR *szVolumeLabel,
1187                                         const WCHAR *szDiskPrompt )
1188 {
1189     HKEY sourcekey, mediakey;
1190     UINT rc;
1191     WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1192     DWORD size;
1193 
1194     TRACE( "%s, %s, %d, %#lx, %lu, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1195            dwDiskId, debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt) );
1196 
1197     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1198         return ERROR_INVALID_PARAMETER;
1199 
1200     if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1201         return ERROR_INVALID_PARAMETER;
1202 
1203     if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1204         return ERROR_INVALID_PARAMETER;
1205 
1206     if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1207         return ERROR_INVALID_PARAMETER;
1208 
1209     if (dwOptions & MSICODE_PATCH)
1210     {
1211         FIXME("Unhandled options MSICODE_PATCH\n");
1212         return ERROR_FUNCTION_FAILED;
1213     }
1214 
1215     rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1216     if (rc != ERROR_SUCCESS)
1217         return rc;
1218 
1219     OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1220 
1221     swprintf(szIndex, ARRAY_SIZE(szIndex), L"%d", dwDiskId);
1222 
1223     size = 2;
1224     if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1225     if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1226 
1227     size *= sizeof(WCHAR);
1228     buffer = malloc(size);
1229     *buffer = '\0';
1230 
1231     if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1232     lstrcatW(buffer, L";");
1233     if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1234 
1235     RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1236     free(buffer);
1237 
1238     RegCloseKey(sourcekey);
1239     RegCloseKey(mediakey);
1240 
1241     return ERROR_SUCCESS;
1242 }
1243 
1244 /******************************************************************
1245  *  MsiSourceListClearAllA (MSI.@)
1246  */
MsiSourceListClearAllA(const char * szProduct,const char * szUserName,DWORD dwReserved)1247 UINT WINAPI MsiSourceListClearAllA( const char *szProduct, const char *szUserName, DWORD dwReserved )
1248 {
1249     FIXME( "%s, %s, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved );
1250     return ERROR_SUCCESS;
1251 }
1252 
1253 /******************************************************************
1254  *  MsiSourceListClearAllW (MSI.@)
1255  */
MsiSourceListClearAllW(const WCHAR * szProduct,const WCHAR * szUserName,DWORD dwReserved)1256 UINT WINAPI MsiSourceListClearAllW( const WCHAR *szProduct, const WCHAR *szUserName, DWORD dwReserved )
1257 {
1258     FIXME( "%s, %s, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved );
1259     return ERROR_SUCCESS;
1260 }
1261 
1262 /******************************************************************
1263  *  MsiSourceListClearAllExA (MSI.@)
1264  */
MsiSourceListClearAllExA(const char * szProduct,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions)1265 UINT WINAPI MsiSourceListClearAllExA( const char *szProduct, const char *szUserSid, MSIINSTALLCONTEXT dwContext,
1266                                       DWORD dwOptions )
1267 {
1268     FIXME( "%s, %s, %d, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserSid), dwContext, dwOptions );
1269     return ERROR_SUCCESS;
1270 }
1271 
1272 /******************************************************************
1273  *  MsiSourceListClearAllExW (MSI.@)
1274  */
MsiSourceListClearAllExW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions)1275 UINT WINAPI MsiSourceListClearAllExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1276                                       DWORD dwOptions )
1277 {
1278     FIXME( "%s, %s, %d, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions );
1279     return ERROR_SUCCESS;
1280 }
1281 
1282 /******************************************************************
1283  *  MsiSourceListClearSourceA (MSI.@)
1284  */
MsiSourceListClearSourceA(const char * szProductCodeOrPatchCode,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,const char * szSource)1285 UINT WINAPI MsiSourceListClearSourceA( const char *szProductCodeOrPatchCode, const char *szUserSid,
1286                                        MSIINSTALLCONTEXT dwContext, DWORD dwOptions, const char *szSource )
1287 {
1288     FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), dwContext,
1289            dwOptions, debugstr_a(szSource) );
1290     return ERROR_SUCCESS;
1291 }
1292 
1293 /******************************************************************
1294  *  MsiSourceListClearSourceW (MSI.@)
1295  */
MsiSourceListClearSourceW(const WCHAR * szProductCodeOrPatchCode,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCWSTR szSource)1296 UINT WINAPI MsiSourceListClearSourceW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid,
1297                                        MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource )
1298 {
1299     FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), dwContext,
1300            dwOptions, debugstr_w(szSource) );
1301     return ERROR_SUCCESS;
1302 }
1303 
1304 /******************************************************************
1305  *  MsiSourceListForceResolutionA (MSI.@)
1306  */
MsiSourceListForceResolutionA(const char * product,const char * user,DWORD reserved)1307 UINT WINAPI MsiSourceListForceResolutionA( const char *product, const char *user, DWORD reserved )
1308 {
1309     FIXME( "%s, %s, %#lx\n", debugstr_a(product), debugstr_a(user), reserved );
1310     return ERROR_SUCCESS;
1311 }
1312 
1313 /******************************************************************
1314  *  MsiSourceListForceResolutionW (MSI.@)
1315  */
MsiSourceListForceResolutionW(const WCHAR * product,const WCHAR * user,DWORD reserved)1316 UINT WINAPI MsiSourceListForceResolutionW( const WCHAR *product, const WCHAR *user, DWORD reserved )
1317 {
1318     FIXME( "%s, %s, %#lx\n", debugstr_w(product), debugstr_w(user), reserved );
1319     return ERROR_SUCCESS;
1320 }
1321