cmd: Fix subdirectory prefix in for loops.
[wine.git] / dlls / msi / source.c
blob68bf9d0a2265be19a98c717e83d34c2709e1914b
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
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.
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.
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
21 #include <stdarg.h>
23 #define COBJMACROS
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"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 * These apis are defined in MSI 3.0
46 typedef struct tagMediaInfo
48 struct list entry;
49 LPWSTR path;
50 WCHAR szIndex[10];
51 DWORD index;
52 } media_info;
54 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
55 MSIINSTALLCONTEXT context, BOOL create)
57 HKEY rootkey = 0;
58 UINT rc = ERROR_FUNCTION_FAILED;
60 if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
62 if (dwOptions & MSICODE_PATCH)
63 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
64 else
65 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
66 &rootkey, create);
68 else if (context == MSIINSTALLCONTEXT_USERMANAGED)
70 if (dwOptions & MSICODE_PATCH)
71 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
72 else
73 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
74 &rootkey, create);
76 else if (context == MSIINSTALLCONTEXT_MACHINE)
78 if (dwOptions & MSICODE_PATCH)
79 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
80 else
81 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
82 &rootkey, create);
85 if (rc != ERROR_SUCCESS)
87 if (dwOptions & MSICODE_PATCH)
88 return ERROR_UNKNOWN_PATCH;
89 else
90 return ERROR_UNKNOWN_PRODUCT;
93 if (create)
94 rc = RegCreateKeyW(rootkey, szSourceList, key);
95 else
97 rc = RegOpenKeyW(rootkey,szSourceList, key);
98 if (rc != ERROR_SUCCESS)
99 rc = ERROR_BAD_CONFIGURATION;
102 return rc;
105 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
107 UINT rc;
108 static const WCHAR media[] = {'M','e','d','i','a',0};
110 if (create)
111 rc = RegCreateKeyW(rootkey, media, key);
112 else
113 rc = RegOpenKeyW(rootkey,media, key);
115 return rc;
118 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
120 UINT rc;
121 static const WCHAR net[] = {'N','e','t',0};
123 if (create)
124 rc = RegCreateKeyW(rootkey, net, key);
125 else
126 rc = RegOpenKeyW(rootkey, net, key);
128 return rc;
131 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
133 UINT rc;
134 static const WCHAR URL[] = {'U','R','L',0};
136 if (create)
137 rc = RegCreateKeyW(rootkey, URL, key);
138 else
139 rc = RegOpenKeyW(rootkey, URL, key);
141 return rc;
144 /******************************************************************
145 * MsiSourceListEnumMediaDisksA (MSI.@)
147 UINT WINAPI MsiSourceListEnumMediaDisksA(LPCSTR szProductCodeOrPatchCode,
148 LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
149 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
150 LPSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
151 LPSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
153 LPWSTR product = NULL;
154 LPWSTR usersid = NULL;
155 LPWSTR volume = NULL;
156 LPWSTR prompt = NULL;
157 UINT r = ERROR_INVALID_PARAMETER;
159 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n", debugstr_a(szProductCodeOrPatchCode),
160 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId,
161 szVolumeLabel, pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
163 if (szDiskPrompt && !pcchDiskPrompt)
164 return ERROR_INVALID_PARAMETER;
166 if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode);
167 if (szUserSid) usersid = strdupAtoW(szUserSid);
169 /* FIXME: add tests for an invalid format */
171 if (pcchVolumeLabel)
172 volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR));
174 if (pcchDiskPrompt)
175 prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR));
177 if (volume) *volume = '\0';
178 if (prompt) *prompt = '\0';
179 r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions,
180 dwIndex, pdwDiskId, volume, pcchVolumeLabel,
181 prompt, pcchDiskPrompt);
182 if (r != ERROR_SUCCESS)
183 goto done;
185 if (szVolumeLabel && pcchVolumeLabel)
186 WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel,
187 *pcchVolumeLabel + 1, NULL, NULL);
189 if (szDiskPrompt)
190 WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt,
191 *pcchDiskPrompt + 1, NULL, NULL);
193 done:
194 msi_free(product);
195 msi_free(usersid);
196 msi_free(volume);
197 msi_free(prompt);
199 return r;
202 /******************************************************************
203 * MsiSourceListEnumMediaDisksW (MSI.@)
205 UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
206 LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
207 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
208 LPWSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
209 LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
211 static const WCHAR fmt[] = {'#','%','d',0};
212 WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11];
213 WCHAR *value = NULL, *data = NULL, *ptr, *ptr2;
214 HKEY source, media;
215 DWORD valuesz, datasz = 0, type, numvals, size;
216 LONG res;
217 UINT r;
218 static DWORD index = 0;
220 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p)\n", debugstr_w(szProductCodeOrPatchCode),
221 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel,
222 pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
224 if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc ))
225 return ERROR_INVALID_PARAMETER;
227 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
228 return ERROR_INVALID_PARAMETER;
230 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
231 return ERROR_INVALID_PARAMETER;
233 if (szDiskPrompt && !pcchDiskPrompt)
234 return ERROR_INVALID_PARAMETER;
236 if (dwIndex == 0)
237 index = 0;
239 if (dwIndex != index)
240 return ERROR_INVALID_PARAMETER;
242 r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE);
243 if (r != ERROR_SUCCESS)
244 return r;
246 r = OpenMediaSubkey(source, &media, FALSE);
247 if (r != ERROR_SUCCESS)
249 RegCloseKey(source);
250 return ERROR_NO_MORE_ITEMS;
253 res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
254 NULL, &numvals, &valuesz, &datasz, NULL, NULL);
255 if (res != ERROR_SUCCESS)
257 r = ERROR_BAD_CONFIGURATION;
258 goto done;
261 value = msi_alloc(++valuesz * sizeof(WCHAR));
262 data = msi_alloc(++datasz * sizeof(WCHAR));
263 if (!value || !data)
265 r = ERROR_OUTOFMEMORY;
266 goto done;
269 r = RegEnumValueW(media, dwIndex, value, &valuesz,
270 NULL, &type, (LPBYTE)data, &datasz);
271 if (r != ERROR_SUCCESS)
272 goto done;
274 if (pdwDiskId)
275 *pdwDiskId = atolW(value);
277 ptr2 = data;
278 ptr = strchrW(data, ';');
279 if (!ptr)
280 ptr = data;
281 else
282 *ptr = '\0';
284 if (pcchVolumeLabel)
286 if (type == REG_DWORD)
288 sprintfW(convert, fmt, *data);
289 size = lstrlenW(convert);
290 ptr2 = convert;
292 else
293 size = lstrlenW(data);
295 if (size >= *pcchVolumeLabel)
296 r = ERROR_MORE_DATA;
297 else if (szVolumeLabel)
298 lstrcpyW(szVolumeLabel, ptr2);
300 *pcchVolumeLabel = size;
303 if (pcchDiskPrompt)
305 if (!*ptr)
306 ptr++;
308 if (type == REG_DWORD)
310 sprintfW(convert, fmt, *ptr);
311 size = lstrlenW(convert);
312 ptr = convert;
314 else
315 size = lstrlenW(ptr);
317 if (size >= *pcchDiskPrompt)
318 r = ERROR_MORE_DATA;
319 else if (szDiskPrompt)
320 lstrcpyW(szDiskPrompt, ptr);
322 *pcchDiskPrompt = size;
325 index++;
327 done:
328 msi_free(value);
329 msi_free(data);
330 RegCloseKey(source);
332 return r;
335 /******************************************************************
336 * MsiSourceListEnumSourcesA (MSI.@)
338 UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid,
339 MSIINSTALLCONTEXT dwContext,
340 DWORD dwOptions, DWORD dwIndex,
341 LPSTR szSource, LPDWORD pcchSource)
343 LPWSTR product = NULL;
344 LPWSTR usersid = NULL;
345 LPWSTR source = NULL;
346 DWORD len = 0;
347 UINT r = ERROR_INVALID_PARAMETER;
348 static DWORD index = 0;
350 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch),
351 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
353 if (dwIndex == 0)
354 index = 0;
356 if (szSource && !pcchSource)
357 goto done;
359 if (dwIndex != index)
360 goto done;
362 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
363 if (szUserSid) usersid = strdupAtoW(szUserSid);
365 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
366 dwIndex, NULL, &len);
367 if (r != ERROR_SUCCESS)
368 goto done;
370 source = msi_alloc(++len * sizeof(WCHAR));
371 if (!source)
373 r = ERROR_OUTOFMEMORY;
374 goto done;
377 *source = '\0';
378 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
379 dwIndex, source, &len);
380 if (r != ERROR_SUCCESS)
381 goto done;
383 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
384 if (pcchSource && *pcchSource >= len)
385 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
386 else if (szSource)
387 r = ERROR_MORE_DATA;
389 if (pcchSource)
390 *pcchSource = len - 1;
392 done:
393 msi_free(product);
394 msi_free(usersid);
395 msi_free(source);
397 if (r == ERROR_SUCCESS)
399 if (szSource || !pcchSource) index++;
401 else if (dwIndex > index)
402 index = 0;
404 return r;
407 /******************************************************************
408 * MsiSourceListEnumSourcesW (MSI.@)
410 UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid,
411 MSIINSTALLCONTEXT dwContext,
412 DWORD dwOptions, DWORD dwIndex,
413 LPWSTR szSource, LPDWORD pcchSource)
415 static const WCHAR format[] = {'%','d',0};
416 WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32];
417 HKEY source = NULL, subkey = NULL;
418 LONG res;
419 UINT r = ERROR_INVALID_PARAMETER;
420 static DWORD index = 0;
422 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch),
423 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
425 if (dwIndex == 0)
426 index = 0;
428 if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc ))
429 goto done;
431 if (szSource && !pcchSource)
432 goto done;
434 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
435 goto done;
437 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
438 goto done;
440 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
441 goto done;
443 if (dwIndex != index)
444 goto done;
446 r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE );
447 if (r != ERROR_SUCCESS)
448 goto done;
450 if (dwOptions & MSISOURCETYPE_NETWORK)
451 r = OpenNetworkSubkey(source, &subkey, FALSE);
452 else if (dwOptions & MSISOURCETYPE_URL)
453 r = OpenURLSubkey(source, &subkey, FALSE);
455 if (r != ERROR_SUCCESS)
457 r = ERROR_NO_MORE_ITEMS;
458 goto done;
461 sprintfW(name, format, dwIndex + 1);
463 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
464 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
465 r = ERROR_NO_MORE_ITEMS;
467 done:
468 RegCloseKey(subkey);
469 RegCloseKey(source);
471 if (r == ERROR_SUCCESS)
473 if (szSource || !pcchSource) index++;
475 else if (dwIndex > index)
476 index = 0;
478 return r;
481 /******************************************************************
482 * MsiSourceListGetInfoA (MSI.@)
484 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
485 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
486 LPCSTR szProperty, LPSTR szValue,
487 LPDWORD pcchValue)
489 UINT ret;
490 LPWSTR product = NULL;
491 LPWSTR usersid = NULL;
492 LPWSTR property = NULL;
493 LPWSTR value = NULL;
494 DWORD len = 0;
496 if (szValue && !pcchValue)
497 return ERROR_INVALID_PARAMETER;
499 if (szProduct) product = strdupAtoW(szProduct);
500 if (szUserSid) usersid = strdupAtoW(szUserSid);
501 if (szProperty) property = strdupAtoW(szProperty);
503 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
504 property, NULL, &len);
505 if (ret != ERROR_SUCCESS)
506 goto done;
508 value = msi_alloc(++len * sizeof(WCHAR));
509 if (!value)
510 return ERROR_OUTOFMEMORY;
512 *value = '\0';
513 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
514 property, value, &len);
515 if (ret != ERROR_SUCCESS)
516 goto done;
518 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
519 if (*pcchValue >= len)
520 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
521 else if (szValue)
522 ret = ERROR_MORE_DATA;
524 *pcchValue = len - 1;
526 done:
527 msi_free(product);
528 msi_free(usersid);
529 msi_free(property);
530 msi_free(value);
531 return ret;
534 /******************************************************************
535 * MsiSourceListGetInfoW (MSI.@)
537 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
538 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
539 LPCWSTR szProperty, LPWSTR szValue,
540 LPDWORD pcchValue)
542 static const WCHAR mediapack[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0};
543 WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE];
544 HKEY sourcekey, media;
545 DWORD size;
546 UINT rc;
548 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
550 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
551 return ERROR_INVALID_PARAMETER;
553 if (szValue && !pcchValue)
554 return ERROR_INVALID_PARAMETER;
556 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
557 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
558 dwContext != MSIINSTALLCONTEXT_MACHINE)
559 return ERROR_INVALID_PARAMETER;
561 if (!szProperty)
562 return ERROR_INVALID_PARAMETER;
564 if (szUserSid)
565 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
567 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
568 if (rc != ERROR_SUCCESS)
569 return rc;
571 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
572 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
574 rc = OpenMediaSubkey(sourcekey, &media, FALSE);
575 if (rc != ERROR_SUCCESS)
577 RegCloseKey(sourcekey);
578 return ERROR_SUCCESS;
581 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
582 szProperty = mediapack;
584 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
585 RegCloseKey(media);
587 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
588 !strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
590 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
591 0, 0, NULL, &size);
592 if (rc != ERROR_SUCCESS)
594 RegCloseKey(sourcekey);
595 return ERROR_SUCCESS;
598 source = msi_alloc(size);
599 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
600 0, 0, (LPBYTE)source, &size);
602 if (!*source)
604 msi_free(source);
605 RegCloseKey(sourcekey);
606 return ERROR_SUCCESS;
609 if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
611 if (*source != 'n' && *source != 'u' && *source != 'm')
613 msi_free(source);
614 RegCloseKey(sourcekey);
615 return ERROR_SUCCESS;
618 ptr = source;
619 source[1] = '\0';
621 else
623 ptr = strrchrW(source, ';');
624 if (!ptr)
625 ptr = source;
626 else
627 ptr++;
630 if (szValue)
632 if (strlenW(ptr) < *pcchValue)
633 lstrcpyW(szValue, ptr);
634 else
635 rc = ERROR_MORE_DATA;
638 *pcchValue = lstrlenW(ptr);
639 msi_free(source);
641 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
643 *pcchValue = *pcchValue * sizeof(WCHAR);
644 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
645 (LPBYTE)szValue, pcchValue);
646 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
648 *pcchValue = 0;
649 rc = ERROR_SUCCESS;
651 else
653 if (*pcchValue)
654 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
655 if (szValue)
656 szValue[*pcchValue] = '\0';
659 else
661 FIXME("Unknown property %s\n",debugstr_w(szProperty));
662 rc = ERROR_UNKNOWN_PROPERTY;
665 RegCloseKey(sourcekey);
666 return rc;
669 /******************************************************************
670 * MsiSourceListSetInfoA (MSI.@)
672 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
673 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
674 LPCSTR szProperty, LPCSTR szValue)
676 UINT ret;
677 LPWSTR product = NULL;
678 LPWSTR usersid = NULL;
679 LPWSTR property = NULL;
680 LPWSTR value = NULL;
682 if (szProduct) product = strdupAtoW(szProduct);
683 if (szUserSid) usersid = strdupAtoW(szUserSid);
684 if (szProperty) property = strdupAtoW(szProperty);
685 if (szValue) value = strdupAtoW(szValue);
687 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
688 property, value);
690 msi_free(product);
691 msi_free(usersid);
692 msi_free(property);
693 msi_free(value);
695 return ret;
698 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
699 MSIINSTALLCONTEXT context, DWORD options,
700 LPCWSTR value)
702 HKEY source;
703 LPWSTR buffer;
704 WCHAR typechar;
705 DWORD size;
706 UINT r;
707 int index = 1;
709 static const WCHAR format[] = {'%','c',';','%','i',';','%','s',0};
711 if (options & MSISOURCETYPE_NETWORK)
712 typechar = 'n';
713 else if (options & MSISOURCETYPE_URL)
714 typechar = 'u';
715 else if (options & MSISOURCETYPE_MEDIA)
716 typechar = 'm';
717 else
718 return ERROR_INVALID_PARAMETER;
720 if (!(options & MSISOURCETYPE_MEDIA))
722 r = MsiSourceListAddSourceExW(product, usersid, context,
723 options, value, 0);
724 if (r != ERROR_SUCCESS)
725 return r;
727 index = 0;
728 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
729 index, NULL, NULL)) == ERROR_SUCCESS)
730 index++;
732 if (r != ERROR_NO_MORE_ITEMS)
733 return r;
736 size = (lstrlenW(format) + lstrlenW(value) + 7) * sizeof(WCHAR);
737 buffer = msi_alloc(size);
738 if (!buffer)
739 return ERROR_OUTOFMEMORY;
741 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
742 if (r != ERROR_SUCCESS)
744 msi_free(buffer);
745 return r;
748 sprintfW(buffer, format, typechar, index, value);
750 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
751 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
752 REG_SZ, (LPBYTE)buffer, size);
753 msi_free(buffer);
755 RegCloseKey(source);
756 return r;
759 /******************************************************************
760 * MsiSourceListSetInfoW (MSI.@)
762 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
763 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
764 LPCWSTR szProperty, LPCWSTR szValue)
766 static const WCHAR media_package[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0};
767 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
768 HKEY sourcekey, media;
769 LPCWSTR property;
770 UINT rc;
772 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
773 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
775 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
776 return ERROR_INVALID_PARAMETER;
778 if (!szProperty)
779 return ERROR_INVALID_PARAMETER;
781 if (!szValue)
782 return ERROR_UNKNOWN_PROPERTY;
784 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
785 return ERROR_INVALID_PARAMETER;
787 if (dwOptions & MSICODE_PATCH)
789 FIXME("Unhandled options MSICODE_PATCH\n");
790 return ERROR_UNKNOWN_PATCH;
793 property = szProperty;
794 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
795 property = media_package;
797 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
798 if (rc != ERROR_SUCCESS)
799 return rc;
801 if (strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
802 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
804 RegCloseKey(sourcekey);
805 return ERROR_INVALID_PARAMETER;
808 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
809 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
811 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
812 if (rc == ERROR_SUCCESS)
814 rc = msi_reg_set_val_str(media, property, szValue);
815 RegCloseKey(media);
818 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
820 DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
821 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
822 REG_SZ, (const BYTE *)szValue, size);
823 if (rc != ERROR_SUCCESS)
824 rc = ERROR_UNKNOWN_PROPERTY;
826 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
828 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
829 rc = ERROR_INVALID_PARAMETER;
830 else
831 rc = msi_set_last_used_source(szProduct, szUserSid, dwContext,
832 dwOptions, szValue);
834 else
835 rc = ERROR_UNKNOWN_PROPERTY;
837 RegCloseKey(sourcekey);
838 return rc;
841 /******************************************************************
842 * MsiSourceListAddSourceW (MSI.@)
844 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
845 DWORD dwReserved, LPCWSTR szSource)
847 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
848 INT ret;
849 DWORD sidsize = 0, domsize = 0, context;
850 HKEY hkey = 0;
851 UINT r;
853 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
855 if (!szSource || !*szSource)
856 return ERROR_INVALID_PARAMETER;
858 if (dwReserved != 0)
859 return ERROR_INVALID_PARAMETER;
861 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
862 return ERROR_INVALID_PARAMETER;
864 if (!szUserName || !*szUserName)
865 context = MSIINSTALLCONTEXT_MACHINE;
866 else
868 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
870 PSID psid = msi_alloc(sidsize);
872 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
873 ConvertSidToStringSidW(psid, &sidstr);
875 msi_free(psid);
878 r = MSIREG_OpenProductKey(szProduct, NULL,
879 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
880 if (r == ERROR_SUCCESS)
881 context = MSIINSTALLCONTEXT_USERMANAGED;
882 else
884 r = MSIREG_OpenProductKey(szProduct, NULL,
885 MSIINSTALLCONTEXT_USERUNMANAGED,
886 &hkey, FALSE);
887 if (r != ERROR_SUCCESS)
888 return ERROR_UNKNOWN_PRODUCT;
890 context = MSIINSTALLCONTEXT_USERUNMANAGED;
893 RegCloseKey(hkey);
896 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
897 context, MSISOURCETYPE_NETWORK, szSource, 0);
899 if (sidstr)
900 LocalFree(sidstr);
902 return ret;
905 /******************************************************************
906 * MsiSourceListAddSourceA (MSI.@)
908 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
909 DWORD dwReserved, LPCSTR szSource)
911 INT ret;
912 LPWSTR szwproduct;
913 LPWSTR szwusername;
914 LPWSTR szwsource;
916 szwproduct = strdupAtoW( szProduct );
917 szwusername = strdupAtoW( szUserName );
918 szwsource = strdupAtoW( szSource );
920 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
922 msi_free(szwproduct);
923 msi_free(szwusername);
924 msi_free(szwsource);
926 return ret;
929 /******************************************************************
930 * MsiSourceListAddSourceExA (MSI.@)
932 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
933 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
935 UINT ret;
936 LPWSTR product, usersid, source;
938 product = strdupAtoW(szProduct);
939 usersid = strdupAtoW(szUserSid);
940 source = strdupAtoW(szSource);
942 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
943 dwOptions, source, dwIndex);
945 msi_free(product);
946 msi_free(usersid);
947 msi_free(source);
949 return ret;
952 static void free_source_list(struct list *sourcelist)
954 while (!list_empty(sourcelist))
956 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
957 list_remove(&info->entry);
958 msi_free(info->path);
959 msi_free(info);
963 static void add_source_to_list(struct list *sourcelist, media_info *info,
964 DWORD *index)
966 media_info *iter;
967 BOOL found = FALSE;
968 static const WCHAR fmt[] = {'%','i',0};
970 if (index) *index = 0;
972 if (list_empty(sourcelist))
974 list_add_head(sourcelist, &info->entry);
975 return;
978 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
980 if (!found && info->index < iter->index)
982 found = TRUE;
983 list_add_before(&iter->entry, &info->entry);
986 /* update the rest of the list */
987 if (found)
988 sprintfW(iter->szIndex, fmt, ++iter->index);
989 else if (index)
990 (*index)++;
993 if (!found)
994 list_add_after(&iter->entry, &info->entry);
997 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
999 UINT r = ERROR_SUCCESS;
1000 DWORD index = 0;
1001 WCHAR name[10];
1002 DWORD size, val_size;
1003 media_info *entry;
1005 *count = 0;
1007 while (r == ERROR_SUCCESS)
1009 size = sizeof(name) / sizeof(name[0]);
1010 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
1011 if (r != ERROR_SUCCESS)
1012 return r;
1014 entry = msi_alloc(sizeof(media_info));
1015 if (!entry)
1016 goto error;
1018 entry->path = msi_alloc(val_size);
1019 if (!entry->path)
1021 msi_free(entry);
1022 goto error;
1025 lstrcpyW(entry->szIndex, name);
1026 entry->index = atoiW(name);
1028 size++;
1029 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1030 NULL, (LPBYTE)entry->path, &val_size);
1031 if (r != ERROR_SUCCESS)
1033 msi_free(entry->path);
1034 msi_free(entry);
1035 goto error;
1038 index = ++(*count);
1039 add_source_to_list(sourcelist, entry, NULL);
1042 error:
1043 *count = -1;
1044 free_source_list(sourcelist);
1045 return ERROR_OUTOFMEMORY;
1048 /******************************************************************
1049 * MsiSourceListAddSourceExW (MSI.@)
1051 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1052 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
1053 DWORD dwIndex)
1055 static const WCHAR fmt[] = {'%','i',0};
1056 HKEY sourcekey, typekey;
1057 UINT rc;
1058 struct list sourcelist;
1059 media_info *info;
1060 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1061 LPCWSTR postfix;
1062 DWORD size, count, index;
1064 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1065 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
1067 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1068 return ERROR_INVALID_PARAMETER;
1070 if (!szSource || !*szSource)
1071 return ERROR_INVALID_PARAMETER;
1073 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1074 return ERROR_INVALID_PARAMETER;
1076 if (dwOptions & MSICODE_PATCH)
1078 FIXME("Unhandled options MSICODE_PATCH\n");
1079 return ERROR_FUNCTION_FAILED;
1082 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1083 return ERROR_INVALID_PARAMETER;
1085 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1086 if (rc != ERROR_SUCCESS)
1087 return rc;
1089 if (dwOptions & MSISOURCETYPE_NETWORK)
1090 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1091 else if (dwOptions & MSISOURCETYPE_URL)
1092 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1093 else if (dwOptions & MSISOURCETYPE_MEDIA)
1094 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1095 else
1097 ERR("unknown media type: %08x\n", dwOptions);
1098 RegCloseKey(sourcekey);
1099 return ERROR_FUNCTION_FAILED;
1101 if (rc != ERROR_SUCCESS)
1103 ERR("can't open subkey %u\n", rc);
1104 RegCloseKey(sourcekey);
1105 return rc;
1108 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? szBackSlash : szForwardSlash;
1109 if (szSource[lstrlenW(szSource) - 1] == *postfix)
1110 source = strdupW(szSource);
1111 else
1113 size = lstrlenW(szSource) + 2;
1114 source = msi_alloc(size * sizeof(WCHAR));
1115 lstrcpyW(source, szSource);
1116 lstrcatW(source, postfix);
1119 list_init(&sourcelist);
1120 rc = fill_source_list(&sourcelist, typekey, &count);
1121 if (rc != ERROR_NO_MORE_ITEMS)
1122 goto done;
1124 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1126 if (count == 0)
1128 rc = RegSetValueExW(typekey, szOne, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1129 goto done;
1131 else if (dwIndex > count || dwIndex == 0)
1133 sprintfW(name, fmt, count + 1);
1134 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1135 goto done;
1137 else
1139 sprintfW(name, fmt, dwIndex);
1140 info = msi_alloc(sizeof(media_info));
1141 if (!info)
1143 rc = ERROR_OUTOFMEMORY;
1144 goto done;
1147 info->path = strdupW(source);
1148 lstrcpyW(info->szIndex, name);
1149 info->index = dwIndex;
1150 add_source_to_list(&sourcelist, info, &index);
1152 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
1154 if (info->index < index)
1155 continue;
1157 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1158 rc = RegSetValueExW(typekey, info->szIndex, 0,
1159 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1160 if (rc != ERROR_SUCCESS)
1161 goto done;
1165 done:
1166 free_source_list(&sourcelist);
1167 msi_free(source);
1168 RegCloseKey(typekey);
1169 RegCloseKey(sourcekey);
1170 return rc;
1173 /******************************************************************
1174 * MsiSourceListAddMediaDiskA (MSI.@)
1176 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1177 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1178 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1180 UINT r;
1181 LPWSTR product = NULL;
1182 LPWSTR usersid = NULL;
1183 LPWSTR volume = NULL;
1184 LPWSTR prompt = NULL;
1186 if (szProduct) product = strdupAtoW(szProduct);
1187 if (szUserSid) usersid = strdupAtoW(szUserSid);
1188 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1189 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1191 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1192 dwDiskId, volume, prompt);
1194 msi_free(product);
1195 msi_free(usersid);
1196 msi_free(volume);
1197 msi_free(prompt);
1199 return r;
1202 /******************************************************************
1203 * MsiSourceListAddMediaDiskW (MSI.@)
1205 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
1206 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1207 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
1209 static const WCHAR fmt[] = {'%','i',0};
1210 HKEY sourcekey, mediakey;
1211 UINT rc;
1212 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1213 DWORD size;
1215 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
1216 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
1217 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
1219 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1220 return ERROR_INVALID_PARAMETER;
1222 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1223 return ERROR_INVALID_PARAMETER;
1225 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1226 return ERROR_INVALID_PARAMETER;
1228 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1229 return ERROR_INVALID_PARAMETER;
1231 if (dwOptions & MSICODE_PATCH)
1233 FIXME("Unhandled options MSICODE_PATCH\n");
1234 return ERROR_FUNCTION_FAILED;
1237 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1238 if (rc != ERROR_SUCCESS)
1239 return rc;
1241 OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1243 sprintfW(szIndex, fmt, dwDiskId);
1245 size = 2;
1246 if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1247 if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1249 size *= sizeof(WCHAR);
1250 buffer = msi_alloc(size);
1251 *buffer = '\0';
1253 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1254 lstrcatW(buffer, szSemiColon);
1255 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1257 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1258 msi_free(buffer);
1260 RegCloseKey(sourcekey);
1261 RegCloseKey(mediakey);
1263 return ERROR_SUCCESS;
1266 /******************************************************************
1267 * MsiSourceListClearAllA (MSI.@)
1269 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
1271 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
1272 return ERROR_SUCCESS;
1275 /******************************************************************
1276 * MsiSourceListClearAllW (MSI.@)
1278 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
1280 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
1281 return ERROR_SUCCESS;
1284 /******************************************************************
1285 * MsiSourceListClearAllExA (MSI.@)
1287 UINT WINAPI MsiSourceListClearAllExA( LPCSTR szProduct, LPCSTR szUserSid,
1288 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1290 FIXME("(%s %s %d %08x)\n", debugstr_a(szProduct), debugstr_a(szUserSid),
1291 dwContext, dwOptions);
1292 return ERROR_SUCCESS;
1295 /******************************************************************
1296 * MsiSourceListClearAllExW (MSI.@)
1298 UINT WINAPI MsiSourceListClearAllExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1299 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1301 FIXME("(%s %s %d %08x)\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1302 dwContext, dwOptions);
1303 return ERROR_SUCCESS;
1306 /******************************************************************
1307 * MsiSourceListClearSourceA (MSI.@)
1309 UINT WINAPI MsiSourceListClearSourceA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid,
1310 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1311 LPCSTR szSource)
1313 FIXME("(%s %s %x %x %s)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid),
1314 dwContext, dwOptions, debugstr_a(szSource));
1315 return ERROR_SUCCESS;
1318 /******************************************************************
1319 * MsiSourceListClearSourceW (MSI.@)
1321 UINT WINAPI MsiSourceListClearSourceW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid,
1322 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1323 LPCWSTR szSource)
1325 FIXME("(%s %s %x %x %s)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid),
1326 dwContext, dwOptions, debugstr_w(szSource));
1327 return ERROR_SUCCESS;