7f55775b05db9bf2c7079e6ea6f9f67edd748126
[reactos.git] / dll / win32 / 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
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "winnls.h"
29 #include "shlwapi.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "wincrypt.h"
35 #include "winver.h"
36 #include "winuser.h"
37 #include "wine/unicode.h"
38 #include "sddl.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41
42 /*
43 * These apis are defined in MSI 3.0
44 */
45
46 typedef struct tagMediaInfo
47 {
48 struct list entry;
49 LPWSTR path;
50 WCHAR szIndex[10];
51 DWORD index;
52 } media_info;
53
54 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
55 MSIINSTALLCONTEXT context, BOOL create)
56 {
57 HKEY rootkey = 0;
58 UINT rc = ERROR_FUNCTION_FAILED;
59
60 if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
61 {
62 if (dwOptions & MSICODE_PATCH)
63 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
64 else
65 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
66 &rootkey, create);
67 }
68 else if (context == MSIINSTALLCONTEXT_USERMANAGED)
69 {
70 if (dwOptions & MSICODE_PATCH)
71 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
72 else
73 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
74 &rootkey, create);
75 }
76 else if (context == MSIINSTALLCONTEXT_MACHINE)
77 {
78 if (dwOptions & MSICODE_PATCH)
79 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
80 else
81 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
82 &rootkey, create);
83 }
84
85 if (rc != ERROR_SUCCESS)
86 {
87 if (dwOptions & MSICODE_PATCH)
88 return ERROR_UNKNOWN_PATCH;
89 else
90 return ERROR_UNKNOWN_PRODUCT;
91 }
92
93 if (create)
94 rc = RegCreateKeyW(rootkey, szSourceList, key);
95 else
96 {
97 rc = RegOpenKeyW(rootkey,szSourceList, key);
98 if (rc != ERROR_SUCCESS)
99 rc = ERROR_BAD_CONFIGURATION;
100 }
101 RegCloseKey(rootkey);
102
103 return rc;
104 }
105
106 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
107 {
108 UINT rc;
109 static const WCHAR media[] = {'M','e','d','i','a',0};
110
111 if (create)
112 rc = RegCreateKeyW(rootkey, media, key);
113 else
114 rc = RegOpenKeyW(rootkey,media, key);
115
116 return rc;
117 }
118
119 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
120 {
121 UINT rc;
122 static const WCHAR net[] = {'N','e','t',0};
123
124 if (create)
125 rc = RegCreateKeyW(rootkey, net, key);
126 else
127 rc = RegOpenKeyW(rootkey, net, key);
128
129 return rc;
130 }
131
132 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
133 {
134 UINT rc;
135 static const WCHAR URL[] = {'U','R','L',0};
136
137 if (create)
138 rc = RegCreateKeyW(rootkey, URL, key);
139 else
140 rc = RegOpenKeyW(rootkey, URL, key);
141
142 return rc;
143 }
144
145 /******************************************************************
146 * MsiSourceListEnumMediaDisksA (MSI.@)
147 */
148 UINT WINAPI MsiSourceListEnumMediaDisksA(LPCSTR szProductCodeOrPatchCode,
149 LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
150 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
151 LPSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
152 LPSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
153 {
154 LPWSTR product = NULL;
155 LPWSTR usersid = NULL;
156 LPWSTR volume = NULL;
157 LPWSTR prompt = NULL;
158 UINT r = ERROR_INVALID_PARAMETER;
159
160 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n", debugstr_a(szProductCodeOrPatchCode),
161 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId,
162 szVolumeLabel, pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
163
164 if (szDiskPrompt && !pcchDiskPrompt)
165 return ERROR_INVALID_PARAMETER;
166
167 if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode);
168 if (szUserSid) usersid = strdupAtoW(szUserSid);
169
170 /* FIXME: add tests for an invalid format */
171
172 if (pcchVolumeLabel)
173 volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR));
174
175 if (pcchDiskPrompt)
176 prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR));
177
178 if (volume) *volume = '\0';
179 if (prompt) *prompt = '\0';
180 r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions,
181 dwIndex, pdwDiskId, volume, pcchVolumeLabel,
182 prompt, pcchDiskPrompt);
183 if (r != ERROR_SUCCESS)
184 goto done;
185
186 if (szVolumeLabel && pcchVolumeLabel)
187 WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel,
188 *pcchVolumeLabel + 1, NULL, NULL);
189
190 if (szDiskPrompt)
191 WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt,
192 *pcchDiskPrompt + 1, NULL, NULL);
193
194 done:
195 msi_free(product);
196 msi_free(usersid);
197 msi_free(volume);
198 msi_free(prompt);
199
200 return r;
201 }
202
203 /******************************************************************
204 * MsiSourceListEnumMediaDisksW (MSI.@)
205 */
206 UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
207 LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
208 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
209 LPWSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
210 LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
211 {
212 static const WCHAR fmt[] = {'#','%','d',0};
213 WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11];
214 WCHAR *value = NULL, *data = NULL, *ptr, *ptr2;
215 HKEY source, media;
216 DWORD valuesz, datasz = 0, type, numvals, size;
217 LONG res;
218 UINT r;
219 static DWORD index = 0;
220
221 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p)\n", debugstr_w(szProductCodeOrPatchCode),
222 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel,
223 pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
224
225 if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc ))
226 return ERROR_INVALID_PARAMETER;
227
228 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
229 return ERROR_INVALID_PARAMETER;
230
231 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
232 return ERROR_INVALID_PARAMETER;
233
234 if (szDiskPrompt && !pcchDiskPrompt)
235 return ERROR_INVALID_PARAMETER;
236
237 if (dwIndex == 0)
238 index = 0;
239
240 if (dwIndex != index)
241 return ERROR_INVALID_PARAMETER;
242
243 r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE);
244 if (r != ERROR_SUCCESS)
245 return r;
246
247 r = OpenMediaSubkey(source, &media, FALSE);
248 if (r != ERROR_SUCCESS)
249 {
250 RegCloseKey(source);
251 return ERROR_NO_MORE_ITEMS;
252 }
253
254 res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
255 NULL, &numvals, &valuesz, &datasz, NULL, NULL);
256 if (res != ERROR_SUCCESS)
257 {
258 r = ERROR_BAD_CONFIGURATION;
259 goto done;
260 }
261
262 value = msi_alloc(++valuesz * sizeof(WCHAR));
263 data = msi_alloc(++datasz * sizeof(WCHAR));
264 if (!value || !data)
265 {
266 r = ERROR_OUTOFMEMORY;
267 goto done;
268 }
269
270 r = RegEnumValueW(media, dwIndex, value, &valuesz,
271 NULL, &type, (LPBYTE)data, &datasz);
272 if (r != ERROR_SUCCESS)
273 goto done;
274
275 if (pdwDiskId)
276 *pdwDiskId = atolW(value);
277
278 ptr2 = data;
279 ptr = strchrW(data, ';');
280 if (!ptr)
281 ptr = data;
282 else
283 *ptr = '\0';
284
285 if (pcchVolumeLabel)
286 {
287 if (type == REG_DWORD)
288 {
289 sprintfW(convert, fmt, *data);
290 size = lstrlenW(convert);
291 ptr2 = convert;
292 }
293 else
294 size = lstrlenW(data);
295
296 if (size >= *pcchVolumeLabel)
297 r = ERROR_MORE_DATA;
298 else if (szVolumeLabel)
299 lstrcpyW(szVolumeLabel, ptr2);
300
301 *pcchVolumeLabel = size;
302 }
303
304 if (pcchDiskPrompt)
305 {
306 if (!*ptr)
307 ptr++;
308
309 if (type == REG_DWORD)
310 {
311 sprintfW(convert, fmt, *ptr);
312 size = lstrlenW(convert);
313 ptr = convert;
314 }
315 else
316 size = lstrlenW(ptr);
317
318 if (size >= *pcchDiskPrompt)
319 r = ERROR_MORE_DATA;
320 else if (szDiskPrompt)
321 lstrcpyW(szDiskPrompt, ptr);
322
323 *pcchDiskPrompt = size;
324 }
325
326 index++;
327
328 done:
329 msi_free(value);
330 msi_free(data);
331 RegCloseKey(source);
332
333 return r;
334 }
335
336 /******************************************************************
337 * MsiSourceListEnumSourcesA (MSI.@)
338 */
339 UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid,
340 MSIINSTALLCONTEXT dwContext,
341 DWORD dwOptions, DWORD dwIndex,
342 LPSTR szSource, LPDWORD pcchSource)
343 {
344 LPWSTR product = NULL;
345 LPWSTR usersid = NULL;
346 LPWSTR source = NULL;
347 DWORD len = 0;
348 UINT r = ERROR_INVALID_PARAMETER;
349 static DWORD index = 0;
350
351 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch),
352 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
353
354 if (dwIndex == 0)
355 index = 0;
356
357 if (szSource && !pcchSource)
358 goto done;
359
360 if (dwIndex != index)
361 goto done;
362
363 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
364 if (szUserSid) usersid = strdupAtoW(szUserSid);
365
366 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
367 dwIndex, NULL, &len);
368 if (r != ERROR_SUCCESS)
369 goto done;
370
371 source = msi_alloc(++len * sizeof(WCHAR));
372 if (!source)
373 {
374 r = ERROR_OUTOFMEMORY;
375 goto done;
376 }
377
378 *source = '\0';
379 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
380 dwIndex, source, &len);
381 if (r != ERROR_SUCCESS)
382 goto done;
383
384 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
385 if (pcchSource && *pcchSource >= len)
386 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
387 else if (szSource)
388 r = ERROR_MORE_DATA;
389
390 if (pcchSource)
391 *pcchSource = len - 1;
392
393 done:
394 msi_free(product);
395 msi_free(usersid);
396 msi_free(source);
397
398 if (r == ERROR_SUCCESS)
399 {
400 if (szSource || !pcchSource) index++;
401 }
402 else if (dwIndex > index)
403 index = 0;
404
405 return r;
406 }
407
408 /******************************************************************
409 * MsiSourceListEnumSourcesW (MSI.@)
410 */
411 UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid,
412 MSIINSTALLCONTEXT dwContext,
413 DWORD dwOptions, DWORD dwIndex,
414 LPWSTR szSource, LPDWORD pcchSource)
415 {
416 static const WCHAR format[] = {'%','d',0};
417 WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32];
418 HKEY source = NULL, subkey = NULL;
419 LONG res;
420 UINT r = ERROR_INVALID_PARAMETER;
421 static DWORD index = 0;
422
423 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch),
424 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
425
426 if (dwIndex == 0)
427 index = 0;
428
429 if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc ))
430 goto done;
431
432 if (szSource && !pcchSource)
433 goto done;
434
435 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
436 goto done;
437
438 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
439 goto done;
440
441 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
442 goto done;
443
444 if (dwIndex != index)
445 goto done;
446
447 r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE );
448 if (r != ERROR_SUCCESS)
449 goto done;
450
451 if (dwOptions & MSISOURCETYPE_NETWORK)
452 r = OpenNetworkSubkey(source, &subkey, FALSE);
453 else if (dwOptions & MSISOURCETYPE_URL)
454 r = OpenURLSubkey(source, &subkey, FALSE);
455
456 if (r != ERROR_SUCCESS)
457 {
458 r = ERROR_NO_MORE_ITEMS;
459 goto done;
460 }
461
462 sprintfW(name, format, dwIndex + 1);
463
464 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
465 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
466 r = ERROR_NO_MORE_ITEMS;
467
468 done:
469 RegCloseKey(subkey);
470 RegCloseKey(source);
471
472 if (r == ERROR_SUCCESS)
473 {
474 if (szSource || !pcchSource) index++;
475 }
476 else if (dwIndex > index)
477 index = 0;
478
479 return r;
480 }
481
482 /******************************************************************
483 * MsiSourceListGetInfoA (MSI.@)
484 */
485 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
486 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
487 LPCSTR szProperty, LPSTR szValue,
488 LPDWORD pcchValue)
489 {
490 UINT ret;
491 LPWSTR product = NULL;
492 LPWSTR usersid = NULL;
493 LPWSTR property = NULL;
494 LPWSTR value = NULL;
495 DWORD len = 0;
496
497 if (szValue && !pcchValue)
498 return ERROR_INVALID_PARAMETER;
499
500 if (szProduct) product = strdupAtoW(szProduct);
501 if (szUserSid) usersid = strdupAtoW(szUserSid);
502 if (szProperty) property = strdupAtoW(szProperty);
503
504 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
505 property, NULL, &len);
506 if (ret != ERROR_SUCCESS)
507 goto done;
508
509 value = msi_alloc(++len * sizeof(WCHAR));
510 if (!value)
511 return ERROR_OUTOFMEMORY;
512
513 *value = '\0';
514 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
515 property, value, &len);
516 if (ret != ERROR_SUCCESS)
517 goto done;
518
519 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
520 if (*pcchValue >= len)
521 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
522 else if (szValue)
523 ret = ERROR_MORE_DATA;
524
525 *pcchValue = len - 1;
526
527 done:
528 msi_free(product);
529 msi_free(usersid);
530 msi_free(property);
531 msi_free(value);
532 return ret;
533 }
534
535 /******************************************************************
536 * MsiSourceListGetInfoW (MSI.@)
537 */
538 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
539 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
540 LPCWSTR szProperty, LPWSTR szValue,
541 LPDWORD pcchValue)
542 {
543 static const WCHAR mediapack[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0};
544 WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE];
545 HKEY sourcekey, media;
546 DWORD size;
547 UINT rc;
548
549 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
550
551 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
552 return ERROR_INVALID_PARAMETER;
553
554 if (szValue && !pcchValue)
555 return ERROR_INVALID_PARAMETER;
556
557 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
558 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
559 dwContext != MSIINSTALLCONTEXT_MACHINE)
560 return ERROR_INVALID_PARAMETER;
561
562 if (!szProperty)
563 return ERROR_INVALID_PARAMETER;
564
565 if (szUserSid)
566 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
567
568 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
569 if (rc != ERROR_SUCCESS)
570 return rc;
571
572 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
573 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
574 {
575 rc = OpenMediaSubkey(sourcekey, &media, FALSE);
576 if (rc != ERROR_SUCCESS)
577 {
578 RegCloseKey(sourcekey);
579 return ERROR_SUCCESS;
580 }
581
582 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
583 szProperty = mediapack;
584
585 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
586 RegCloseKey(media);
587 }
588 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
589 !strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
590 {
591 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
592 0, 0, NULL, &size);
593 if (rc != ERROR_SUCCESS)
594 {
595 RegCloseKey(sourcekey);
596 return ERROR_SUCCESS;
597 }
598
599 source = msi_alloc(size);
600 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
601 0, 0, (LPBYTE)source, &size);
602
603 if (!*source)
604 {
605 msi_free(source);
606 RegCloseKey(sourcekey);
607 return ERROR_SUCCESS;
608 }
609
610 if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
611 {
612 if (*source != 'n' && *source != 'u' && *source != 'm')
613 {
614 msi_free(source);
615 RegCloseKey(sourcekey);
616 return ERROR_SUCCESS;
617 }
618
619 ptr = source;
620 source[1] = '\0';
621 }
622 else
623 {
624 ptr = strrchrW(source, ';');
625 if (!ptr)
626 ptr = source;
627 else
628 ptr++;
629 }
630
631 if (szValue)
632 {
633 if (strlenW(ptr) < *pcchValue)
634 lstrcpyW(szValue, ptr);
635 else
636 rc = ERROR_MORE_DATA;
637 }
638
639 *pcchValue = lstrlenW(ptr);
640 msi_free(source);
641 }
642 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
643 {
644 *pcchValue = *pcchValue * sizeof(WCHAR);
645 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
646 (LPBYTE)szValue, pcchValue);
647 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
648 {
649 *pcchValue = 0;
650 rc = ERROR_SUCCESS;
651 }
652 else
653 {
654 if (*pcchValue)
655 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
656 if (szValue)
657 szValue[*pcchValue] = '\0';
658 }
659 }
660 else
661 {
662 FIXME("Unknown property %s\n",debugstr_w(szProperty));
663 rc = ERROR_UNKNOWN_PROPERTY;
664 }
665
666 RegCloseKey(sourcekey);
667 return rc;
668 }
669
670 /******************************************************************
671 * MsiSourceListSetInfoA (MSI.@)
672 */
673 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
674 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
675 LPCSTR szProperty, LPCSTR szValue)
676 {
677 UINT ret;
678 LPWSTR product = NULL;
679 LPWSTR usersid = NULL;
680 LPWSTR property = NULL;
681 LPWSTR value = NULL;
682
683 if (szProduct) product = strdupAtoW(szProduct);
684 if (szUserSid) usersid = strdupAtoW(szUserSid);
685 if (szProperty) property = strdupAtoW(szProperty);
686 if (szValue) value = strdupAtoW(szValue);
687
688 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
689 property, value);
690
691 msi_free(product);
692 msi_free(usersid);
693 msi_free(property);
694 msi_free(value);
695
696 return ret;
697 }
698
699 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
700 MSIINSTALLCONTEXT context, DWORD options,
701 LPCWSTR value)
702 {
703 HKEY source;
704 LPWSTR buffer;
705 WCHAR typechar;
706 DWORD size;
707 UINT r;
708 int index = 1;
709
710 static const WCHAR format[] = {'%','c',';','%','i',';','%','s',0};
711
712 if (options & MSISOURCETYPE_NETWORK)
713 typechar = 'n';
714 else if (options & MSISOURCETYPE_URL)
715 typechar = 'u';
716 else if (options & MSISOURCETYPE_MEDIA)
717 typechar = 'm';
718 else
719 return ERROR_INVALID_PARAMETER;
720
721 if (!(options & MSISOURCETYPE_MEDIA))
722 {
723 r = MsiSourceListAddSourceExW(product, usersid, context,
724 options, value, 0);
725 if (r != ERROR_SUCCESS)
726 return r;
727
728 index = 0;
729 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
730 index, NULL, NULL)) == ERROR_SUCCESS)
731 index++;
732
733 if (r != ERROR_NO_MORE_ITEMS)
734 return r;
735 }
736
737 size = (lstrlenW(format) + lstrlenW(value) + 7) * sizeof(WCHAR);
738 buffer = msi_alloc(size);
739 if (!buffer)
740 return ERROR_OUTOFMEMORY;
741
742 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
743 if (r != ERROR_SUCCESS)
744 {
745 msi_free(buffer);
746 return r;
747 }
748
749 sprintfW(buffer, format, typechar, index, value);
750
751 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
752 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
753 REG_SZ, (LPBYTE)buffer, size);
754 msi_free(buffer);
755
756 RegCloseKey(source);
757 return r;
758 }
759
760 /******************************************************************
761 * MsiSourceListSetInfoW (MSI.@)
762 */
763 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
764 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
765 LPCWSTR szProperty, LPCWSTR szValue)
766 {
767 static const WCHAR media_package[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0};
768 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
769 HKEY sourcekey, media;
770 LPCWSTR property;
771 UINT rc;
772
773 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
774 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
775
776 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
777 return ERROR_INVALID_PARAMETER;
778
779 if (!szProperty)
780 return ERROR_INVALID_PARAMETER;
781
782 if (!szValue)
783 return ERROR_UNKNOWN_PROPERTY;
784
785 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
786 return ERROR_INVALID_PARAMETER;
787
788 if (dwOptions & MSICODE_PATCH)
789 {
790 FIXME("Unhandled options MSICODE_PATCH\n");
791 return ERROR_UNKNOWN_PATCH;
792 }
793
794 property = szProperty;
795 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
796 property = media_package;
797
798 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
799 if (rc != ERROR_SUCCESS)
800 return rc;
801
802 if (strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
803 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
804 {
805 RegCloseKey(sourcekey);
806 return ERROR_INVALID_PARAMETER;
807 }
808
809 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
810 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
811 {
812 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
813 if (rc == ERROR_SUCCESS)
814 {
815 rc = msi_reg_set_val_str(media, property, szValue);
816 RegCloseKey(media);
817 }
818 }
819 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
820 {
821 DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
822 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
823 REG_SZ, (const BYTE *)szValue, size);
824 if (rc != ERROR_SUCCESS)
825 rc = ERROR_UNKNOWN_PROPERTY;
826 }
827 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
828 {
829 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
830 rc = ERROR_INVALID_PARAMETER;
831 else
832 rc = msi_set_last_used_source(szProduct, szUserSid, dwContext,
833 dwOptions, szValue);
834 }
835 else
836 rc = ERROR_UNKNOWN_PROPERTY;
837
838 RegCloseKey(sourcekey);
839 return rc;
840 }
841
842 /******************************************************************
843 * MsiSourceListAddSourceW (MSI.@)
844 */
845 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
846 DWORD dwReserved, LPCWSTR szSource)
847 {
848 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
849 INT ret;
850 DWORD sidsize = 0, domsize = 0, context;
851 HKEY hkey = 0;
852 UINT r;
853
854 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
855
856 if (!szSource || !*szSource)
857 return ERROR_INVALID_PARAMETER;
858
859 if (dwReserved != 0)
860 return ERROR_INVALID_PARAMETER;
861
862 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
863 return ERROR_INVALID_PARAMETER;
864
865 if (!szUserName || !*szUserName)
866 context = MSIINSTALLCONTEXT_MACHINE;
867 else
868 {
869 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
870 {
871 PSID psid = msi_alloc(sidsize);
872
873 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
874 ConvertSidToStringSidW(psid, &sidstr);
875
876 msi_free(psid);
877 }
878
879 r = MSIREG_OpenProductKey(szProduct, NULL,
880 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
881 if (r == ERROR_SUCCESS)
882 context = MSIINSTALLCONTEXT_USERMANAGED;
883 else
884 {
885 r = MSIREG_OpenProductKey(szProduct, NULL,
886 MSIINSTALLCONTEXT_USERUNMANAGED,
887 &hkey, FALSE);
888 if (r != ERROR_SUCCESS)
889 return ERROR_UNKNOWN_PRODUCT;
890
891 context = MSIINSTALLCONTEXT_USERUNMANAGED;
892 }
893
894 RegCloseKey(hkey);
895 }
896
897 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
898 context, MSISOURCETYPE_NETWORK, szSource, 0);
899
900 if (sidstr)
901 LocalFree(sidstr);
902
903 return ret;
904 }
905
906 /******************************************************************
907 * MsiSourceListAddSourceA (MSI.@)
908 */
909 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
910 DWORD dwReserved, LPCSTR szSource)
911 {
912 INT ret;
913 LPWSTR szwproduct;
914 LPWSTR szwusername;
915 LPWSTR szwsource;
916
917 szwproduct = strdupAtoW( szProduct );
918 szwusername = strdupAtoW( szUserName );
919 szwsource = strdupAtoW( szSource );
920
921 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
922
923 msi_free(szwproduct);
924 msi_free(szwusername);
925 msi_free(szwsource);
926
927 return ret;
928 }
929
930 /******************************************************************
931 * MsiSourceListAddSourceExA (MSI.@)
932 */
933 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
934 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
935 {
936 UINT ret;
937 LPWSTR product, usersid, source;
938
939 product = strdupAtoW(szProduct);
940 usersid = strdupAtoW(szUserSid);
941 source = strdupAtoW(szSource);
942
943 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
944 dwOptions, source, dwIndex);
945
946 msi_free(product);
947 msi_free(usersid);
948 msi_free(source);
949
950 return ret;
951 }
952
953 static void free_source_list(struct list *sourcelist)
954 {
955 while (!list_empty(sourcelist))
956 {
957 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
958 list_remove(&info->entry);
959 msi_free(info->path);
960 msi_free(info);
961 }
962 }
963
964 static void add_source_to_list(struct list *sourcelist, media_info *info,
965 DWORD *index)
966 {
967 media_info *iter;
968 BOOL found = FALSE;
969 static const WCHAR fmt[] = {'%','i',0};
970
971 if (index) *index = 0;
972
973 if (list_empty(sourcelist))
974 {
975 list_add_head(sourcelist, &info->entry);
976 return;
977 }
978
979 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
980 {
981 if (!found && info->index < iter->index)
982 {
983 found = TRUE;
984 list_add_before(&iter->entry, &info->entry);
985 }
986
987 /* update the rest of the list */
988 if (found)
989 sprintfW(iter->szIndex, fmt, ++iter->index);
990 else if (index)
991 (*index)++;
992 }
993
994 if (!found)
995 list_add_after(&iter->entry, &info->entry);
996 }
997
998 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
999 {
1000 UINT r = ERROR_SUCCESS;
1001 DWORD index = 0;
1002 WCHAR name[10];
1003 DWORD size, val_size;
1004 media_info *entry;
1005
1006 *count = 0;
1007
1008 while (r == ERROR_SUCCESS)
1009 {
1010 size = sizeof(name) / sizeof(name[0]);
1011 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
1012 if (r != ERROR_SUCCESS)
1013 return r;
1014
1015 entry = msi_alloc(sizeof(media_info));
1016 if (!entry)
1017 goto error;
1018
1019 entry->path = msi_alloc(val_size);
1020 if (!entry->path)
1021 {
1022 msi_free(entry);
1023 goto error;
1024 }
1025
1026 lstrcpyW(entry->szIndex, name);
1027 entry->index = atoiW(name);
1028
1029 size++;
1030 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1031 NULL, (LPBYTE)entry->path, &val_size);
1032 if (r != ERROR_SUCCESS)
1033 {
1034 msi_free(entry->path);
1035 msi_free(entry);
1036 goto error;
1037 }
1038
1039 index = ++(*count);
1040 add_source_to_list(sourcelist, entry, NULL);
1041 }
1042
1043 error:
1044 *count = -1;
1045 free_source_list(sourcelist);
1046 return ERROR_OUTOFMEMORY;
1047 }
1048
1049 /******************************************************************
1050 * MsiSourceListAddSourceExW (MSI.@)
1051 */
1052 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1053 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
1054 DWORD dwIndex)
1055 {
1056 static const WCHAR fmt[] = {'%','i',0};
1057 HKEY sourcekey, typekey;
1058 UINT rc;
1059 struct list sourcelist;
1060 media_info *info;
1061 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1062 LPCWSTR postfix;
1063 DWORD size, count, index;
1064
1065 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1066 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
1067
1068 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1069 return ERROR_INVALID_PARAMETER;
1070
1071 if (!szSource || !*szSource)
1072 return ERROR_INVALID_PARAMETER;
1073
1074 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1075 return ERROR_INVALID_PARAMETER;
1076
1077 if (dwOptions & MSICODE_PATCH)
1078 {
1079 FIXME("Unhandled options MSICODE_PATCH\n");
1080 return ERROR_FUNCTION_FAILED;
1081 }
1082
1083 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1084 return ERROR_INVALID_PARAMETER;
1085
1086 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1087 if (rc != ERROR_SUCCESS)
1088 return rc;
1089
1090 if (dwOptions & MSISOURCETYPE_NETWORK)
1091 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1092 else if (dwOptions & MSISOURCETYPE_URL)
1093 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1094 else if (dwOptions & MSISOURCETYPE_MEDIA)
1095 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1096 else
1097 {
1098 ERR("unknown media type: %08x\n", dwOptions);
1099 RegCloseKey(sourcekey);
1100 return ERROR_FUNCTION_FAILED;
1101 }
1102 if (rc != ERROR_SUCCESS)
1103 {
1104 ERR("can't open subkey %u\n", rc);
1105 RegCloseKey(sourcekey);
1106 return rc;
1107 }
1108
1109 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? szBackSlash : szForwardSlash;
1110 if (szSource[lstrlenW(szSource) - 1] == *postfix)
1111 source = strdupW(szSource);
1112 else
1113 {
1114 size = lstrlenW(szSource) + 2;
1115 source = msi_alloc(size * sizeof(WCHAR));
1116 lstrcpyW(source, szSource);
1117 lstrcatW(source, postfix);
1118 }
1119
1120 list_init(&sourcelist);
1121 rc = fill_source_list(&sourcelist, typekey, &count);
1122 if (rc != ERROR_NO_MORE_ITEMS)
1123 goto done;
1124
1125 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1126
1127 if (count == 0)
1128 {
1129 rc = RegSetValueExW(typekey, szOne, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1130 goto done;
1131 }
1132 else if (dwIndex > count || dwIndex == 0)
1133 {
1134 sprintfW(name, fmt, count + 1);
1135 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1136 goto done;
1137 }
1138 else
1139 {
1140 sprintfW(name, fmt, dwIndex);
1141 info = msi_alloc(sizeof(media_info));
1142 if (!info)
1143 {
1144 rc = ERROR_OUTOFMEMORY;
1145 goto done;
1146 }
1147
1148 info->path = strdupW(source);
1149 lstrcpyW(info->szIndex, name);
1150 info->index = dwIndex;
1151 add_source_to_list(&sourcelist, info, &index);
1152
1153 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
1154 {
1155 if (info->index < index)
1156 continue;
1157
1158 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1159 rc = RegSetValueExW(typekey, info->szIndex, 0,
1160 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1161 if (rc != ERROR_SUCCESS)
1162 goto done;
1163 }
1164 }
1165
1166 done:
1167 free_source_list(&sourcelist);
1168 msi_free(source);
1169 RegCloseKey(typekey);
1170 RegCloseKey(sourcekey);
1171 return rc;
1172 }
1173
1174 /******************************************************************
1175 * MsiSourceListAddMediaDiskA (MSI.@)
1176 */
1177 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1178 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1179 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1180 {
1181 UINT r;
1182 LPWSTR product = NULL;
1183 LPWSTR usersid = NULL;
1184 LPWSTR volume = NULL;
1185 LPWSTR prompt = NULL;
1186
1187 if (szProduct) product = strdupAtoW(szProduct);
1188 if (szUserSid) usersid = strdupAtoW(szUserSid);
1189 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1190 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1191
1192 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1193 dwDiskId, volume, prompt);
1194
1195 msi_free(product);
1196 msi_free(usersid);
1197 msi_free(volume);
1198 msi_free(prompt);
1199
1200 return r;
1201 }
1202
1203 /******************************************************************
1204 * MsiSourceListAddMediaDiskW (MSI.@)
1205 */
1206 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
1207 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1208 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
1209 {
1210 static const WCHAR fmt[] = {'%','i',0};
1211 HKEY sourcekey, mediakey;
1212 UINT rc;
1213 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1214 DWORD size;
1215
1216 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
1217 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
1218 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
1219
1220 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1221 return ERROR_INVALID_PARAMETER;
1222
1223 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1224 return ERROR_INVALID_PARAMETER;
1225
1226 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1227 return ERROR_INVALID_PARAMETER;
1228
1229 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1230 return ERROR_INVALID_PARAMETER;
1231
1232 if (dwOptions & MSICODE_PATCH)
1233 {
1234 FIXME("Unhandled options MSICODE_PATCH\n");
1235 return ERROR_FUNCTION_FAILED;
1236 }
1237
1238 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1239 if (rc != ERROR_SUCCESS)
1240 return rc;
1241
1242 OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1243
1244 sprintfW(szIndex, fmt, dwDiskId);
1245
1246 size = 2;
1247 if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1248 if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1249
1250 size *= sizeof(WCHAR);
1251 buffer = msi_alloc(size);
1252 *buffer = '\0';
1253
1254 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1255 lstrcatW(buffer, szSemiColon);
1256 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1257
1258 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1259 msi_free(buffer);
1260
1261 RegCloseKey(sourcekey);
1262 RegCloseKey(mediakey);
1263
1264 return ERROR_SUCCESS;
1265 }
1266
1267 /******************************************************************
1268 * MsiSourceListClearAllA (MSI.@)
1269 */
1270 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
1271 {
1272 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
1273 return ERROR_SUCCESS;
1274 }
1275
1276 /******************************************************************
1277 * MsiSourceListClearAllW (MSI.@)
1278 */
1279 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
1280 {
1281 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
1282 return ERROR_SUCCESS;
1283 }
1284
1285 /******************************************************************
1286 * MsiSourceListClearAllExA (MSI.@)
1287 */
1288 UINT WINAPI MsiSourceListClearAllExA( LPCSTR szProduct, LPCSTR szUserSid,
1289 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1290 {
1291 FIXME("(%s %s %d %08x)\n", debugstr_a(szProduct), debugstr_a(szUserSid),
1292 dwContext, dwOptions);
1293 return ERROR_SUCCESS;
1294 }
1295
1296 /******************************************************************
1297 * MsiSourceListClearAllExW (MSI.@)
1298 */
1299 UINT WINAPI MsiSourceListClearAllExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1300 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1301 {
1302 FIXME("(%s %s %d %08x)\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1303 dwContext, dwOptions);
1304 return ERROR_SUCCESS;
1305 }
1306
1307 /******************************************************************
1308 * MsiSourceListClearSourceA (MSI.@)
1309 */
1310 UINT WINAPI MsiSourceListClearSourceA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid,
1311 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1312 LPCSTR szSource)
1313 {
1314 FIXME("(%s %s %x %x %s)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid),
1315 dwContext, dwOptions, debugstr_a(szSource));
1316 return ERROR_SUCCESS;
1317 }
1318
1319 /******************************************************************
1320 * MsiSourceListClearSourceW (MSI.@)
1321 */
1322 UINT WINAPI MsiSourceListClearSourceW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid,
1323 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1324 LPCWSTR szSource)
1325 {
1326 FIXME("(%s %s %x %x %s)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid),
1327 dwContext, dwOptions, debugstr_w(szSource));
1328 return ERROR_SUCCESS;
1329 }