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