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