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