mf/session: Implement support for sinks that provide sample allocators.
[wine.git] / dlls / msi / source.c
blobb4b3b54fe35f247a70a59a74b6e7313235adedce
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 "sddl.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 * These apis are defined in MSI 3.0
45 typedef struct tagMediaInfo
47 struct list entry;
48 LPWSTR path;
49 WCHAR szIndex[10];
50 DWORD index;
51 } media_info;
53 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
54 MSIINSTALLCONTEXT context, BOOL create)
56 HKEY rootkey = 0;
57 UINT rc = ERROR_FUNCTION_FAILED;
59 if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
61 if (dwOptions & MSICODE_PATCH)
62 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
63 else
64 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
65 &rootkey, create);
67 else if (context == MSIINSTALLCONTEXT_USERMANAGED)
69 if (dwOptions & MSICODE_PATCH)
70 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
71 else
72 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
73 &rootkey, create);
75 else if (context == MSIINSTALLCONTEXT_MACHINE)
77 if (dwOptions & MSICODE_PATCH)
78 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
79 else
80 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
81 &rootkey, create);
84 if (rc != ERROR_SUCCESS)
86 if (dwOptions & MSICODE_PATCH)
87 return ERROR_UNKNOWN_PATCH;
88 else
89 return ERROR_UNKNOWN_PRODUCT;
92 if (create)
93 rc = RegCreateKeyW(rootkey, L"SourceList", key);
94 else
96 rc = RegOpenKeyW(rootkey, L"SourceList", key);
97 if (rc != ERROR_SUCCESS)
98 rc = ERROR_BAD_CONFIGURATION;
100 RegCloseKey(rootkey);
102 return rc;
105 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
107 UINT rc;
109 if (create)
110 rc = RegCreateKeyW(rootkey, L"Media", key);
111 else
112 rc = RegOpenKeyW(rootkey, L"Media", key);
114 return rc;
117 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
119 UINT rc;
121 if (create)
122 rc = RegCreateKeyW(rootkey, L"Net", key);
123 else
124 rc = RegOpenKeyW(rootkey, L"Net", key);
126 return rc;
129 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
131 UINT rc;
133 if (create)
134 rc = RegCreateKeyW(rootkey, L"URL", key);
135 else
136 rc = RegOpenKeyW(rootkey, L"URL", key);
138 return rc;
141 /******************************************************************
142 * MsiSourceListEnumMediaDisksA (MSI.@)
144 UINT WINAPI MsiSourceListEnumMediaDisksA(LPCSTR szProductCodeOrPatchCode,
145 LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
146 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
147 LPSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
148 LPSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
150 LPWSTR product = NULL;
151 LPWSTR usersid = NULL;
152 LPWSTR volume = NULL;
153 LPWSTR prompt = NULL;
154 UINT r = ERROR_INVALID_PARAMETER;
156 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n", debugstr_a(szProductCodeOrPatchCode),
157 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId,
158 szVolumeLabel, pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
160 if (szDiskPrompt && !pcchDiskPrompt)
161 return ERROR_INVALID_PARAMETER;
163 if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode);
164 if (szUserSid) usersid = strdupAtoW(szUserSid);
166 /* FIXME: add tests for an invalid format */
168 if (pcchVolumeLabel)
169 volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR));
171 if (pcchDiskPrompt)
172 prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR));
174 if (volume) *volume = '\0';
175 if (prompt) *prompt = '\0';
176 r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions,
177 dwIndex, pdwDiskId, volume, pcchVolumeLabel,
178 prompt, pcchDiskPrompt);
179 if (r != ERROR_SUCCESS)
180 goto done;
182 if (szVolumeLabel && pcchVolumeLabel)
183 WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel,
184 *pcchVolumeLabel + 1, NULL, NULL);
186 if (szDiskPrompt)
187 WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt,
188 *pcchDiskPrompt + 1, NULL, NULL);
190 done:
191 msi_free(product);
192 msi_free(usersid);
193 msi_free(volume);
194 msi_free(prompt);
196 return r;
199 /******************************************************************
200 * MsiSourceListEnumMediaDisksW (MSI.@)
202 UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
203 LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
204 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId,
205 LPWSTR szVolumeLabel, LPDWORD pcchVolumeLabel,
206 LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
208 WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11];
209 WCHAR *value = NULL, *data = NULL, *ptr, *ptr2;
210 HKEY source, media;
211 DWORD valuesz, datasz = 0, type, numvals, size;
212 LONG res;
213 UINT r;
214 static DWORD index = 0;
216 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p)\n", debugstr_w(szProductCodeOrPatchCode),
217 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel,
218 pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt);
220 if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc ))
221 return ERROR_INVALID_PARAMETER;
223 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
224 return ERROR_INVALID_PARAMETER;
226 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
227 return ERROR_INVALID_PARAMETER;
229 if (szDiskPrompt && !pcchDiskPrompt)
230 return ERROR_INVALID_PARAMETER;
232 if (dwIndex == 0)
233 index = 0;
235 if (dwIndex != index)
236 return ERROR_INVALID_PARAMETER;
238 r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE);
239 if (r != ERROR_SUCCESS)
240 return r;
242 r = OpenMediaSubkey(source, &media, FALSE);
243 if (r != ERROR_SUCCESS)
245 RegCloseKey(source);
246 return ERROR_NO_MORE_ITEMS;
249 res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
250 NULL, &numvals, &valuesz, &datasz, NULL, NULL);
251 if (res != ERROR_SUCCESS)
253 r = ERROR_BAD_CONFIGURATION;
254 goto done;
257 value = msi_alloc(++valuesz * sizeof(WCHAR));
258 data = msi_alloc(++datasz * sizeof(WCHAR));
259 if (!value || !data)
261 r = ERROR_OUTOFMEMORY;
262 goto done;
265 r = RegEnumValueW(media, dwIndex, value, &valuesz,
266 NULL, &type, (LPBYTE)data, &datasz);
267 if (r != ERROR_SUCCESS)
268 goto done;
270 if (pdwDiskId)
271 *pdwDiskId = wcstol(value, NULL, 10);
273 ptr2 = data;
274 ptr = wcschr(data, ';');
275 if (!ptr)
276 ptr = data;
277 else
278 *ptr = '\0';
280 if (pcchVolumeLabel)
282 if (type == REG_DWORD)
284 swprintf(convert, ARRAY_SIZE(convert), L"#%d", *data);
285 size = lstrlenW(convert);
286 ptr2 = convert;
288 else
289 size = lstrlenW(data);
291 if (size >= *pcchVolumeLabel)
292 r = ERROR_MORE_DATA;
293 else if (szVolumeLabel)
294 lstrcpyW(szVolumeLabel, ptr2);
296 *pcchVolumeLabel = size;
299 if (pcchDiskPrompt)
301 if (!*ptr)
302 ptr++;
304 if (type == REG_DWORD)
306 swprintf(convert, ARRAY_SIZE(convert), L"#%d", *ptr);
307 size = lstrlenW(convert);
308 ptr = convert;
310 else
311 size = lstrlenW(ptr);
313 if (size >= *pcchDiskPrompt)
314 r = ERROR_MORE_DATA;
315 else if (szDiskPrompt)
316 lstrcpyW(szDiskPrompt, ptr);
318 *pcchDiskPrompt = size;
321 index++;
323 done:
324 msi_free(value);
325 msi_free(data);
326 RegCloseKey(source);
328 return r;
331 /******************************************************************
332 * MsiSourceListEnumSourcesA (MSI.@)
334 UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid,
335 MSIINSTALLCONTEXT dwContext,
336 DWORD dwOptions, DWORD dwIndex,
337 LPSTR szSource, LPDWORD pcchSource)
339 LPWSTR product = NULL;
340 LPWSTR usersid = NULL;
341 LPWSTR source = NULL;
342 DWORD len = 0;
343 UINT r = ERROR_INVALID_PARAMETER;
344 static DWORD index = 0;
346 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch),
347 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
349 if (dwIndex == 0)
350 index = 0;
352 if (szSource && !pcchSource)
353 goto done;
355 if (dwIndex != index)
356 goto done;
358 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
359 if (szUserSid) usersid = strdupAtoW(szUserSid);
361 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
362 dwIndex, NULL, &len);
363 if (r != ERROR_SUCCESS)
364 goto done;
366 source = msi_alloc(++len * sizeof(WCHAR));
367 if (!source)
369 r = ERROR_OUTOFMEMORY;
370 goto done;
373 *source = '\0';
374 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
375 dwIndex, source, &len);
376 if (r != ERROR_SUCCESS)
377 goto done;
379 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
380 if (pcchSource && *pcchSource >= len)
381 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
382 else if (szSource)
383 r = ERROR_MORE_DATA;
385 if (pcchSource)
386 *pcchSource = len - 1;
388 done:
389 msi_free(product);
390 msi_free(usersid);
391 msi_free(source);
393 if (r == ERROR_SUCCESS)
395 if (szSource || !pcchSource) index++;
397 else if (dwIndex > index)
398 index = 0;
400 return r;
403 /******************************************************************
404 * MsiSourceListEnumSourcesW (MSI.@)
406 UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid,
407 MSIINSTALLCONTEXT dwContext,
408 DWORD dwOptions, DWORD dwIndex,
409 LPWSTR szSource, LPDWORD pcchSource)
411 WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32];
412 HKEY source = NULL, subkey = NULL;
413 LONG res;
414 UINT r = ERROR_INVALID_PARAMETER;
415 static DWORD index = 0;
417 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch),
418 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
420 if (dwIndex == 0)
421 index = 0;
423 if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc ))
424 goto done;
426 if (szSource && !pcchSource)
427 goto done;
429 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
430 goto done;
432 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
433 goto done;
435 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
436 goto done;
438 if (dwIndex != index)
439 goto done;
441 r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE );
442 if (r != ERROR_SUCCESS)
443 goto done;
445 if (dwOptions & MSISOURCETYPE_NETWORK)
446 r = OpenNetworkSubkey(source, &subkey, FALSE);
447 else if (dwOptions & MSISOURCETYPE_URL)
448 r = OpenURLSubkey(source, &subkey, FALSE);
450 if (r != ERROR_SUCCESS)
452 r = ERROR_NO_MORE_ITEMS;
453 goto done;
456 swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex + 1);
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;
462 done:
463 RegCloseKey(subkey);
464 RegCloseKey(source);
466 if (r == ERROR_SUCCESS)
468 if (szSource || !pcchSource) index++;
470 else if (dwIndex > index)
471 index = 0;
473 return r;
476 /******************************************************************
477 * MsiSourceListGetInfoA (MSI.@)
479 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
480 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
481 LPCSTR szProperty, LPSTR szValue,
482 LPDWORD pcchValue)
484 UINT ret;
485 LPWSTR product = NULL;
486 LPWSTR usersid = NULL;
487 LPWSTR property = NULL;
488 LPWSTR value = NULL;
489 DWORD len = 0;
491 if (szValue && !pcchValue)
492 return ERROR_INVALID_PARAMETER;
494 if (szProduct) product = strdupAtoW(szProduct);
495 if (szUserSid) usersid = strdupAtoW(szUserSid);
496 if (szProperty) property = strdupAtoW(szProperty);
498 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
499 property, NULL, &len);
500 if (ret != ERROR_SUCCESS)
501 goto done;
503 value = msi_alloc(++len * sizeof(WCHAR));
504 if (!value)
505 return ERROR_OUTOFMEMORY;
507 *value = '\0';
508 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
509 property, value, &len);
510 if (ret != ERROR_SUCCESS)
511 goto done;
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;
519 *pcchValue = len - 1;
521 done:
522 msi_free(product);
523 msi_free(usersid);
524 msi_free(property);
525 msi_free(value);
526 return ret;
529 /******************************************************************
530 * MsiSourceListGetInfoW (MSI.@)
532 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
533 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
534 LPCWSTR szProperty, LPWSTR szValue,
535 LPDWORD pcchValue)
537 WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE];
538 HKEY sourcekey, media;
539 DWORD size;
540 UINT rc;
542 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
544 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
545 return ERROR_INVALID_PARAMETER;
547 if (szValue && !pcchValue)
548 return ERROR_INVALID_PARAMETER;
550 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
551 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
552 dwContext != MSIINSTALLCONTEXT_MACHINE)
553 return ERROR_INVALID_PARAMETER;
555 if (!szProperty)
556 return ERROR_INVALID_PARAMETER;
558 if (szUserSid)
559 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
561 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
562 if (rc != ERROR_SUCCESS)
563 return rc;
565 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
566 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
568 rc = OpenMediaSubkey(sourcekey, &media, FALSE);
569 if (rc != ERROR_SUCCESS)
571 RegCloseKey(sourcekey);
572 return ERROR_SUCCESS;
575 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
576 szProperty = L"MediaPackage";
578 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
579 RegCloseKey(media);
581 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
582 !wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
584 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
585 0, 0, NULL, &size);
586 if (rc != ERROR_SUCCESS)
588 static WCHAR szEmpty[] = {0};
589 rc = ERROR_SUCCESS;
590 source = NULL;
591 ptr = szEmpty;
592 goto output_out;
595 source = msi_alloc(size);
596 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
597 0, 0, (LPBYTE)source, &size);
599 if (!*source)
601 msi_free(source);
602 RegCloseKey(sourcekey);
603 return ERROR_SUCCESS;
606 if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
608 if (*source != 'n' && *source != 'u' && *source != 'm')
610 msi_free(source);
611 RegCloseKey(sourcekey);
612 return ERROR_SUCCESS;
615 ptr = source;
616 source[1] = '\0';
618 else
620 ptr = wcsrchr(source, ';');
621 if (!ptr)
622 ptr = source;
623 else
624 ptr++;
626 output_out:
627 if (szValue)
629 if (lstrlenW(ptr) < *pcchValue)
630 lstrcpyW(szValue, ptr);
631 else
632 rc = ERROR_MORE_DATA;
635 *pcchValue = lstrlenW(ptr);
636 msi_free(source);
638 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
640 *pcchValue = *pcchValue * sizeof(WCHAR);
641 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
642 (LPBYTE)szValue, pcchValue);
643 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
645 *pcchValue = 0;
646 rc = ERROR_SUCCESS;
648 else
650 if (*pcchValue)
651 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
652 if (szValue)
653 szValue[*pcchValue] = '\0';
656 else
658 FIXME("Unknown property %s\n",debugstr_w(szProperty));
659 rc = ERROR_UNKNOWN_PROPERTY;
662 RegCloseKey(sourcekey);
663 return rc;
666 /******************************************************************
667 * MsiSourceListSetInfoA (MSI.@)
669 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
670 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
671 LPCSTR szProperty, LPCSTR szValue)
673 UINT ret;
674 LPWSTR product = NULL;
675 LPWSTR usersid = NULL;
676 LPWSTR property = NULL;
677 LPWSTR value = NULL;
679 if (szProduct) product = strdupAtoW(szProduct);
680 if (szUserSid) usersid = strdupAtoW(szUserSid);
681 if (szProperty) property = strdupAtoW(szProperty);
682 if (szValue) value = strdupAtoW(szValue);
684 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
685 property, value);
687 msi_free(product);
688 msi_free(usersid);
689 msi_free(property);
690 msi_free(value);
692 return ret;
695 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
696 MSIINSTALLCONTEXT context, DWORD options,
697 LPCWSTR value)
699 HKEY source;
700 LPWSTR buffer;
701 WCHAR typechar;
702 DWORD size;
703 UINT r;
704 int index = 1;
706 if (options & MSISOURCETYPE_NETWORK)
707 typechar = 'n';
708 else if (options & MSISOURCETYPE_URL)
709 typechar = 'u';
710 else if (options & MSISOURCETYPE_MEDIA)
711 typechar = 'm';
712 else
713 return ERROR_INVALID_PARAMETER;
715 if (!(options & MSISOURCETYPE_MEDIA))
717 r = MsiSourceListAddSourceExW(product, usersid, context,
718 options, value, 0);
719 if (r != ERROR_SUCCESS)
720 return r;
722 index = 0;
723 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
724 index, NULL, NULL)) == ERROR_SUCCESS)
725 index++;
727 if (r != ERROR_NO_MORE_ITEMS)
728 return r;
731 size = lstrlenW(L"%c;%d;%s") + lstrlenW(value) + 7;
732 buffer = msi_alloc(size * sizeof(WCHAR));
733 if (!buffer)
734 return ERROR_OUTOFMEMORY;
736 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
737 if (r != ERROR_SUCCESS)
739 msi_free(buffer);
740 return r;
743 swprintf(buffer, size, L"%c;%d;%s", typechar, index, value);
745 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
746 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
747 REG_SZ, (LPBYTE)buffer, size);
748 msi_free(buffer);
750 RegCloseKey(source);
751 return r;
754 /******************************************************************
755 * MsiSourceListSetInfoW (MSI.@)
757 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
758 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
759 LPCWSTR szProperty, LPCWSTR szValue)
761 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
762 HKEY sourcekey, media;
763 LPCWSTR property;
764 UINT rc;
766 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
767 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
769 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
770 return ERROR_INVALID_PARAMETER;
772 if (!szProperty)
773 return ERROR_INVALID_PARAMETER;
775 if (!szValue)
776 return ERROR_UNKNOWN_PROPERTY;
778 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
779 return ERROR_INVALID_PARAMETER;
781 if (dwOptions & MSICODE_PATCH)
783 FIXME("Unhandled options MSICODE_PATCH\n");
784 return ERROR_UNKNOWN_PATCH;
787 property = szProperty;
788 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
789 property = L"MediaPackage";
791 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
792 if (rc != ERROR_SUCCESS)
793 return rc;
795 if (wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
796 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
798 RegCloseKey(sourcekey);
799 return ERROR_INVALID_PARAMETER;
802 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
803 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
805 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
806 if (rc == ERROR_SUCCESS)
808 rc = msi_reg_set_val_str(media, property, szValue);
809 RegCloseKey(media);
812 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
814 DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
815 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
816 REG_SZ, (const BYTE *)szValue, size);
817 if (rc != ERROR_SUCCESS)
818 rc = ERROR_UNKNOWN_PROPERTY;
820 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
822 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
823 rc = ERROR_INVALID_PARAMETER;
824 else
825 rc = msi_set_last_used_source(szProduct, szUserSid, dwContext,
826 dwOptions, szValue);
828 else
829 rc = ERROR_UNKNOWN_PROPERTY;
831 RegCloseKey(sourcekey);
832 return rc;
835 /******************************************************************
836 * MsiSourceListAddSourceW (MSI.@)
838 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
839 DWORD dwReserved, LPCWSTR szSource)
841 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
842 INT ret;
843 DWORD sidsize = 0, domsize = 0, context;
844 HKEY hkey = 0;
845 UINT r;
847 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
849 if (!szSource || !*szSource)
850 return ERROR_INVALID_PARAMETER;
852 if (dwReserved != 0)
853 return ERROR_INVALID_PARAMETER;
855 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
856 return ERROR_INVALID_PARAMETER;
858 if (!szUserName || !*szUserName)
859 context = MSIINSTALLCONTEXT_MACHINE;
860 else
862 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
864 PSID psid = msi_alloc(sidsize);
866 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
867 ConvertSidToStringSidW(psid, &sidstr);
869 msi_free(psid);
872 r = MSIREG_OpenProductKey(szProduct, NULL,
873 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
874 if (r == ERROR_SUCCESS)
875 context = MSIINSTALLCONTEXT_USERMANAGED;
876 else
878 r = MSIREG_OpenProductKey(szProduct, NULL,
879 MSIINSTALLCONTEXT_USERUNMANAGED,
880 &hkey, FALSE);
881 if (r != ERROR_SUCCESS)
882 return ERROR_UNKNOWN_PRODUCT;
884 context = MSIINSTALLCONTEXT_USERUNMANAGED;
887 RegCloseKey(hkey);
890 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
891 context, MSISOURCETYPE_NETWORK, szSource, 0);
893 if (sidstr)
894 LocalFree(sidstr);
896 return ret;
899 /******************************************************************
900 * MsiSourceListAddSourceA (MSI.@)
902 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
903 DWORD dwReserved, LPCSTR szSource)
905 INT ret;
906 LPWSTR szwproduct;
907 LPWSTR szwusername;
908 LPWSTR szwsource;
910 szwproduct = strdupAtoW( szProduct );
911 szwusername = strdupAtoW( szUserName );
912 szwsource = strdupAtoW( szSource );
914 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
916 msi_free(szwproduct);
917 msi_free(szwusername);
918 msi_free(szwsource);
920 return ret;
923 /******************************************************************
924 * MsiSourceListAddSourceExA (MSI.@)
926 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
927 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
929 UINT ret;
930 LPWSTR product, usersid, source;
932 product = strdupAtoW(szProduct);
933 usersid = strdupAtoW(szUserSid);
934 source = strdupAtoW(szSource);
936 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
937 dwOptions, source, dwIndex);
939 msi_free(product);
940 msi_free(usersid);
941 msi_free(source);
943 return ret;
946 static void free_source_list(struct list *sourcelist)
948 while (!list_empty(sourcelist))
950 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
951 list_remove(&info->entry);
952 msi_free(info->path);
953 msi_free(info);
957 static void add_source_to_list(struct list *sourcelist, media_info *info,
958 DWORD *index)
960 media_info *iter;
961 BOOL found = FALSE;
963 if (index) *index = 0;
965 if (list_empty(sourcelist))
967 list_add_head(sourcelist, &info->entry);
968 return;
971 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
973 if (!found && info->index < iter->index)
975 found = TRUE;
976 list_add_before(&iter->entry, &info->entry);
979 /* update the rest of the list */
980 if (found)
981 swprintf(iter->szIndex, ARRAY_SIZE(iter->szIndex), L"%d", ++iter->index);
982 else if (index)
983 (*index)++;
986 if (!found)
987 list_add_after(&iter->entry, &info->entry);
990 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
992 UINT r = ERROR_SUCCESS;
993 DWORD index = 0;
994 WCHAR name[10];
995 DWORD size, val_size;
996 media_info *entry;
998 *count = 0;
1000 while (r == ERROR_SUCCESS)
1002 size = ARRAY_SIZE(name);
1003 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
1004 if (r != ERROR_SUCCESS)
1005 return r;
1007 entry = msi_alloc(sizeof(media_info));
1008 if (!entry)
1009 goto error;
1011 entry->path = msi_alloc(val_size);
1012 if (!entry->path)
1014 msi_free(entry);
1015 goto error;
1018 lstrcpyW(entry->szIndex, name);
1019 entry->index = wcstol(name, NULL, 10);
1021 size++;
1022 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1023 NULL, (LPBYTE)entry->path, &val_size);
1024 if (r != ERROR_SUCCESS)
1026 msi_free(entry->path);
1027 msi_free(entry);
1028 goto error;
1031 index = ++(*count);
1032 add_source_to_list(sourcelist, entry, NULL);
1035 error:
1036 *count = -1;
1037 free_source_list(sourcelist);
1038 return ERROR_OUTOFMEMORY;
1041 /******************************************************************
1042 * MsiSourceListAddSourceExW (MSI.@)
1044 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1045 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
1046 DWORD dwIndex)
1048 HKEY sourcekey, typekey;
1049 UINT rc;
1050 struct list sourcelist;
1051 media_info *info;
1052 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1053 LPCWSTR postfix;
1054 DWORD size, count, index;
1056 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1057 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
1059 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1060 return ERROR_INVALID_PARAMETER;
1062 if (!szSource || !*szSource)
1063 return ERROR_INVALID_PARAMETER;
1065 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1066 return ERROR_INVALID_PARAMETER;
1068 if (dwOptions & MSICODE_PATCH)
1070 FIXME("Unhandled options MSICODE_PATCH\n");
1071 return ERROR_FUNCTION_FAILED;
1074 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1075 return ERROR_INVALID_PARAMETER;
1077 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1078 if (rc != ERROR_SUCCESS)
1079 return rc;
1081 if (dwOptions & MSISOURCETYPE_NETWORK)
1082 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1083 else if (dwOptions & MSISOURCETYPE_URL)
1084 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1085 else if (dwOptions & MSISOURCETYPE_MEDIA)
1086 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1087 else
1089 ERR("unknown media type: %08x\n", dwOptions);
1090 RegCloseKey(sourcekey);
1091 return ERROR_FUNCTION_FAILED;
1093 if (rc != ERROR_SUCCESS)
1095 ERR("can't open subkey %u\n", rc);
1096 RegCloseKey(sourcekey);
1097 return rc;
1100 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? L"\\" : L"/";
1101 if (szSource[lstrlenW(szSource) - 1] == *postfix)
1102 source = strdupW(szSource);
1103 else
1105 size = lstrlenW(szSource) + 2;
1106 source = msi_alloc(size * sizeof(WCHAR));
1107 lstrcpyW(source, szSource);
1108 lstrcatW(source, postfix);
1111 list_init(&sourcelist);
1112 rc = fill_source_list(&sourcelist, typekey, &count);
1113 if (rc != ERROR_NO_MORE_ITEMS)
1114 goto done;
1116 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1118 if (count == 0)
1120 rc = RegSetValueExW(typekey, L"1", 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1121 goto done;
1123 else if (dwIndex > count || dwIndex == 0)
1125 swprintf(name, ARRAY_SIZE(name), L"%d", count + 1);
1126 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1127 goto done;
1129 else
1131 swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex);
1132 info = msi_alloc(sizeof(media_info));
1133 if (!info)
1135 rc = ERROR_OUTOFMEMORY;
1136 goto done;
1139 info->path = strdupW(source);
1140 lstrcpyW(info->szIndex, name);
1141 info->index = dwIndex;
1142 add_source_to_list(&sourcelist, info, &index);
1144 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
1146 if (info->index < index)
1147 continue;
1149 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1150 rc = RegSetValueExW(typekey, info->szIndex, 0,
1151 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1152 if (rc != ERROR_SUCCESS)
1153 goto done;
1157 done:
1158 free_source_list(&sourcelist);
1159 msi_free(source);
1160 RegCloseKey(typekey);
1161 RegCloseKey(sourcekey);
1162 return rc;
1165 /******************************************************************
1166 * MsiSourceListAddMediaDiskA (MSI.@)
1168 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1169 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1170 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1172 UINT r;
1173 LPWSTR product = NULL;
1174 LPWSTR usersid = NULL;
1175 LPWSTR volume = NULL;
1176 LPWSTR prompt = NULL;
1178 if (szProduct) product = strdupAtoW(szProduct);
1179 if (szUserSid) usersid = strdupAtoW(szUserSid);
1180 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1181 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1183 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1184 dwDiskId, volume, prompt);
1186 msi_free(product);
1187 msi_free(usersid);
1188 msi_free(volume);
1189 msi_free(prompt);
1191 return r;
1194 /******************************************************************
1195 * MsiSourceListAddMediaDiskW (MSI.@)
1197 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
1198 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1199 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
1201 HKEY sourcekey, mediakey;
1202 UINT rc;
1203 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1204 DWORD size;
1206 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
1207 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
1208 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
1210 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1211 return ERROR_INVALID_PARAMETER;
1213 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1214 return ERROR_INVALID_PARAMETER;
1216 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1217 return ERROR_INVALID_PARAMETER;
1219 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1220 return ERROR_INVALID_PARAMETER;
1222 if (dwOptions & MSICODE_PATCH)
1224 FIXME("Unhandled options MSICODE_PATCH\n");
1225 return ERROR_FUNCTION_FAILED;
1228 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1229 if (rc != ERROR_SUCCESS)
1230 return rc;
1232 OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1234 swprintf(szIndex, ARRAY_SIZE(szIndex), L"%d", dwDiskId);
1236 size = 2;
1237 if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1238 if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1240 size *= sizeof(WCHAR);
1241 buffer = msi_alloc(size);
1242 *buffer = '\0';
1244 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1245 lstrcatW(buffer, L";");
1246 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1248 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1249 msi_free(buffer);
1251 RegCloseKey(sourcekey);
1252 RegCloseKey(mediakey);
1254 return ERROR_SUCCESS;
1257 /******************************************************************
1258 * MsiSourceListClearAllA (MSI.@)
1260 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
1262 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
1263 return ERROR_SUCCESS;
1266 /******************************************************************
1267 * MsiSourceListClearAllW (MSI.@)
1269 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
1271 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
1272 return ERROR_SUCCESS;
1275 /******************************************************************
1276 * MsiSourceListClearAllExA (MSI.@)
1278 UINT WINAPI MsiSourceListClearAllExA( LPCSTR szProduct, LPCSTR szUserSid,
1279 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1281 FIXME("(%s %s %d %08x)\n", debugstr_a(szProduct), debugstr_a(szUserSid),
1282 dwContext, dwOptions);
1283 return ERROR_SUCCESS;
1286 /******************************************************************
1287 * MsiSourceListClearAllExW (MSI.@)
1289 UINT WINAPI MsiSourceListClearAllExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1290 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1292 FIXME("(%s %s %d %08x)\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1293 dwContext, dwOptions);
1294 return ERROR_SUCCESS;
1297 /******************************************************************
1298 * MsiSourceListClearSourceA (MSI.@)
1300 UINT WINAPI MsiSourceListClearSourceA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid,
1301 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1302 LPCSTR szSource)
1304 FIXME("(%s %s %x %x %s)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid),
1305 dwContext, dwOptions, debugstr_a(szSource));
1306 return ERROR_SUCCESS;
1309 /******************************************************************
1310 * MsiSourceListClearSourceW (MSI.@)
1312 UINT WINAPI MsiSourceListClearSourceW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid,
1313 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1314 LPCWSTR szSource)
1316 FIXME("(%s %s %x %x %s)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid),
1317 dwContext, dwOptions, debugstr_w(szSource));
1318 return ERROR_SUCCESS;
1321 /******************************************************************
1322 * MsiSourceListForceResolutionA (MSI.@)
1324 UINT WINAPI MsiSourceListForceResolutionA(const CHAR *product, const CHAR *user, DWORD reserved)
1326 FIXME("(%s %s %x)\n", debugstr_a(product), debugstr_a(user), reserved);
1327 return ERROR_SUCCESS;
1330 /******************************************************************
1331 * MsiSourceListForceResolutionW (MSI.@)
1333 UINT WINAPI MsiSourceListForceResolutionW(const WCHAR *product, const WCHAR *user, DWORD reserved)
1335 FIXME("(%s %s %x)\n", debugstr_w(product), debugstr_w(user), reserved);
1336 return ERROR_SUCCESS;