ntoskrnl.exe: Reimplement KeSetTimerEx() on top of thread pool.
[wine.git] / dlls / msi / source.c
blob89c04d9f7ddc39e2c894c2cad9df54dec3b82a7f
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, szSourceList, key);
94 else
96 rc = RegOpenKeyW(rootkey,szSourceList, 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;
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 = wcstol(value, NULL, 10);
277 ptr2 = data;
278 ptr = wcschr(data, ';');
279 if (!ptr)
280 ptr = data;
281 else
282 *ptr = '\0';
284 if (pcchVolumeLabel)
286 if (type == REG_DWORD)
288 swprintf(convert, ARRAY_SIZE(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 swprintf(convert, ARRAY_SIZE(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 swprintf(name, ARRAY_SIZE(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 (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
572 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
574 rc = OpenMediaSubkey(sourcekey, &media, FALSE);
575 if (rc != ERROR_SUCCESS)
577 RegCloseKey(sourcekey);
578 return ERROR_SUCCESS;
581 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
582 szProperty = mediapack;
584 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
585 RegCloseKey(media);
587 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
588 !wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
590 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
591 0, 0, NULL, &size);
592 if (rc != ERROR_SUCCESS)
594 static WCHAR szEmpty[1] = { '\0' };
595 rc = ERROR_SUCCESS;
596 source = NULL;
597 ptr = szEmpty;
598 goto output_out;
601 source = msi_alloc(size);
602 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
603 0, 0, (LPBYTE)source, &size);
605 if (!*source)
607 msi_free(source);
608 RegCloseKey(sourcekey);
609 return ERROR_SUCCESS;
612 if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
614 if (*source != 'n' && *source != 'u' && *source != 'm')
616 msi_free(source);
617 RegCloseKey(sourcekey);
618 return ERROR_SUCCESS;
621 ptr = source;
622 source[1] = '\0';
624 else
626 ptr = wcsrchr(source, ';');
627 if (!ptr)
628 ptr = source;
629 else
630 ptr++;
632 output_out:
633 if (szValue)
635 if (lstrlenW(ptr) < *pcchValue)
636 lstrcpyW(szValue, ptr);
637 else
638 rc = ERROR_MORE_DATA;
641 *pcchValue = lstrlenW(ptr);
642 msi_free(source);
644 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
646 *pcchValue = *pcchValue * sizeof(WCHAR);
647 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
648 (LPBYTE)szValue, pcchValue);
649 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
651 *pcchValue = 0;
652 rc = ERROR_SUCCESS;
654 else
656 if (*pcchValue)
657 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
658 if (szValue)
659 szValue[*pcchValue] = '\0';
662 else
664 FIXME("Unknown property %s\n",debugstr_w(szProperty));
665 rc = ERROR_UNKNOWN_PROPERTY;
668 RegCloseKey(sourcekey);
669 return rc;
672 /******************************************************************
673 * MsiSourceListSetInfoA (MSI.@)
675 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
676 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
677 LPCSTR szProperty, LPCSTR szValue)
679 UINT ret;
680 LPWSTR product = NULL;
681 LPWSTR usersid = NULL;
682 LPWSTR property = NULL;
683 LPWSTR value = NULL;
685 if (szProduct) product = strdupAtoW(szProduct);
686 if (szUserSid) usersid = strdupAtoW(szUserSid);
687 if (szProperty) property = strdupAtoW(szProperty);
688 if (szValue) value = strdupAtoW(szValue);
690 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
691 property, value);
693 msi_free(product);
694 msi_free(usersid);
695 msi_free(property);
696 msi_free(value);
698 return ret;
701 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
702 MSIINSTALLCONTEXT context, DWORD options,
703 LPCWSTR value)
705 HKEY source;
706 LPWSTR buffer;
707 WCHAR typechar;
708 DWORD size;
709 UINT r;
710 int index = 1;
712 static const WCHAR format[] = {'%','c',';','%','i',';','%','s',0};
714 if (options & MSISOURCETYPE_NETWORK)
715 typechar = 'n';
716 else if (options & MSISOURCETYPE_URL)
717 typechar = 'u';
718 else if (options & MSISOURCETYPE_MEDIA)
719 typechar = 'm';
720 else
721 return ERROR_INVALID_PARAMETER;
723 if (!(options & MSISOURCETYPE_MEDIA))
725 r = MsiSourceListAddSourceExW(product, usersid, context,
726 options, value, 0);
727 if (r != ERROR_SUCCESS)
728 return r;
730 index = 0;
731 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
732 index, NULL, NULL)) == ERROR_SUCCESS)
733 index++;
735 if (r != ERROR_NO_MORE_ITEMS)
736 return r;
739 size = lstrlenW(format) + lstrlenW(value) + 7;
740 buffer = msi_alloc(size * sizeof(WCHAR));
741 if (!buffer)
742 return ERROR_OUTOFMEMORY;
744 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
745 if (r != ERROR_SUCCESS)
747 msi_free(buffer);
748 return r;
751 swprintf(buffer, size, format, typechar, index, value);
753 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
754 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
755 REG_SZ, (LPBYTE)buffer, size);
756 msi_free(buffer);
758 RegCloseKey(source);
759 return r;
762 /******************************************************************
763 * MsiSourceListSetInfoW (MSI.@)
765 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
766 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
767 LPCWSTR szProperty, LPCWSTR szValue)
769 static const WCHAR media_package[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0};
770 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
771 HKEY sourcekey, media;
772 LPCWSTR property;
773 UINT rc;
775 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
776 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
778 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
779 return ERROR_INVALID_PARAMETER;
781 if (!szProperty)
782 return ERROR_INVALID_PARAMETER;
784 if (!szValue)
785 return ERROR_UNKNOWN_PROPERTY;
787 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
788 return ERROR_INVALID_PARAMETER;
790 if (dwOptions & MSICODE_PATCH)
792 FIXME("Unhandled options MSICODE_PATCH\n");
793 return ERROR_UNKNOWN_PATCH;
796 property = szProperty;
797 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
798 property = media_package;
800 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
801 if (rc != ERROR_SUCCESS)
802 return rc;
804 if (wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
805 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
807 RegCloseKey(sourcekey);
808 return ERROR_INVALID_PARAMETER;
811 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
812 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
814 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
815 if (rc == ERROR_SUCCESS)
817 rc = msi_reg_set_val_str(media, property, szValue);
818 RegCloseKey(media);
821 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
823 DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
824 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
825 REG_SZ, (const BYTE *)szValue, size);
826 if (rc != ERROR_SUCCESS)
827 rc = ERROR_UNKNOWN_PROPERTY;
829 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
831 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
832 rc = ERROR_INVALID_PARAMETER;
833 else
834 rc = msi_set_last_used_source(szProduct, szUserSid, dwContext,
835 dwOptions, szValue);
837 else
838 rc = ERROR_UNKNOWN_PROPERTY;
840 RegCloseKey(sourcekey);
841 return rc;
844 /******************************************************************
845 * MsiSourceListAddSourceW (MSI.@)
847 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
848 DWORD dwReserved, LPCWSTR szSource)
850 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
851 INT ret;
852 DWORD sidsize = 0, domsize = 0, context;
853 HKEY hkey = 0;
854 UINT r;
856 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
858 if (!szSource || !*szSource)
859 return ERROR_INVALID_PARAMETER;
861 if (dwReserved != 0)
862 return ERROR_INVALID_PARAMETER;
864 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
865 return ERROR_INVALID_PARAMETER;
867 if (!szUserName || !*szUserName)
868 context = MSIINSTALLCONTEXT_MACHINE;
869 else
871 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
873 PSID psid = msi_alloc(sidsize);
875 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
876 ConvertSidToStringSidW(psid, &sidstr);
878 msi_free(psid);
881 r = MSIREG_OpenProductKey(szProduct, NULL,
882 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
883 if (r == ERROR_SUCCESS)
884 context = MSIINSTALLCONTEXT_USERMANAGED;
885 else
887 r = MSIREG_OpenProductKey(szProduct, NULL,
888 MSIINSTALLCONTEXT_USERUNMANAGED,
889 &hkey, FALSE);
890 if (r != ERROR_SUCCESS)
891 return ERROR_UNKNOWN_PRODUCT;
893 context = MSIINSTALLCONTEXT_USERUNMANAGED;
896 RegCloseKey(hkey);
899 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
900 context, MSISOURCETYPE_NETWORK, szSource, 0);
902 if (sidstr)
903 LocalFree(sidstr);
905 return ret;
908 /******************************************************************
909 * MsiSourceListAddSourceA (MSI.@)
911 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
912 DWORD dwReserved, LPCSTR szSource)
914 INT ret;
915 LPWSTR szwproduct;
916 LPWSTR szwusername;
917 LPWSTR szwsource;
919 szwproduct = strdupAtoW( szProduct );
920 szwusername = strdupAtoW( szUserName );
921 szwsource = strdupAtoW( szSource );
923 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
925 msi_free(szwproduct);
926 msi_free(szwusername);
927 msi_free(szwsource);
929 return ret;
932 /******************************************************************
933 * MsiSourceListAddSourceExA (MSI.@)
935 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
936 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
938 UINT ret;
939 LPWSTR product, usersid, source;
941 product = strdupAtoW(szProduct);
942 usersid = strdupAtoW(szUserSid);
943 source = strdupAtoW(szSource);
945 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
946 dwOptions, source, dwIndex);
948 msi_free(product);
949 msi_free(usersid);
950 msi_free(source);
952 return ret;
955 static void free_source_list(struct list *sourcelist)
957 while (!list_empty(sourcelist))
959 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
960 list_remove(&info->entry);
961 msi_free(info->path);
962 msi_free(info);
966 static void add_source_to_list(struct list *sourcelist, media_info *info,
967 DWORD *index)
969 media_info *iter;
970 BOOL found = FALSE;
971 static const WCHAR fmt[] = {'%','i',0};
973 if (index) *index = 0;
975 if (list_empty(sourcelist))
977 list_add_head(sourcelist, &info->entry);
978 return;
981 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
983 if (!found && info->index < iter->index)
985 found = TRUE;
986 list_add_before(&iter->entry, &info->entry);
989 /* update the rest of the list */
990 if (found)
991 swprintf(iter->szIndex, ARRAY_SIZE(iter->szIndex), fmt, ++iter->index);
992 else if (index)
993 (*index)++;
996 if (!found)
997 list_add_after(&iter->entry, &info->entry);
1000 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
1002 UINT r = ERROR_SUCCESS;
1003 DWORD index = 0;
1004 WCHAR name[10];
1005 DWORD size, val_size;
1006 media_info *entry;
1008 *count = 0;
1010 while (r == ERROR_SUCCESS)
1012 size = ARRAY_SIZE(name);
1013 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
1014 if (r != ERROR_SUCCESS)
1015 return r;
1017 entry = msi_alloc(sizeof(media_info));
1018 if (!entry)
1019 goto error;
1021 entry->path = msi_alloc(val_size);
1022 if (!entry->path)
1024 msi_free(entry);
1025 goto error;
1028 lstrcpyW(entry->szIndex, name);
1029 entry->index = wcstol(name, NULL, 10);
1031 size++;
1032 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1033 NULL, (LPBYTE)entry->path, &val_size);
1034 if (r != ERROR_SUCCESS)
1036 msi_free(entry->path);
1037 msi_free(entry);
1038 goto error;
1041 index = ++(*count);
1042 add_source_to_list(sourcelist, entry, NULL);
1045 error:
1046 *count = -1;
1047 free_source_list(sourcelist);
1048 return ERROR_OUTOFMEMORY;
1051 /******************************************************************
1052 * MsiSourceListAddSourceExW (MSI.@)
1054 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1055 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
1056 DWORD dwIndex)
1058 static const WCHAR fmt[] = {'%','i',0};
1059 HKEY sourcekey, typekey;
1060 UINT rc;
1061 struct list sourcelist;
1062 media_info *info;
1063 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1064 LPCWSTR postfix;
1065 DWORD size, count, index;
1067 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1068 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
1070 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1071 return ERROR_INVALID_PARAMETER;
1073 if (!szSource || !*szSource)
1074 return ERROR_INVALID_PARAMETER;
1076 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1077 return ERROR_INVALID_PARAMETER;
1079 if (dwOptions & MSICODE_PATCH)
1081 FIXME("Unhandled options MSICODE_PATCH\n");
1082 return ERROR_FUNCTION_FAILED;
1085 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1086 return ERROR_INVALID_PARAMETER;
1088 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1089 if (rc != ERROR_SUCCESS)
1090 return rc;
1092 if (dwOptions & MSISOURCETYPE_NETWORK)
1093 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1094 else if (dwOptions & MSISOURCETYPE_URL)
1095 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1096 else if (dwOptions & MSISOURCETYPE_MEDIA)
1097 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1098 else
1100 ERR("unknown media type: %08x\n", dwOptions);
1101 RegCloseKey(sourcekey);
1102 return ERROR_FUNCTION_FAILED;
1104 if (rc != ERROR_SUCCESS)
1106 ERR("can't open subkey %u\n", rc);
1107 RegCloseKey(sourcekey);
1108 return rc;
1111 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? szBackSlash : szForwardSlash;
1112 if (szSource[lstrlenW(szSource) - 1] == *postfix)
1113 source = strdupW(szSource);
1114 else
1116 size = lstrlenW(szSource) + 2;
1117 source = msi_alloc(size * sizeof(WCHAR));
1118 lstrcpyW(source, szSource);
1119 lstrcatW(source, postfix);
1122 list_init(&sourcelist);
1123 rc = fill_source_list(&sourcelist, typekey, &count);
1124 if (rc != ERROR_NO_MORE_ITEMS)
1125 goto done;
1127 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1129 if (count == 0)
1131 rc = RegSetValueExW(typekey, szOne, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1132 goto done;
1134 else if (dwIndex > count || dwIndex == 0)
1136 swprintf(name, ARRAY_SIZE(name), fmt, count + 1);
1137 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1138 goto done;
1140 else
1142 swprintf(name, ARRAY_SIZE(name), fmt, dwIndex);
1143 info = msi_alloc(sizeof(media_info));
1144 if (!info)
1146 rc = ERROR_OUTOFMEMORY;
1147 goto done;
1150 info->path = strdupW(source);
1151 lstrcpyW(info->szIndex, name);
1152 info->index = dwIndex;
1153 add_source_to_list(&sourcelist, info, &index);
1155 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
1157 if (info->index < index)
1158 continue;
1160 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1161 rc = RegSetValueExW(typekey, info->szIndex, 0,
1162 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1163 if (rc != ERROR_SUCCESS)
1164 goto done;
1168 done:
1169 free_source_list(&sourcelist);
1170 msi_free(source);
1171 RegCloseKey(typekey);
1172 RegCloseKey(sourcekey);
1173 return rc;
1176 /******************************************************************
1177 * MsiSourceListAddMediaDiskA (MSI.@)
1179 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1180 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1181 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1183 UINT r;
1184 LPWSTR product = NULL;
1185 LPWSTR usersid = NULL;
1186 LPWSTR volume = NULL;
1187 LPWSTR prompt = NULL;
1189 if (szProduct) product = strdupAtoW(szProduct);
1190 if (szUserSid) usersid = strdupAtoW(szUserSid);
1191 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1192 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1194 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1195 dwDiskId, volume, prompt);
1197 msi_free(product);
1198 msi_free(usersid);
1199 msi_free(volume);
1200 msi_free(prompt);
1202 return r;
1205 /******************************************************************
1206 * MsiSourceListAddMediaDiskW (MSI.@)
1208 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
1209 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1210 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
1212 static const WCHAR fmt[] = {'%','i',0};
1213 HKEY sourcekey, mediakey;
1214 UINT rc;
1215 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1216 DWORD size;
1218 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
1219 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
1220 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
1222 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1223 return ERROR_INVALID_PARAMETER;
1225 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1226 return ERROR_INVALID_PARAMETER;
1228 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1229 return ERROR_INVALID_PARAMETER;
1231 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1232 return ERROR_INVALID_PARAMETER;
1234 if (dwOptions & MSICODE_PATCH)
1236 FIXME("Unhandled options MSICODE_PATCH\n");
1237 return ERROR_FUNCTION_FAILED;
1240 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1241 if (rc != ERROR_SUCCESS)
1242 return rc;
1244 OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1246 swprintf(szIndex, ARRAY_SIZE(szIndex), fmt, dwDiskId);
1248 size = 2;
1249 if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1250 if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1252 size *= sizeof(WCHAR);
1253 buffer = msi_alloc(size);
1254 *buffer = '\0';
1256 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1257 lstrcatW(buffer, szSemiColon);
1258 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1260 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1261 msi_free(buffer);
1263 RegCloseKey(sourcekey);
1264 RegCloseKey(mediakey);
1266 return ERROR_SUCCESS;
1269 /******************************************************************
1270 * MsiSourceListClearAllA (MSI.@)
1272 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
1274 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
1275 return ERROR_SUCCESS;
1278 /******************************************************************
1279 * MsiSourceListClearAllW (MSI.@)
1281 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
1283 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
1284 return ERROR_SUCCESS;
1287 /******************************************************************
1288 * MsiSourceListClearAllExA (MSI.@)
1290 UINT WINAPI MsiSourceListClearAllExA( LPCSTR szProduct, LPCSTR szUserSid,
1291 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1293 FIXME("(%s %s %d %08x)\n", debugstr_a(szProduct), debugstr_a(szUserSid),
1294 dwContext, dwOptions);
1295 return ERROR_SUCCESS;
1298 /******************************************************************
1299 * MsiSourceListClearAllExW (MSI.@)
1301 UINT WINAPI MsiSourceListClearAllExW( LPCWSTR szProduct, LPCWSTR szUserSid,
1302 MSIINSTALLCONTEXT dwContext, DWORD dwOptions )
1304 FIXME("(%s %s %d %08x)\n", debugstr_w(szProduct), debugstr_w(szUserSid),
1305 dwContext, dwOptions);
1306 return ERROR_SUCCESS;
1309 /******************************************************************
1310 * MsiSourceListClearSourceA (MSI.@)
1312 UINT WINAPI MsiSourceListClearSourceA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid,
1313 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1314 LPCSTR szSource)
1316 FIXME("(%s %s %x %x %s)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid),
1317 dwContext, dwOptions, debugstr_a(szSource));
1318 return ERROR_SUCCESS;
1321 /******************************************************************
1322 * MsiSourceListClearSourceW (MSI.@)
1324 UINT WINAPI MsiSourceListClearSourceW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid,
1325 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
1326 LPCWSTR szSource)
1328 FIXME("(%s %s %x %x %s)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid),
1329 dwContext, dwOptions, debugstr_w(szSource));
1330 return ERROR_SUCCESS;
1333 /******************************************************************
1334 * MsiSourceListForceResolutionA (MSI.@)
1336 UINT WINAPI MsiSourceListForceResolutionA(const CHAR *product, const CHAR *user, DWORD reserved)
1338 FIXME("(%s %s %x)\n", debugstr_a(product), debugstr_a(user), reserved);
1339 return ERROR_SUCCESS;
1342 /******************************************************************
1343 * MsiSourceListForceResolutionW (MSI.@)
1345 UINT WINAPI MsiSourceListForceResolutionW(const WCHAR *product, const WCHAR *user, DWORD reserved)
1347 FIXME("(%s %s %x)\n", debugstr_w(product), debugstr_w(user), reserved);
1348 return ERROR_SUCCESS;