msi: Do not leak rootkey.
[wine.git] / dlls / msi / source.c
blobe2cf7fc8ad7cb0c2ea94158a0f61c540b6a8b7f1
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;
101 RegCloseKey(rootkey);
103 return rc;
106 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
108 UINT rc;
109 static const WCHAR media[] = {'M','e','d','i','a',0};
111 if (create)
112 rc = RegCreateKeyW(rootkey, media, key);
113 else
114 rc = RegOpenKeyW(rootkey,media, key);
116 return rc;
119 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
121 UINT rc;
122 static const WCHAR net[] = {'N','e','t',0};
124 if (create)
125 rc = RegCreateKeyW(rootkey, net, key);
126 else
127 rc = RegOpenKeyW(rootkey, net, key);
129 return rc;
132 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
134 UINT rc;
135 static const WCHAR URL[] = {'U','R','L',0};
137 if (create)
138 rc = RegCreateKeyW(rootkey, URL, key);
139 else
140 rc = RegOpenKeyW(rootkey, URL, key);
142 return rc;
145 /******************************************************************
146 * MsiSourceListEnumMediaDisksA (MSI.@)
148 UINT WINAPI MsiSourceListEnumMediaDisksA(LPCSTR szProductCodeOrPatchCode,
149 LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
150 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
151 LPSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
152 LPSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
154 LPWSTR product = NULL;
155 LPWSTR usersid = NULL;
156 LPWSTR volume = NULL;
157 LPWSTR prompt = NULL;
158 UINT r = ERROR_INVALID_PARAMETER;
160 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n", debugstr_a(szProductCodeOrPatchCode),
161 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId,
162 szVolumeLabel, pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
164 if (szDiskPrompt && !pcchDiskPrompt)
165 return ERROR_INVALID_PARAMETER;
167 if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode);
168 if (szUserSid) usersid = strdupAtoW(szUserSid);
170 /* FIXME: add tests for an invalid format */
172 if (pcchVolumeLabel)
173 volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR));
175 if (pcchDiskPrompt)
176 prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR));
178 if (volume) *volume = '\0';
179 if (prompt) *prompt = '\0';
180 r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions,
181 dwIndex, pdwDiskId, volume, pcchVolumeLabel,
182 prompt, pcchDiskPrompt);
183 if (r != ERROR_SUCCESS)
184 goto done;
186 if (szVolumeLabel && pcchVolumeLabel)
187 WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel,
188 *pcchVolumeLabel + 1, NULL, NULL);
190 if (szDiskPrompt)
191 WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt,
192 *pcchDiskPrompt + 1, NULL, NULL);
194 done:
195 msi_free(product);
196 msi_free(usersid);
197 msi_free(volume);
198 msi_free(prompt);
200 return r;
203 /******************************************************************
204 * MsiSourceListEnumMediaDisksW (MSI.@)
206 UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
207 LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
208 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
209 LPWSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
210 LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
212 static const WCHAR fmt[] = {'#','%','d',0};
213 WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11];
214 WCHAR *value = NULL, *data = NULL, *ptr, *ptr2;
215 HKEY source, media;
216 DWORD valuesz, datasz = 0, type, numvals, size;
217 LONG res;
218 UINT r;
219 static DWORD index = 0;
221 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p)\n", debugstr_w(szProductCodeOrPatchCode),
222 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel,
223 pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
225 if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc ))
226 return ERROR_INVALID_PARAMETER;
228 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
229 return ERROR_INVALID_PARAMETER;
231 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
232 return ERROR_INVALID_PARAMETER;
234 if (szDiskPrompt && !pcchDiskPrompt)
235 return ERROR_INVALID_PARAMETER;
237 if (dwIndex == 0)
238 index = 0;
240 if (dwIndex != index)
241 return ERROR_INVALID_PARAMETER;
243 r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE);
244 if (r != ERROR_SUCCESS)
245 return r;
247 r = OpenMediaSubkey(source, &media, FALSE);
248 if (r != ERROR_SUCCESS)
250 RegCloseKey(source);
251 return ERROR_NO_MORE_ITEMS;
254 res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
255 NULL, &numvals, &valuesz, &datasz, NULL, NULL);
256 if (res != ERROR_SUCCESS)
258 r = ERROR_BAD_CONFIGURATION;
259 goto done;
262 value = msi_alloc(++valuesz * sizeof(WCHAR));
263 data = msi_alloc(++datasz * sizeof(WCHAR));
264 if (!value || !data)
266 r = ERROR_OUTOFMEMORY;
267 goto done;
270 r = RegEnumValueW(media, dwIndex, value, &valuesz,
271 NULL, &type, (LPBYTE)data, &datasz);
272 if (r != ERROR_SUCCESS)
273 goto done;
275 if (pdwDiskId)
276 *pdwDiskId = atolW(value);
278 ptr2 = data;
279 ptr = strchrW(data, ';');
280 if (!ptr)
281 ptr = data;
282 else
283 *ptr = '\0';
285 if (pcchVolumeLabel)
287 if (type == REG_DWORD)
289 sprintfW(convert, fmt, *data);
290 size = lstrlenW(convert);
291 ptr2 = convert;
293 else
294 size = lstrlenW(data);
296 if (size >= *pcchVolumeLabel)
297 r = ERROR_MORE_DATA;
298 else if (szVolumeLabel)
299 lstrcpyW(szVolumeLabel, ptr2);
301 *pcchVolumeLabel = size;
304 if (pcchDiskPrompt)
306 if (!*ptr)
307 ptr++;
309 if (type == REG_DWORD)
311 sprintfW(convert, fmt, *ptr);
312 size = lstrlenW(convert);
313 ptr = convert;
315 else
316 size = lstrlenW(ptr);
318 if (size >= *pcchDiskPrompt)
319 r = ERROR_MORE_DATA;
320 else if (szDiskPrompt)
321 lstrcpyW(szDiskPrompt, ptr);
323 *pcchDiskPrompt = size;
326 index++;
328 done:
329 msi_free(value);
330 msi_free(data);
331 RegCloseKey(source);
333 return r;
336 /******************************************************************
337 * MsiSourceListEnumSourcesA (MSI.@)
339 UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid,
340 MSIINSTALLCONTEXT dwContext,
341 DWORD dwOptions, DWORD dwIndex,
342 LPSTR szSource, LPDWORD pcchSource)
344 LPWSTR product = NULL;
345 LPWSTR usersid = NULL;
346 LPWSTR source = NULL;
347 DWORD len = 0;
348 UINT r = ERROR_INVALID_PARAMETER;
349 static DWORD index = 0;
351 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch),
352 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
354 if (dwIndex == 0)
355 index = 0;
357 if (szSource && !pcchSource)
358 goto done;
360 if (dwIndex != index)
361 goto done;
363 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
364 if (szUserSid) usersid = strdupAtoW(szUserSid);
366 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
367 dwIndex, NULL, &len);
368 if (r != ERROR_SUCCESS)
369 goto done;
371 source = msi_alloc(++len * sizeof(WCHAR));
372 if (!source)
374 r = ERROR_OUTOFMEMORY;
375 goto done;
378 *source = '\0';
379 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
380 dwIndex, source, &len);
381 if (r != ERROR_SUCCESS)
382 goto done;
384 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
385 if (pcchSource && *pcchSource >= len)
386 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
387 else if (szSource)
388 r = ERROR_MORE_DATA;
390 if (pcchSource)
391 *pcchSource = len - 1;
393 done:
394 msi_free(product);
395 msi_free(usersid);
396 msi_free(source);
398 if (r == ERROR_SUCCESS)
400 if (szSource || !pcchSource) index++;
402 else if (dwIndex > index)
403 index = 0;
405 return r;
408 /******************************************************************
409 * MsiSourceListEnumSourcesW (MSI.@)
411 UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid,
412 MSIINSTALLCONTEXT dwContext,
413 DWORD dwOptions, DWORD dwIndex,
414 LPWSTR szSource, LPDWORD pcchSource)
416 static const WCHAR format[] = {'%','d',0};
417 WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32];
418 HKEY source = NULL, subkey = NULL;
419 LONG res;
420 UINT r = ERROR_INVALID_PARAMETER;
421 static DWORD index = 0;
423 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch),
424 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
426 if (dwIndex == 0)
427 index = 0;
429 if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc ))
430 goto done;
432 if (szSource && !pcchSource)
433 goto done;
435 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
436 goto done;
438 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
439 goto done;
441 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
442 goto done;
444 if (dwIndex != index)
445 goto done;
447 r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE );
448 if (r != ERROR_SUCCESS)
449 goto done;
451 if (dwOptions & MSISOURCETYPE_NETWORK)
452 r = OpenNetworkSubkey(source, &subkey, FALSE);
453 else if (dwOptions & MSISOURCETYPE_URL)
454 r = OpenURLSubkey(source, &subkey, FALSE);
456 if (r != ERROR_SUCCESS)
458 r = ERROR_NO_MORE_ITEMS;
459 goto done;
462 sprintfW(name, format, dwIndex + 1);
464 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
465 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
466 r = ERROR_NO_MORE_ITEMS;
468 done:
469 RegCloseKey(subkey);
470 RegCloseKey(source);
472 if (r == ERROR_SUCCESS)
474 if (szSource || !pcchSource) index++;
476 else if (dwIndex > index)
477 index = 0;
479 return r;
482 /******************************************************************
483 * MsiSourceListGetInfoA (MSI.@)
485 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
486 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
487 LPCSTR szProperty, LPSTR szValue,
488 LPDWORD pcchValue)
490 UINT ret;
491 LPWSTR product = NULL;
492 LPWSTR usersid = NULL;
493 LPWSTR property = NULL;
494 LPWSTR value = NULL;
495 DWORD len = 0;
497 if (szValue && !pcchValue)
498 return ERROR_INVALID_PARAMETER;
500 if (szProduct) product = strdupAtoW(szProduct);
501 if (szUserSid) usersid = strdupAtoW(szUserSid);
502 if (szProperty) property = strdupAtoW(szProperty);
504 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
505 property, NULL, &len);
506 if (ret != ERROR_SUCCESS)
507 goto done;
509 value = msi_alloc(++len * sizeof(WCHAR));
510 if (!value)
511 return ERROR_OUTOFMEMORY;
513 *value = '\0';
514 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
515 property, value, &len);
516 if (ret != ERROR_SUCCESS)
517 goto done;
519 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
520 if (*pcchValue >= len)
521 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
522 else if (szValue)
523 ret = ERROR_MORE_DATA;
525 *pcchValue = len - 1;
527 done:
528 msi_free(product);
529 msi_free(usersid);
530 msi_free(property);
531 msi_free(value);
532 return ret;
535 /******************************************************************
536 * MsiSourceListGetInfoW (MSI.@)
538 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
539 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
540 LPCWSTR szProperty, LPWSTR szValue,
541 LPDWORD pcchValue)
543 static const WCHAR mediapack[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0};
544 WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE];
545 HKEY sourcekey, media;
546 DWORD size;
547 UINT rc;
549 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
551 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
552 return ERROR_INVALID_PARAMETER;
554 if (szValue && !pcchValue)
555 return ERROR_INVALID_PARAMETER;
557 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
558 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
559 dwContext != MSIINSTALLCONTEXT_MACHINE)
560 return ERROR_INVALID_PARAMETER;
562 if (!szProperty)
563 return ERROR_INVALID_PARAMETER;
565 if (szUserSid)
566 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
568 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
569 if (rc != ERROR_SUCCESS)
570 return rc;
572 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
573 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
575 rc = OpenMediaSubkey(sourcekey, &media, FALSE);
576 if (rc != ERROR_SUCCESS)
578 RegCloseKey(sourcekey);
579 return ERROR_SUCCESS;
582 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
583 szProperty = mediapack;
585 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
586 RegCloseKey(media);
588 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
589 !strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
591 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
592 0, 0, NULL, &size);
593 if (rc != ERROR_SUCCESS)
595 RegCloseKey(sourcekey);
596 return ERROR_SUCCESS;
599 source = msi_alloc(size);
600 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
601 0, 0, (LPBYTE)source, &size);
603 if (!*source)
605 msi_free(source);
606 RegCloseKey(sourcekey);
607 return ERROR_SUCCESS;
610 if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
612 if (*source != 'n' && *source != 'u' && *source != 'm')
614 msi_free(source);
615 RegCloseKey(sourcekey);
616 return ERROR_SUCCESS;
619 ptr = source;
620 source[1] = '\0';
622 else
624 ptr = strrchrW(source, ';');
625 if (!ptr)
626 ptr = source;
627 else
628 ptr++;
631 if (szValue)
633 if (strlenW(ptr) < *pcchValue)
634 lstrcpyW(szValue, ptr);
635 else
636 rc = ERROR_MORE_DATA;
639 *pcchValue = lstrlenW(ptr);
640 msi_free(source);
642 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
644 *pcchValue = *pcchValue * sizeof(WCHAR);
645 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
646 (LPBYTE)szValue, pcchValue);
647 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
649 *pcchValue = 0;
650 rc = ERROR_SUCCESS;
652 else
654 if (*pcchValue)
655 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
656 if (szValue)
657 szValue[*pcchValue] = '\0';
660 else
662 FIXME("Unknown property %s\n",debugstr_w(szProperty));
663 rc = ERROR_UNKNOWN_PROPERTY;
666 RegCloseKey(sourcekey);
667 return rc;
670 /******************************************************************
671 * MsiSourceListSetInfoA (MSI.@)
673 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
674 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
675 LPCSTR szProperty, LPCSTR szValue)
677 UINT ret;
678 LPWSTR product = NULL;
679 LPWSTR usersid = NULL;
680 LPWSTR property = NULL;
681 LPWSTR value = NULL;
683 if (szProduct) product = strdupAtoW(szProduct);
684 if (szUserSid) usersid = strdupAtoW(szUserSid);
685 if (szProperty) property = strdupAtoW(szProperty);
686 if (szValue) value = strdupAtoW(szValue);
688 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
689 property, value);
691 msi_free(product);
692 msi_free(usersid);
693 msi_free(property);
694 msi_free(value);
696 return ret;
699 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
700 MSIINSTALLCONTEXT context, DWORD options,
701 LPCWSTR value)
703 HKEY source;
704 LPWSTR buffer;
705 WCHAR typechar;
706 DWORD size;
707 UINT r;
708 int index = 1;
710 static const WCHAR format[] = {'%','c',';','%','i',';','%','s',0};
712 if (options & MSISOURCETYPE_NETWORK)
713 typechar = 'n';
714 else if (options & MSISOURCETYPE_URL)
715 typechar = 'u';
716 else if (options & MSISOURCETYPE_MEDIA)
717 typechar = 'm';
718 else
719 return ERROR_INVALID_PARAMETER;
721 if (!(options & MSISOURCETYPE_MEDIA))
723 r = MsiSourceListAddSourceExW(product, usersid, context,
724 options, value, 0);
725 if (r != ERROR_SUCCESS)
726 return r;
728 index = 0;
729 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
730 index, NULL, NULL)) == ERROR_SUCCESS)
731 index++;
733 if (r != ERROR_NO_MORE_ITEMS)
734 return r;
737 size = (lstrlenW(format) + lstrlenW(value) + 7) * sizeof(WCHAR);
738 buffer = msi_alloc(size);
739 if (!buffer)
740 return ERROR_OUTOFMEMORY;
742 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
743 if (r != ERROR_SUCCESS)
745 msi_free(buffer);
746 return r;
749 sprintfW(buffer, format, typechar, index, value);
751 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
752 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
753 REG_SZ, (LPBYTE)buffer, size);
754 msi_free(buffer);
756 RegCloseKey(source);
757 return r;
760 /******************************************************************
761 * MsiSourceListSetInfoW (MSI.@)
763 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
764 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
765 LPCWSTR szProperty, LPCWSTR szValue)
767 static const WCHAR media_package[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0};
768 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
769 HKEY sourcekey, media;
770 LPCWSTR property;
771 UINT rc;
773 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
774 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
776 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
777 return ERROR_INVALID_PARAMETER;
779 if (!szProperty)
780 return ERROR_INVALID_PARAMETER;
782 if (!szValue)
783 return ERROR_UNKNOWN_PROPERTY;
785 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
786 return ERROR_INVALID_PARAMETER;
788 if (dwOptions & MSICODE_PATCH)
790 FIXME("Unhandled options MSICODE_PATCH\n");
791 return ERROR_UNKNOWN_PATCH;
794 property = szProperty;
795 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
796 property = media_package;
798 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
799 if (rc != ERROR_SUCCESS)
800 return rc;
802 if (strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
803 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
805 RegCloseKey(sourcekey);
806 return ERROR_INVALID_PARAMETER;
809 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
810 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
812 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
813 if (rc == ERROR_SUCCESS)
815 rc = msi_reg_set_val_str(media, property, szValue);
816 RegCloseKey(media);
819 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
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;
827 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
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);
835 else
836 rc = ERROR_UNKNOWN_PROPERTY;
838 RegCloseKey(sourcekey);
839 return rc;
842 /******************************************************************
843 * MsiSourceListAddSourceW (MSI.@)
845 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
846 DWORD dwReserved, LPCWSTR szSource)
848 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
849 INT ret;
850 DWORD sidsize = 0, domsize = 0, context;
851 HKEY hkey = 0;
852 UINT r;
854 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
856 if (!szSource || !*szSource)
857 return ERROR_INVALID_PARAMETER;
859 if (dwReserved != 0)
860 return ERROR_INVALID_PARAMETER;
862 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
863 return ERROR_INVALID_PARAMETER;
865 if (!szUserName || !*szUserName)
866 context = MSIINSTALLCONTEXT_MACHINE;
867 else
869 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
871 PSID psid = msi_alloc(sidsize);
873 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
874 ConvertSidToStringSidW(psid, &sidstr);
876 msi_free(psid);
879 r = MSIREG_OpenProductKey(szProduct, NULL,
880 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
881 if (r == ERROR_SUCCESS)
882 context = MSIINSTALLCONTEXT_USERMANAGED;
883 else
885 r = MSIREG_OpenProductKey(szProduct, NULL,
886 MSIINSTALLCONTEXT_USERUNMANAGED,
887 &hkey, FALSE);
888 if (r != ERROR_SUCCESS)
889 return ERROR_UNKNOWN_PRODUCT;
891 context = MSIINSTALLCONTEXT_USERUNMANAGED;
894 RegCloseKey(hkey);
897 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
898 context, MSISOURCETYPE_NETWORK, szSource, 0);
900 if (sidstr)
901 LocalFree(sidstr);
903 return ret;
906 /******************************************************************
907 * MsiSourceListAddSourceA (MSI.@)
909 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
910 DWORD dwReserved, LPCSTR szSource)
912 INT ret;
913 LPWSTR szwproduct;
914 LPWSTR szwusername;
915 LPWSTR szwsource;
917 szwproduct = strdupAtoW( szProduct );
918 szwusername = strdupAtoW( szUserName );
919 szwsource = strdupAtoW( szSource );
921 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
923 msi_free(szwproduct);
924 msi_free(szwusername);
925 msi_free(szwsource);
927 return ret;
930 /******************************************************************
931 * MsiSourceListAddSourceExA (MSI.@)
933 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
934 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
936 UINT ret;
937 LPWSTR product, usersid, source;
939 product = strdupAtoW(szProduct);
940 usersid = strdupAtoW(szUserSid);
941 source = strdupAtoW(szSource);
943 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
944 dwOptions, source, dwIndex);
946 msi_free(product);
947 msi_free(usersid);
948 msi_free(source);
950 return ret;
953 static void free_source_list(struct list *sourcelist)
955 while (!list_empty(sourcelist))
957 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
958 list_remove(&info->entry);
959 msi_free(info->path);
960 msi_free(info);
964 static void add_source_to_list(struct list *sourcelist, media_info *info,
965 DWORD *index)
967 media_info *iter;
968 BOOL found = FALSE;
969 static const WCHAR fmt[] = {'%','i',0};
971 if (index) *index = 0;
973 if (list_empty(sourcelist))
975 list_add_head(sourcelist, &info->entry);
976 return;
979 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
981 if (!found && info->index < iter->index)
983 found = TRUE;
984 list_add_before(&iter->entry, &info->entry);
987 /* update the rest of the list */
988 if (found)
989 sprintfW(iter->szIndex, fmt, ++iter->index);
990 else if (index)
991 (*index)++;
994 if (!found)
995 list_add_after(&iter->entry, &info->entry);
998 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
1000 UINT r = ERROR_SUCCESS;
1001 DWORD index = 0;
1002 WCHAR name[10];
1003 DWORD size, val_size;
1004 media_info *entry;
1006 *count = 0;
1008 while (r == ERROR_SUCCESS)
1010 size = ARRAY_SIZE(name);
1011 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
1012 if (r != ERROR_SUCCESS)
1013 return r;
1015 entry = msi_alloc(sizeof(media_info));
1016 if (!entry)
1017 goto error;
1019 entry->path = msi_alloc(val_size);
1020 if (!entry->path)
1022 msi_free(entry);
1023 goto error;
1026 lstrcpyW(entry->szIndex, name);
1027 entry->index = atoiW(name);
1029 size++;
1030 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1031 NULL, (LPBYTE)entry->path, &val_size);
1032 if (r != ERROR_SUCCESS)
1034 msi_free(entry->path);
1035 msi_free(entry);
1036 goto error;
1039 index = ++(*count);
1040 add_source_to_list(sourcelist, entry, NULL);
1043 error:
1044 *count = -1;
1045 free_source_list(sourcelist);
1046 return ERROR_OUTOFMEMORY;
1049 /******************************************************************
1050 * MsiSourceListAddSourceExW (MSI.@)
1052 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1053 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
1054 DWORD dwIndex)
1056 static const WCHAR fmt[] = {'%','i',0};
1057 HKEY sourcekey, typekey;
1058 UINT rc;
1059 struct list sourcelist;
1060 media_info *info;
1061 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1062 LPCWSTR postfix;
1063 DWORD size, count, index;
1065 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1066 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
1068 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1069 return ERROR_INVALID_PARAMETER;
1071 if (!szSource || !*szSource)
1072 return ERROR_INVALID_PARAMETER;
1074 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1075 return ERROR_INVALID_PARAMETER;
1077 if (dwOptions & MSICODE_PATCH)
1079 FIXME("Unhandled options MSICODE_PATCH\n");
1080 return ERROR_FUNCTION_FAILED;
1083 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1084 return ERROR_INVALID_PARAMETER;
1086 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1087 if (rc != ERROR_SUCCESS)
1088 return rc;
1090 if (dwOptions & MSISOURCETYPE_NETWORK)
1091 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1092 else if (dwOptions & MSISOURCETYPE_URL)
1093 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1094 else if (dwOptions & MSISOURCETYPE_MEDIA)
1095 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1096 else
1098 ERR("unknown media type: %08x\n", dwOptions);
1099 RegCloseKey(sourcekey);
1100 return ERROR_FUNCTION_FAILED;
1102 if (rc != ERROR_SUCCESS)
1104 ERR("can't open subkey %u\n", rc);
1105 RegCloseKey(sourcekey);
1106 return rc;
1109 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? szBackSlash : szForwardSlash;
1110 if (szSource[lstrlenW(szSource) - 1] == *postfix)
1111 source = strdupW(szSource);
1112 else
1114 size = lstrlenW(szSource) + 2;
1115 source = msi_alloc(size * sizeof(WCHAR));
1116 lstrcpyW(source, szSource);
1117 lstrcatW(source, postfix);
1120 list_init(&sourcelist);
1121 rc = fill_source_list(&sourcelist, typekey, &count);
1122 if (rc != ERROR_NO_MORE_ITEMS)
1123 goto done;
1125 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1127 if (count == 0)
1129 rc = RegSetValueExW(typekey, szOne, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1130 goto done;
1132 else if (dwIndex > count || dwIndex == 0)
1134 sprintfW(name, fmt, count + 1);
1135 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1136 goto done;
1138 else
1140 sprintfW(name, fmt, dwIndex);
1141 info = msi_alloc(sizeof(media_info));
1142 if (!info)
1144 rc = ERROR_OUTOFMEMORY;
1145 goto done;
1148 info->path = strdupW(source);
1149 lstrcpyW(info->szIndex, name);
1150 info->index = dwIndex;
1151 add_source_to_list(&sourcelist, info, &index);
1153 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
1155 if (info->index < index)
1156 continue;
1158 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1159 rc = RegSetValueExW(typekey, info->szIndex, 0,
1160 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1161 if (rc != ERROR_SUCCESS)
1162 goto done;
1166 done:
1167 free_source_list(&sourcelist);
1168 msi_free(source);
1169 RegCloseKey(typekey);
1170 RegCloseKey(sourcekey);
1171 return rc;
1174 /******************************************************************
1175 * MsiSourceListAddMediaDiskA (MSI.@)
1177 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1178 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1179 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1181 UINT r;
1182 LPWSTR product = NULL;
1183 LPWSTR usersid = NULL;
1184 LPWSTR volume = NULL;
1185 LPWSTR prompt = NULL;
1187 if (szProduct) product = strdupAtoW(szProduct);
1188 if (szUserSid) usersid = strdupAtoW(szUserSid);
1189 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1190 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1192 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1193 dwDiskId, volume, prompt);
1195 msi_free(product);
1196 msi_free(usersid);
1197 msi_free(volume);
1198 msi_free(prompt);
1200 return r;
1203 /******************************************************************
1204 * MsiSourceListAddMediaDiskW (MSI.@)
1206 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
1207 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1208 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
1210 static const WCHAR fmt[] = {'%','i',0};
1211 HKEY sourcekey, mediakey;
1212 UINT rc;
1213 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1214 DWORD size;
1216 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
1217 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
1218 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
1220 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1221 return ERROR_INVALID_PARAMETER;
1223 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1224 return ERROR_INVALID_PARAMETER;
1226 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1227 return ERROR_INVALID_PARAMETER;
1229 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1230 return ERROR_INVALID_PARAMETER;
1232 if (dwOptions & MSICODE_PATCH)
1234 FIXME("Unhandled options MSICODE_PATCH\n");
1235 return ERROR_FUNCTION_FAILED;
1238 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1239 if (rc != ERROR_SUCCESS)
1240 return rc;
1242 OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1244 sprintfW(szIndex, fmt, dwDiskId);
1246 size = 2;
1247 if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1248 if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1250 size *= sizeof(WCHAR);
1251 buffer = msi_alloc(size);
1252 *buffer = '\0';
1254 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1255 lstrcatW(buffer, szSemiColon);
1256 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1258 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1259 msi_free(buffer);
1261 RegCloseKey(sourcekey);
1262 RegCloseKey(mediakey);
1264 return ERROR_SUCCESS;
1267 /******************************************************************
1268 * MsiSourceListClearAllA (MSI.@)
1270 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
1272 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
1273 return ERROR_SUCCESS;
1276 /******************************************************************
1277 * MsiSourceListClearAllW (MSI.@)
1279 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
1281 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
1282 return ERROR_SUCCESS;
1285 /******************************************************************
1286 * MsiSourceListClearAllExA (MSI.@)
1288 UINT WINAPI MsiSourceListClearAllExA( LPCSTR szProduct, LPCSTR szUserSid,
1289 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1291 FIXME("(%s %s %d %08x)\n", debugstr_a(szProduct), debugstr_a(szUserSid),
1292 dwContext, dwOptions);
1293 return ERROR_SUCCESS;
1296 /******************************************************************
1297 * MsiSourceListClearAllExW (MSI.@)
1299 UINT WINAPI MsiSourceListClearAllExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1300 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1302 FIXME("(%s %s %d %08x)\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1303 dwContext, dwOptions);
1304 return ERROR_SUCCESS;
1307 /******************************************************************
1308 * MsiSourceListClearSourceA (MSI.@)
1310 UINT WINAPI MsiSourceListClearSourceA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid,
1311 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1312 LPCSTR szSource)
1314 FIXME("(%s %s %x %x %s)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid),
1315 dwContext, dwOptions, debugstr_a(szSource));
1316 return ERROR_SUCCESS;
1319 /******************************************************************
1320 * MsiSourceListClearSourceW (MSI.@)
1322 UINT WINAPI MsiSourceListClearSourceW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid,
1323 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1324 LPCWSTR szSource)
1326 FIXME("(%s %s %x %x %s)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid),
1327 dwContext, dwOptions, debugstr_w(szSource));
1328 return ERROR_SUCCESS;