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