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