msi: Implement MsiSourceListGetInfoA.
[wine] / dlls / msi / source.c
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 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msiquery.h"
34 #include "msipriv.h"
35 #include "wincrypt.h"
36 #include "winver.h"
37 #include "winuser.h"
38 #include "wine/unicode.h"
39 #include "sddl.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42
43 /*
44  * These apis are defined in MSI 3.0
45  */
46
47 typedef struct tagMediaInfo
48 {
49     LPWSTR  path;
50     WCHAR   szIndex[10];
51     WCHAR   type;
52 } media_info;
53
54 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, BOOL user, BOOL create)
55 {
56     HKEY rootkey = 0; 
57     UINT rc; 
58     static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
59
60     if (user)
61         rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
62     else
63         rc = MSIREG_OpenProductsKey(szProduct, &rootkey, create);
64
65     if (rc)
66         return rc;
67
68     if (create)
69         rc = RegCreateKeyW(rootkey, szSourceList, key);
70     else
71         rc = RegOpenKeyW(rootkey,szSourceList, key); 
72
73     return rc;
74 }
75
76 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
77 {
78     UINT rc;
79     static const WCHAR media[] = {'M','e','d','i','a',0};
80
81     if (create)
82         rc = RegCreateKeyW(rootkey, media, key);
83     else
84         rc = RegOpenKeyW(rootkey,media, key); 
85
86     return rc;
87 }
88
89 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
90 {
91     UINT rc;
92     static const WCHAR net[] = {'N','e','t',0};
93
94     if (create)
95         rc = RegCreateKeyW(rootkey, net, key);
96     else
97         rc = RegOpenKeyW(rootkey, net, key); 
98
99     return rc;
100 }
101
102 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
103 {
104     UINT rc;
105     static const WCHAR URL[] = {'U','R','L',0};
106
107     if (create)
108         rc = RegCreateKeyW(rootkey, URL, key);
109     else
110         rc = RegOpenKeyW(rootkey, URL, key); 
111
112     return rc;
113 }
114
115
116 static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
117 {
118     DWORD index = 0;
119     WCHAR szIndex[10];
120     DWORD size;
121     DWORD val_size;
122     LPWSTR val;
123     UINT rc = ERROR_SUCCESS;
124
125     while (rc == ERROR_SUCCESS)
126     {
127         val = NULL;
128         val_size = 0;
129         size = sizeof(szIndex)/sizeof(szIndex[0]);
130         rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
131         if (rc != ERROR_NO_MORE_ITEMS)
132         {
133             val = msi_alloc(val_size);
134             RegEnumValueW(key, index, szIndex, &size, NULL, NULL, (LPBYTE)val, 
135                 &val_size);
136             if (lstrcmpiW(szSource,val)==0)
137             {
138                 ss->path = val;
139                 strcpyW(ss->szIndex,szIndex);
140                 break;
141             }
142             else
143                 strcpyW(ss->szIndex,szIndex);
144
145             msi_free(val);
146             index ++;
147         }
148     }
149     return rc;
150 }
151
152 /******************************************************************
153  *  MsiSourceListGetInfoA   (MSI.@)
154  */
155 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
156                                    MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
157                                    LPCSTR szProperty, LPSTR szValue,
158                                    LPDWORD pcchValue)
159 {
160     UINT ret;
161     LPWSTR product = NULL;
162     LPWSTR usersid = NULL;
163     LPWSTR property = NULL;
164     LPWSTR value = NULL;
165     DWORD len = 0;
166
167     if (szValue && !pcchValue)
168         return ERROR_INVALID_PARAMETER;
169
170     if (szProduct) product = strdupAtoW(szProduct);
171     if (szUserSid) usersid = strdupAtoW(szUserSid);
172     if (szProperty) property = strdupAtoW(szProperty);
173
174     ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
175                                 property, NULL, &len);
176     if (ret != ERROR_SUCCESS)
177         goto done;
178
179     value = msi_alloc(++len * sizeof(WCHAR));
180     if (!value)
181         return ERROR_OUTOFMEMORY;
182
183     ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
184                                 property, value, &len);
185     if (ret != ERROR_SUCCESS)
186         goto done;
187
188     len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
189     if (*pcchValue >= len)
190         WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
191     else if (szValue)
192         ret = ERROR_MORE_DATA;
193
194     *pcchValue = len - 1;
195
196 done:
197     msi_free(product);
198     msi_free(usersid);
199     msi_free(property);
200     msi_free(value);
201     return ret;
202 }
203
204 /******************************************************************
205  *  MsiSourceListGetInfoW   (MSI.@)
206  */
207 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
208                                    MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
209                                    LPCWSTR szProperty, LPWSTR szValue, 
210                                    LPDWORD pcchValue) 
211 {
212     HKEY sourcekey;
213     UINT rc;
214
215     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
216
217     if (!szProduct || lstrlenW(szProduct) > 39)
218         return ERROR_INVALID_PARAMETER;
219
220     if (szValue && !pcchValue)
221         return ERROR_INVALID_PARAMETER;
222     
223     if (dwOptions == MSICODE_PATCH)
224     {
225         FIXME("Unhandled options MSICODE_PATCH\n");
226         return ERROR_FUNCTION_FAILED;
227     }
228
229     if (szUserSid)
230         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
231
232     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
233         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
234
235     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
236         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, FALSE);
237     else
238         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, FALSE);
239
240     if (rc != ERROR_SUCCESS)
241         return ERROR_UNKNOWN_PRODUCT;
242
243     if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
244     {
245         HKEY key;
246         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
247         if (rc == ERROR_SUCCESS)
248             rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW,
249                     0, 0, (LPBYTE)szValue, pcchValue);
250         if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
251             rc = ERROR_UNKNOWN_PROPERTY;
252         RegCloseKey(key);
253     }
254     else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0)
255     {
256         HKEY key;
257         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
258         if (rc == ERROR_SUCCESS)
259             rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0,
260                     (LPBYTE)szValue, pcchValue);
261         if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
262             rc = ERROR_UNKNOWN_PROPERTY;
263         RegCloseKey(key);
264     }
265     else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
266     {
267         LPWSTR buffer;
268         DWORD size = 0;
269
270         RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
271                 NULL, &size);
272         if (size == 0)
273             rc = ERROR_UNKNOWN_PROPERTY;
274         else
275         {
276             LPWSTR ptr;
277             buffer = msi_alloc(size);
278             rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
279                     0, 0, (LPBYTE)buffer,&size); 
280             ptr = strchrW(buffer,';');
281             if (ptr) ptr = strchrW(ptr+1,';');
282             if (!ptr)
283                 rc = ERROR_UNKNOWN_PROPERTY;
284             else
285             {
286                 ptr ++;
287                 lstrcpynW(szValue, ptr, *pcchValue);
288                 if (lstrlenW(ptr) > *pcchValue)
289                 {
290                     *pcchValue = lstrlenW(ptr)+1;
291                     rc = ERROR_MORE_DATA;
292                 }
293                 else
294                     rc = ERROR_SUCCESS;
295             }
296             msi_free(buffer);
297         }
298     }
299     else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0)
300     {
301         LPWSTR buffer;
302         DWORD size = 0;
303
304         RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
305                 NULL, &size);
306         if (size == 0)
307             rc = ERROR_UNKNOWN_PROPERTY;
308         else
309         {
310             buffer = msi_alloc(size);
311             rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
312                     0, 0, (LPBYTE)buffer,&size); 
313             if (*pcchValue < 1)
314             {
315                 rc = ERROR_MORE_DATA;
316                 *pcchValue = 1;
317             }
318             else
319             {
320                 szValue[0] = buffer[0];
321                 rc = ERROR_SUCCESS;
322             }
323             msi_free(buffer);
324         }
325     }
326     else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
327     {
328         rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0, 
329                 (LPBYTE)szValue, pcchValue);
330         if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
331             rc = ERROR_UNKNOWN_PROPERTY;
332     }
333     else
334     {
335         FIXME("Unknown property %s\n",debugstr_w(szProperty));
336         rc = ERROR_UNKNOWN_PROPERTY;
337     }
338
339     RegCloseKey(sourcekey);
340     return rc;
341 }
342
343 /******************************************************************
344  *  MsiSourceListSetInfoW   (MSI.@)
345  */
346 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
347                                    MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
348                                    LPCWSTR szProperty, LPCWSTR szValue)
349 {
350     HKEY sourcekey;
351     UINT rc;
352
353     TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
354             dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
355
356     if (!szProduct || lstrlenW(szProduct) > 39)
357         return ERROR_INVALID_PARAMETER;
358
359     if (dwOptions & MSICODE_PATCH)
360     {
361         FIXME("Unhandled options MSICODE_PATCH\n");
362         return ERROR_FUNCTION_FAILED;
363     }
364     
365     if (szUserSid)
366         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
367
368     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
369         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
370
371     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
372         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
373     else
374         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
375
376     if (rc != ERROR_SUCCESS)
377         return ERROR_UNKNOWN_PRODUCT;
378
379
380     if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
381     {
382         HKEY key;
383         DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
384         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
385         if (rc == ERROR_SUCCESS)
386             rc = RegSetValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, 0,
387                     REG_SZ, (const BYTE *)szValue, size);
388         if (rc != ERROR_SUCCESS)
389             rc = ERROR_UNKNOWN_PROPERTY;
390         RegCloseKey(key);
391     }
392     else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) == 0)
393     {
394         HKEY key;
395         DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
396         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
397         if (rc == ERROR_SUCCESS)
398             rc = RegSetValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0,
399                     REG_SZ, (const BYTE *)szValue, size);
400         if (rc != ERROR_SUCCESS)
401             rc = ERROR_UNKNOWN_PROPERTY;
402         RegCloseKey(key);
403     }
404     else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
405     {
406         LPWSTR buffer = NULL;
407         DWORD size;
408         WCHAR typechar = 'n';
409         static const WCHAR LastUsedSource_Fmt[] = {'%','c',';','%','i',';','%','s',0};
410
411         /* make sure the source is registered */
412         MsiSourceListAddSourceExW(szProduct, szUserSid, dwContext, 
413                 dwOptions, szValue, 0); 
414
415         if (dwOptions & MSISOURCETYPE_NETWORK)
416             typechar = 'n';
417         else if (dwOptions & MSISOURCETYPE_URL)
418             typechar = 'u';
419         else if (dwOptions & MSISOURCETYPE_MEDIA)
420             typechar = 'm';
421         else
422             ERR("Unknown source type! %x\n", dwOptions);
423
424         size = (lstrlenW(szValue)+5)*sizeof(WCHAR);
425         buffer = msi_alloc(size);
426         sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue);
427         rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 
428                 REG_EXPAND_SZ, (LPBYTE)buffer, size);
429         if (rc != ERROR_SUCCESS)
430             rc = ERROR_UNKNOWN_PROPERTY;
431         msi_free( buffer );
432     }
433     else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
434     {
435         DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
436         rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
437                 REG_SZ, (const BYTE *)szValue, size);
438         if (rc != ERROR_SUCCESS)
439             rc = ERROR_UNKNOWN_PROPERTY;
440     }
441     else
442     {
443         FIXME("Unknown property %s\n",debugstr_w(szProperty));
444         rc = ERROR_UNKNOWN_PROPERTY;
445     }
446
447     RegCloseKey(sourcekey);
448     return rc;
449
450 }
451
452 /******************************************************************
453  *  MsiSourceListAddSourceW (MSI.@)
454  */
455 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
456         DWORD dwReserved, LPCWSTR szSource)
457 {
458     INT ret;
459     LPWSTR sidstr = NULL;
460     DWORD sidsize = 0;
461     DWORD domsize = 0;
462
463     TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
464
465     if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
466     {
467         PSID psid = msi_alloc(sidsize);
468
469         if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
470             ConvertSidToStringSidW(psid, &sidstr);
471
472         msi_free(psid);
473     }
474
475     ret = MsiSourceListAddSourceExW(szProduct, sidstr, 
476         MSIINSTALLCONTEXT_USERMANAGED, MSISOURCETYPE_NETWORK, szSource, 0);
477
478     if (sidstr)
479         LocalFree(sidstr);
480
481     return ret;
482 }
483
484 /******************************************************************
485  *  MsiSourceListAddSourceA (MSI.@)
486  */
487 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
488         DWORD dwReserved, LPCSTR szSource)
489 {
490     INT ret;
491     LPWSTR szwproduct;
492     LPWSTR szwusername;
493     LPWSTR szwsource;
494
495     szwproduct = strdupAtoW( szProduct );
496     szwusername = strdupAtoW( szUserName );
497     szwsource = strdupAtoW( szSource );
498
499     ret = MsiSourceListAddSourceW(szwproduct, szwusername, 0, szwsource);
500
501     msi_free(szwproduct);
502     msi_free(szwusername);
503     msi_free(szwsource);
504
505     return ret;
506 }
507
508 /******************************************************************
509  *  MsiSourceListAddSourceExW (MSI.@)
510  */
511 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
512         MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource, 
513         DWORD dwIndex)
514 {
515     HKEY sourcekey;
516     HKEY typekey;
517     UINT rc;
518     media_info source_struct;
519
520     TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
521           dwContext, dwOptions, debugstr_w(szSource), dwIndex);
522
523     if (!szProduct)
524         return ERROR_INVALID_PARAMETER;
525
526     if (!szSource)
527         return ERROR_INVALID_PARAMETER;
528
529     if (dwOptions & MSICODE_PATCH)
530     {
531         FIXME("Unhandled options MSICODE_PATCH\n");
532         return ERROR_FUNCTION_FAILED;
533     }
534
535     if (szUserSid)
536         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
537
538     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
539         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
540
541     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
542         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
543     else
544         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
545
546     if (rc != ERROR_SUCCESS)
547         return ERROR_UNKNOWN_PRODUCT;
548
549     if (dwOptions & MSISOURCETYPE_NETWORK)
550         rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
551     else if (dwOptions & MSISOURCETYPE_URL)
552         rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
553     else if (dwOptions & MSISOURCETYPE_MEDIA)
554         rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
555     else
556     {
557         ERR("unknown media type: %08x\n", dwOptions);
558         RegCloseKey(sourcekey);
559         return ERROR_FUNCTION_FAILED;
560     }
561
562     source_struct.szIndex[0] = 0;
563     if (find_given_source(typekey, szSource, &source_struct)==ERROR_SUCCESS)
564     {
565         DWORD current_index = atoiW(source_struct.szIndex);
566         /* found the source */
567         if (dwIndex > 0 && current_index != dwIndex)
568             FIXME("Need to reorder the sources!\n");
569         msi_free( source_struct.path );
570     }
571     else
572     {
573         DWORD current_index = 0;
574         static const WCHAR fmt[] = {'%','i',0};
575         DWORD size = lstrlenW(szSource)*sizeof(WCHAR);
576
577         if (source_struct.szIndex[0])
578             current_index = atoiW(source_struct.szIndex);
579         /* new source */
580         if (dwIndex > 0 && dwIndex < current_index)
581             FIXME("Need to reorder the sources!\n");
582
583         current_index ++;
584         sprintfW(source_struct.szIndex,fmt,current_index);
585         rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ, 
586                 (const BYTE *)szSource, size);
587     }
588
589     RegCloseKey(typekey);
590     RegCloseKey(sourcekey);
591     return rc;
592 }
593
594 /******************************************************************
595  *  MsiSourceListAddMediaDisk(MSI.@)
596  */
597 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid, 
598         MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, 
599         LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
600 {
601     HKEY sourcekey;
602     HKEY mediakey;
603     UINT rc;
604     WCHAR szIndex[10];
605     static const WCHAR fmt[] = {'%','i',0};
606     static const WCHAR disk_fmt[] = {'%','s',';','%','s',0};
607     static const WCHAR empty[1] = {0};
608     LPCWSTR pt1,pt2;
609     LPWSTR buffer;
610     DWORD size;
611
612     TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
613             debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
614             debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
615
616     if (!szProduct || lstrlenW(szProduct) > 39)
617         return ERROR_INVALID_PARAMETER;
618
619     if (dwOptions & MSICODE_PATCH)
620     {
621         FIXME("Unhandled options MSICODE_PATCH\n");
622         return ERROR_FUNCTION_FAILED;
623     }
624     
625     if (szUserSid)
626         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
627
628     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
629         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
630
631     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
632         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
633     else
634         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
635
636     if (rc != ERROR_SUCCESS)
637         return ERROR_UNKNOWN_PRODUCT;
638
639     OpenMediaSubkey(sourcekey,&mediakey,TRUE);
640
641     sprintfW(szIndex,fmt,dwDiskId);
642
643     size = 2;
644     if (szVolumeLabel)
645     {
646         size +=lstrlenW(szVolumeLabel);
647         pt1 = szVolumeLabel;
648     }
649     else
650         pt1 = empty;
651     if (szDiskPrompt)
652     {
653         size +=lstrlenW(szDiskPrompt);
654         pt2 = szDiskPrompt;
655     }
656     else
657         pt2 = empty;
658
659     size *=sizeof(WCHAR);
660
661     buffer = msi_alloc(size);
662     sprintfW(buffer,disk_fmt,pt1,pt2);
663
664     RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
665     msi_free( buffer );
666
667     RegCloseKey(sourcekey);
668     RegCloseKey(mediakey);
669
670     return ERROR_SUCCESS;
671 }
672
673 /******************************************************************
674  *  MsiSourceListAddSourceExA (MSI.@)
675  */
676 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
677 {
678     FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
679     return ERROR_SUCCESS;
680 }
681
682 /******************************************************************
683  *  MsiSourceListAddSourceExW (MSI.@)
684  */
685 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
686 {
687     FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
688     return ERROR_SUCCESS;
689 }