user32: Hook drawing menu buttons.
[wine.git] / dlls / msi / source.c
blob7ed0aabf142d248be2f1cf8facd2a6414742f743
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( const char *szProductCodeOrPatchCode, const char *szUserSid,
145 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex,
146 DWORD *pdwDiskId, char *szVolumeLabel, DWORD *pcchVolumeLabel,
147 char *szDiskPrompt, DWORD *pcchDiskPrompt )
149 WCHAR *product = NULL, *usersid = NULL, *volume = NULL, *prompt = NULL;
150 UINT r = ERROR_INVALID_PARAMETER;
152 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p, %p, %p, %p\n", debugstr_a(szProductCodeOrPatchCode),
153 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId, szVolumeLabel, pcchVolumeLabel,
154 szDiskPrompt, pcchDiskPrompt );
156 if (szDiskPrompt && !pcchDiskPrompt)
157 return ERROR_INVALID_PARAMETER;
159 if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode);
160 if (szUserSid) usersid = strdupAtoW(szUserSid);
162 /* FIXME: add tests for an invalid format */
164 if (pcchVolumeLabel)
165 volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR));
167 if (pcchDiskPrompt)
168 prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR));
170 if (volume) *volume = '\0';
171 if (prompt) *prompt = '\0';
172 r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions,
173 dwIndex, pdwDiskId, volume, pcchVolumeLabel,
174 prompt, pcchDiskPrompt);
175 if (r != ERROR_SUCCESS)
176 goto done;
178 if (szVolumeLabel && pcchVolumeLabel)
179 WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel,
180 *pcchVolumeLabel + 1, NULL, NULL);
182 if (szDiskPrompt)
183 WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt,
184 *pcchDiskPrompt + 1, NULL, NULL);
186 done:
187 msi_free(product);
188 msi_free(usersid);
189 msi_free(volume);
190 msi_free(prompt);
192 return r;
195 /******************************************************************
196 * MsiSourceListEnumMediaDisksW (MSI.@)
198 UINT WINAPI MsiSourceListEnumMediaDisksW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid,
199 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex,
200 DWORD *pdwDiskId, WCHAR *szVolumeLabel, DWORD *pcchVolumeLabel,
201 WCHAR *szDiskPrompt, DWORD *pcchDiskPrompt )
203 WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11];
204 WCHAR *value = NULL, *data = NULL, *ptr, *ptr2;
205 HKEY source, media;
206 DWORD valuesz, datasz = 0, type, numvals, size;
207 LONG res;
208 UINT r;
209 static DWORD index = 0;
211 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(szProductCodeOrPatchCode),
212 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel, pcchVolumeLabel,
213 szDiskPrompt, pcchDiskPrompt );
215 if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc ))
216 return ERROR_INVALID_PARAMETER;
218 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
219 return ERROR_INVALID_PARAMETER;
221 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
222 return ERROR_INVALID_PARAMETER;
224 if (szDiskPrompt && !pcchDiskPrompt)
225 return ERROR_INVALID_PARAMETER;
227 if (dwIndex == 0)
228 index = 0;
230 if (dwIndex != index)
231 return ERROR_INVALID_PARAMETER;
233 r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE);
234 if (r != ERROR_SUCCESS)
235 return r;
237 r = OpenMediaSubkey(source, &media, FALSE);
238 if (r != ERROR_SUCCESS)
240 RegCloseKey(source);
241 return ERROR_NO_MORE_ITEMS;
244 res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
245 NULL, &numvals, &valuesz, &datasz, NULL, NULL);
246 if (res != ERROR_SUCCESS)
248 r = ERROR_BAD_CONFIGURATION;
249 goto done;
252 value = msi_alloc(++valuesz * sizeof(WCHAR));
253 data = msi_alloc(++datasz * sizeof(WCHAR));
254 if (!value || !data)
256 r = ERROR_OUTOFMEMORY;
257 goto done;
260 r = RegEnumValueW(media, dwIndex, value, &valuesz,
261 NULL, &type, (LPBYTE)data, &datasz);
262 if (r != ERROR_SUCCESS)
263 goto done;
265 if (pdwDiskId)
266 *pdwDiskId = wcstol(value, NULL, 10);
268 ptr2 = data;
269 ptr = wcschr(data, ';');
270 if (!ptr)
271 ptr = data;
272 else
273 *ptr = '\0';
275 if (pcchVolumeLabel)
277 if (type == REG_DWORD)
279 swprintf(convert, ARRAY_SIZE(convert), L"#%d", *data);
280 size = lstrlenW(convert);
281 ptr2 = convert;
283 else
284 size = lstrlenW(data);
286 if (size >= *pcchVolumeLabel)
287 r = ERROR_MORE_DATA;
288 else if (szVolumeLabel)
289 lstrcpyW(szVolumeLabel, ptr2);
291 *pcchVolumeLabel = size;
294 if (pcchDiskPrompt)
296 if (!*ptr)
297 ptr++;
299 if (type == REG_DWORD)
301 swprintf(convert, ARRAY_SIZE(convert), L"#%d", *ptr);
302 size = lstrlenW(convert);
303 ptr = convert;
305 else
306 size = lstrlenW(ptr);
308 if (size >= *pcchDiskPrompt)
309 r = ERROR_MORE_DATA;
310 else if (szDiskPrompt)
311 lstrcpyW(szDiskPrompt, ptr);
313 *pcchDiskPrompt = size;
316 index++;
318 done:
319 msi_free(value);
320 msi_free(data);
321 RegCloseKey(source);
323 return r;
326 /******************************************************************
327 * MsiSourceListEnumSourcesA (MSI.@)
329 UINT WINAPI MsiSourceListEnumSourcesA( const char *szProductCodeOrPatch, const char *szUserSid,
330 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, char *szSource,
331 DWORD *pcchSource )
333 WCHAR *product = NULL, *usersid = NULL, *source = NULL;
334 DWORD len = 0;
335 UINT r = ERROR_INVALID_PARAMETER;
336 static DWORD index = 0;
338 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p)\n", debugstr_a(szProductCodeOrPatch), debugstr_a(szUserSid), dwContext,
339 dwOptions, dwIndex, szSource, pcchSource );
341 if (dwIndex == 0)
342 index = 0;
344 if (szSource && !pcchSource)
345 goto done;
347 if (dwIndex != index)
348 goto done;
350 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
351 if (szUserSid) usersid = strdupAtoW(szUserSid);
353 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
354 dwIndex, NULL, &len);
355 if (r != ERROR_SUCCESS)
356 goto done;
358 source = msi_alloc(++len * sizeof(WCHAR));
359 if (!source)
361 r = ERROR_OUTOFMEMORY;
362 goto done;
365 *source = '\0';
366 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
367 dwIndex, source, &len);
368 if (r != ERROR_SUCCESS)
369 goto done;
371 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
372 if (pcchSource && *pcchSource >= len)
373 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
374 else if (szSource)
375 r = ERROR_MORE_DATA;
377 if (pcchSource)
378 *pcchSource = len - 1;
380 done:
381 msi_free(product);
382 msi_free(usersid);
383 msi_free(source);
385 if (r == ERROR_SUCCESS)
387 if (szSource || !pcchSource) index++;
389 else if (dwIndex > index)
390 index = 0;
392 return r;
395 /******************************************************************
396 * MsiSourceListEnumSourcesW (MSI.@)
398 UINT WINAPI MsiSourceListEnumSourcesW( const WCHAR *szProductCodeOrPatch, const WCHAR *szUserSid,
399 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, WCHAR *szSource,
400 DWORD *pcchSource )
402 WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32];
403 HKEY source = NULL, subkey = NULL;
404 LONG res;
405 UINT r = ERROR_INVALID_PARAMETER;
406 static DWORD index = 0;
408 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p\n", debugstr_w(szProductCodeOrPatch), debugstr_w(szUserSid), dwContext,
409 dwOptions, dwIndex, szSource, pcchSource );
411 if (dwIndex == 0)
412 index = 0;
414 if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc ))
415 goto done;
417 if (szSource && !pcchSource)
418 goto done;
420 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
421 goto done;
423 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
424 goto done;
426 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
427 goto done;
429 if (dwIndex != index)
430 goto done;
432 r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE );
433 if (r != ERROR_SUCCESS)
434 goto done;
436 if (dwOptions & MSISOURCETYPE_NETWORK)
437 r = OpenNetworkSubkey(source, &subkey, FALSE);
438 else if (dwOptions & MSISOURCETYPE_URL)
439 r = OpenURLSubkey(source, &subkey, FALSE);
441 if (r != ERROR_SUCCESS)
443 r = ERROR_NO_MORE_ITEMS;
444 goto done;
447 swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex + 1);
449 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
450 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
451 r = ERROR_NO_MORE_ITEMS;
453 done:
454 RegCloseKey(subkey);
455 RegCloseKey(source);
457 if (r == ERROR_SUCCESS)
459 if (szSource || !pcchSource) index++;
461 else if (dwIndex > index)
462 index = 0;
464 return r;
467 /******************************************************************
468 * MsiSourceListGetInfoA (MSI.@)
470 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
471 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
472 LPCSTR szProperty, LPSTR szValue,
473 LPDWORD pcchValue)
475 UINT ret;
476 LPWSTR product = NULL;
477 LPWSTR usersid = NULL;
478 LPWSTR property = NULL;
479 LPWSTR value = NULL;
480 DWORD len = 0;
482 if (szValue && !pcchValue)
483 return ERROR_INVALID_PARAMETER;
485 if (szProduct) product = strdupAtoW(szProduct);
486 if (szUserSid) usersid = strdupAtoW(szUserSid);
487 if (szProperty) property = strdupAtoW(szProperty);
489 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
490 property, NULL, &len);
491 if (ret != ERROR_SUCCESS)
492 goto done;
494 value = msi_alloc(++len * sizeof(WCHAR));
495 if (!value)
496 return ERROR_OUTOFMEMORY;
498 *value = '\0';
499 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
500 property, value, &len);
501 if (ret != ERROR_SUCCESS)
502 goto done;
504 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
505 if (*pcchValue >= len)
506 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
507 else if (szValue)
508 ret = ERROR_MORE_DATA;
510 *pcchValue = len - 1;
512 done:
513 msi_free(product);
514 msi_free(usersid);
515 msi_free(property);
516 msi_free(value);
517 return ret;
520 /******************************************************************
521 * MsiSourceListGetInfoW (MSI.@)
523 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
524 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
525 LPCWSTR szProperty, LPWSTR szValue,
526 LPDWORD pcchValue)
528 WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE];
529 HKEY sourcekey, media;
530 DWORD size;
531 UINT rc;
533 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
535 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
536 return ERROR_INVALID_PARAMETER;
538 if (szValue && !pcchValue)
539 return ERROR_INVALID_PARAMETER;
541 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
542 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
543 dwContext != MSIINSTALLCONTEXT_MACHINE)
544 return ERROR_INVALID_PARAMETER;
546 if (!szProperty)
547 return ERROR_INVALID_PARAMETER;
549 if (szUserSid)
550 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
552 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
553 if (rc != ERROR_SUCCESS)
554 return rc;
556 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
557 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
559 rc = OpenMediaSubkey(sourcekey, &media, FALSE);
560 if (rc != ERROR_SUCCESS)
562 RegCloseKey(sourcekey);
563 return ERROR_SUCCESS;
566 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
567 szProperty = L"MediaPackage";
569 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
570 RegCloseKey(media);
572 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
573 !wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
575 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
576 0, 0, NULL, &size);
577 if (rc != ERROR_SUCCESS)
579 static WCHAR szEmpty[] = L"";
580 rc = ERROR_SUCCESS;
581 source = NULL;
582 ptr = szEmpty;
583 goto output_out;
586 source = msi_alloc(size);
587 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
588 0, 0, (LPBYTE)source, &size);
590 if (!*source)
592 msi_free(source);
593 RegCloseKey(sourcekey);
594 return ERROR_SUCCESS;
597 if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
599 if (*source != 'n' && *source != 'u' && *source != 'm')
601 msi_free(source);
602 RegCloseKey(sourcekey);
603 return ERROR_SUCCESS;
606 ptr = source;
607 source[1] = '\0';
609 else
611 ptr = wcsrchr(source, ';');
612 if (!ptr)
613 ptr = source;
614 else
615 ptr++;
617 output_out:
618 if (szValue)
620 if (lstrlenW(ptr) < *pcchValue)
621 lstrcpyW(szValue, ptr);
622 else
623 rc = ERROR_MORE_DATA;
626 *pcchValue = lstrlenW(ptr);
627 msi_free(source);
629 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
631 *pcchValue = *pcchValue * sizeof(WCHAR);
632 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
633 (LPBYTE)szValue, pcchValue);
634 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
636 *pcchValue = 0;
637 rc = ERROR_SUCCESS;
639 else
641 if (*pcchValue)
642 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
643 if (szValue)
644 szValue[*pcchValue] = '\0';
647 else
649 FIXME("Unknown property %s\n",debugstr_w(szProperty));
650 rc = ERROR_UNKNOWN_PROPERTY;
653 RegCloseKey(sourcekey);
654 return rc;
657 /******************************************************************
658 * MsiSourceListSetInfoA (MSI.@)
660 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
661 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
662 LPCSTR szProperty, LPCSTR szValue)
664 UINT ret;
665 LPWSTR product = NULL;
666 LPWSTR usersid = NULL;
667 LPWSTR property = NULL;
668 LPWSTR value = NULL;
670 if (szProduct) product = strdupAtoW(szProduct);
671 if (szUserSid) usersid = strdupAtoW(szUserSid);
672 if (szProperty) property = strdupAtoW(szProperty);
673 if (szValue) value = strdupAtoW(szValue);
675 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
676 property, value);
678 msi_free(product);
679 msi_free(usersid);
680 msi_free(property);
681 msi_free(value);
683 return ret;
686 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
687 MSIINSTALLCONTEXT context, DWORD options,
688 LPCWSTR value)
690 HKEY source;
691 LPWSTR buffer;
692 WCHAR typechar;
693 DWORD size;
694 UINT r;
695 int index = 1;
697 if (options & MSISOURCETYPE_NETWORK)
698 typechar = 'n';
699 else if (options & MSISOURCETYPE_URL)
700 typechar = 'u';
701 else if (options & MSISOURCETYPE_MEDIA)
702 typechar = 'm';
703 else
704 return ERROR_INVALID_PARAMETER;
706 if (!(options & MSISOURCETYPE_MEDIA))
708 r = MsiSourceListAddSourceExW(product, usersid, context,
709 options, value, 0);
710 if (r != ERROR_SUCCESS)
711 return r;
713 index = 0;
714 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
715 index, NULL, NULL)) == ERROR_SUCCESS)
716 index++;
718 if (r != ERROR_NO_MORE_ITEMS)
719 return r;
722 size = lstrlenW(L"%c;%d;%s") + lstrlenW(value) + 7;
723 buffer = msi_alloc(size * sizeof(WCHAR));
724 if (!buffer)
725 return ERROR_OUTOFMEMORY;
727 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
728 if (r != ERROR_SUCCESS)
730 msi_free(buffer);
731 return r;
734 swprintf(buffer, size, L"%c;%d;%s", typechar, index, value);
736 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
737 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
738 REG_SZ, (LPBYTE)buffer, size);
739 msi_free(buffer);
741 RegCloseKey(source);
742 return r;
745 /******************************************************************
746 * MsiSourceListSetInfoW (MSI.@)
748 UINT WINAPI MsiSourceListSetInfoW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
749 DWORD dwOptions, const WCHAR *szProperty, const WCHAR *szValue )
751 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
752 HKEY sourcekey, media;
753 LPCWSTR property;
754 UINT rc;
756 TRACE( "%s, %s, %d, %#lx, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
757 debugstr_w(szProperty), debugstr_w(szValue) );
759 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
760 return ERROR_INVALID_PARAMETER;
762 if (!szProperty)
763 return ERROR_INVALID_PARAMETER;
765 if (!szValue)
766 return ERROR_UNKNOWN_PROPERTY;
768 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
769 return ERROR_INVALID_PARAMETER;
771 if (dwOptions & MSICODE_PATCH)
773 FIXME("Unhandled options MSICODE_PATCH\n");
774 return ERROR_UNKNOWN_PATCH;
777 property = szProperty;
778 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
779 property = L"MediaPackage";
781 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
782 if (rc != ERROR_SUCCESS)
783 return rc;
785 if (wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
786 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
788 RegCloseKey(sourcekey);
789 return ERROR_INVALID_PARAMETER;
792 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
793 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
795 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
796 if (rc == ERROR_SUCCESS)
798 rc = msi_reg_set_val_str(media, property, szValue);
799 RegCloseKey(media);
802 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
804 DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
805 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
806 REG_SZ, (const BYTE *)szValue, size);
807 if (rc != ERROR_SUCCESS)
808 rc = ERROR_UNKNOWN_PROPERTY;
810 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
812 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
813 rc = ERROR_INVALID_PARAMETER;
814 else
815 rc = msi_set_last_used_source(szProduct, szUserSid, dwContext,
816 dwOptions, szValue);
818 else
819 rc = ERROR_UNKNOWN_PROPERTY;
821 RegCloseKey(sourcekey);
822 return rc;
825 /******************************************************************
826 * MsiSourceListAddSourceW (MSI.@)
828 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
829 DWORD dwReserved, LPCWSTR szSource)
831 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
832 INT ret;
833 DWORD sidsize = 0, domsize = 0, context;
834 HKEY hkey = 0;
835 UINT r;
837 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
839 if (!szSource || !*szSource)
840 return ERROR_INVALID_PARAMETER;
842 if (dwReserved != 0)
843 return ERROR_INVALID_PARAMETER;
845 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
846 return ERROR_INVALID_PARAMETER;
848 if (!szUserName || !*szUserName)
849 context = MSIINSTALLCONTEXT_MACHINE;
850 else
852 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
854 PSID psid = msi_alloc(sidsize);
856 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
857 ConvertSidToStringSidW(psid, &sidstr);
859 msi_free(psid);
862 r = MSIREG_OpenProductKey(szProduct, NULL,
863 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
864 if (r == ERROR_SUCCESS)
865 context = MSIINSTALLCONTEXT_USERMANAGED;
866 else
868 r = MSIREG_OpenProductKey(szProduct, NULL,
869 MSIINSTALLCONTEXT_USERUNMANAGED,
870 &hkey, FALSE);
871 if (r != ERROR_SUCCESS)
872 return ERROR_UNKNOWN_PRODUCT;
874 context = MSIINSTALLCONTEXT_USERUNMANAGED;
877 RegCloseKey(hkey);
880 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
881 context, MSISOURCETYPE_NETWORK, szSource, 0);
883 if (sidstr)
884 LocalFree(sidstr);
886 return ret;
889 /******************************************************************
890 * MsiSourceListAddSourceA (MSI.@)
892 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
893 DWORD dwReserved, LPCSTR szSource)
895 INT ret;
896 LPWSTR szwproduct;
897 LPWSTR szwusername;
898 LPWSTR szwsource;
900 szwproduct = strdupAtoW( szProduct );
901 szwusername = strdupAtoW( szUserName );
902 szwsource = strdupAtoW( szSource );
904 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
906 msi_free(szwproduct);
907 msi_free(szwusername);
908 msi_free(szwsource);
910 return ret;
913 /******************************************************************
914 * MsiSourceListAddSourceExA (MSI.@)
916 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
917 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
919 UINT ret;
920 LPWSTR product, usersid, source;
922 product = strdupAtoW(szProduct);
923 usersid = strdupAtoW(szUserSid);
924 source = strdupAtoW(szSource);
926 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
927 dwOptions, source, dwIndex);
929 msi_free(product);
930 msi_free(usersid);
931 msi_free(source);
933 return ret;
936 static void free_source_list(struct list *sourcelist)
938 while (!list_empty(sourcelist))
940 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
941 list_remove(&info->entry);
942 msi_free(info->path);
943 msi_free(info);
947 static void add_source_to_list(struct list *sourcelist, media_info *info,
948 DWORD *index)
950 media_info *iter;
951 BOOL found = FALSE;
953 if (index) *index = 0;
955 if (list_empty(sourcelist))
957 list_add_head(sourcelist, &info->entry);
958 return;
961 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
963 if (!found && info->index < iter->index)
965 found = TRUE;
966 list_add_before(&iter->entry, &info->entry);
969 /* update the rest of the list */
970 if (found)
971 swprintf(iter->szIndex, ARRAY_SIZE(iter->szIndex), L"%d", ++iter->index);
972 else if (index)
973 (*index)++;
976 if (!found)
977 list_add_after(&iter->entry, &info->entry);
980 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
982 UINT r = ERROR_SUCCESS;
983 DWORD index = 0;
984 WCHAR name[10];
985 DWORD size, val_size;
986 media_info *entry;
988 *count = 0;
990 while (r == ERROR_SUCCESS)
992 size = ARRAY_SIZE(name);
993 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
994 if (r != ERROR_SUCCESS)
995 return r;
997 entry = msi_alloc(sizeof(media_info));
998 if (!entry)
999 goto error;
1001 entry->path = msi_alloc(val_size);
1002 if (!entry->path)
1004 msi_free(entry);
1005 goto error;
1008 lstrcpyW(entry->szIndex, name);
1009 entry->index = wcstol(name, NULL, 10);
1011 size++;
1012 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1013 NULL, (LPBYTE)entry->path, &val_size);
1014 if (r != ERROR_SUCCESS)
1016 msi_free(entry->path);
1017 msi_free(entry);
1018 goto error;
1021 index = ++(*count);
1022 add_source_to_list(sourcelist, entry, NULL);
1025 error:
1026 *count = -1;
1027 free_source_list(sourcelist);
1028 return ERROR_OUTOFMEMORY;
1031 /******************************************************************
1032 * MsiSourceListAddSourceExW (MSI.@)
1034 UINT WINAPI MsiSourceListAddSourceExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1035 DWORD dwOptions, const WCHAR *szSource, DWORD dwIndex )
1037 HKEY sourcekey, typekey;
1038 UINT rc;
1039 struct list sourcelist;
1040 media_info *info;
1041 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1042 LPCWSTR postfix;
1043 DWORD size, count, index;
1045 TRACE( "%s, %s, %d, %#lx, %s, %lu\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1046 debugstr_w(szSource), dwIndex );
1048 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1049 return ERROR_INVALID_PARAMETER;
1051 if (!szSource || !*szSource)
1052 return ERROR_INVALID_PARAMETER;
1054 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1055 return ERROR_INVALID_PARAMETER;
1057 if (dwOptions & MSICODE_PATCH)
1059 FIXME("Unhandled options MSICODE_PATCH\n");
1060 return ERROR_FUNCTION_FAILED;
1063 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1064 return ERROR_INVALID_PARAMETER;
1066 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1067 if (rc != ERROR_SUCCESS)
1068 return rc;
1070 if (dwOptions & MSISOURCETYPE_NETWORK)
1071 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1072 else if (dwOptions & MSISOURCETYPE_URL)
1073 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1074 else if (dwOptions & MSISOURCETYPE_MEDIA)
1075 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1076 else
1078 ERR( "unknown media type: %#lx\n", dwOptions );
1079 RegCloseKey(sourcekey);
1080 return ERROR_FUNCTION_FAILED;
1082 if (rc != ERROR_SUCCESS)
1084 ERR("can't open subkey %u\n", rc);
1085 RegCloseKey(sourcekey);
1086 return rc;
1089 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? L"\\" : L"/";
1090 if (szSource[lstrlenW(szSource) - 1] == *postfix)
1091 source = strdupW(szSource);
1092 else
1094 size = lstrlenW(szSource) + 2;
1095 source = msi_alloc(size * sizeof(WCHAR));
1096 lstrcpyW(source, szSource);
1097 lstrcatW(source, postfix);
1100 list_init(&sourcelist);
1101 rc = fill_source_list(&sourcelist, typekey, &count);
1102 if (rc != ERROR_NO_MORE_ITEMS)
1103 goto done;
1105 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1107 if (count == 0)
1109 rc = RegSetValueExW(typekey, L"1", 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1110 goto done;
1112 else if (dwIndex > count || dwIndex == 0)
1114 swprintf(name, ARRAY_SIZE(name), L"%d", count + 1);
1115 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1116 goto done;
1118 else
1120 swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex);
1121 info = msi_alloc(sizeof(media_info));
1122 if (!info)
1124 rc = ERROR_OUTOFMEMORY;
1125 goto done;
1128 info->path = strdupW(source);
1129 lstrcpyW(info->szIndex, name);
1130 info->index = dwIndex;
1131 add_source_to_list(&sourcelist, info, &index);
1133 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
1135 if (info->index < index)
1136 continue;
1138 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1139 rc = RegSetValueExW(typekey, info->szIndex, 0,
1140 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1141 if (rc != ERROR_SUCCESS)
1142 goto done;
1146 done:
1147 free_source_list(&sourcelist);
1148 msi_free(source);
1149 RegCloseKey(typekey);
1150 RegCloseKey(sourcekey);
1151 return rc;
1154 /******************************************************************
1155 * MsiSourceListAddMediaDiskA (MSI.@)
1157 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1158 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1159 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1161 UINT r;
1162 LPWSTR product = NULL;
1163 LPWSTR usersid = NULL;
1164 LPWSTR volume = NULL;
1165 LPWSTR prompt = NULL;
1167 if (szProduct) product = strdupAtoW(szProduct);
1168 if (szUserSid) usersid = strdupAtoW(szUserSid);
1169 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1170 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1172 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1173 dwDiskId, volume, prompt);
1175 msi_free(product);
1176 msi_free(usersid);
1177 msi_free(volume);
1178 msi_free(prompt);
1180 return r;
1183 /******************************************************************
1184 * MsiSourceListAddMediaDiskW (MSI.@)
1186 UINT WINAPI MsiSourceListAddMediaDiskW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1187 DWORD dwOptions, DWORD dwDiskId, const WCHAR *szVolumeLabel,
1188 const WCHAR *szDiskPrompt )
1190 HKEY sourcekey, mediakey;
1191 UINT rc;
1192 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1193 DWORD size;
1195 TRACE( "%s, %s, %d, %#lx, %lu, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1196 dwDiskId, debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt) );
1198 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1199 return ERROR_INVALID_PARAMETER;
1201 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1202 return ERROR_INVALID_PARAMETER;
1204 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1205 return ERROR_INVALID_PARAMETER;
1207 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1208 return ERROR_INVALID_PARAMETER;
1210 if (dwOptions & MSICODE_PATCH)
1212 FIXME("Unhandled options MSICODE_PATCH\n");
1213 return ERROR_FUNCTION_FAILED;
1216 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1217 if (rc != ERROR_SUCCESS)
1218 return rc;
1220 OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1222 swprintf(szIndex, ARRAY_SIZE(szIndex), L"%d", dwDiskId);
1224 size = 2;
1225 if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1226 if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1228 size *= sizeof(WCHAR);
1229 buffer = msi_alloc(size);
1230 *buffer = '\0';
1232 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1233 lstrcatW(buffer, L";");
1234 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1236 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1237 msi_free(buffer);
1239 RegCloseKey(sourcekey);
1240 RegCloseKey(mediakey);
1242 return ERROR_SUCCESS;
1245 /******************************************************************
1246 * MsiSourceListClearAllA (MSI.@)
1248 UINT WINAPI MsiSourceListClearAllA( const char *szProduct, const char *szUserName, DWORD dwReserved )
1250 FIXME( "%s, %s, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved );
1251 return ERROR_SUCCESS;
1254 /******************************************************************
1255 * MsiSourceListClearAllW (MSI.@)
1257 UINT WINAPI MsiSourceListClearAllW( const WCHAR *szProduct, const WCHAR *szUserName, DWORD dwReserved )
1259 FIXME( "%s, %s, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved );
1260 return ERROR_SUCCESS;
1263 /******************************************************************
1264 * MsiSourceListClearAllExA (MSI.@)
1266 UINT WINAPI MsiSourceListClearAllExA( const char *szProduct, const char *szUserSid, MSIINSTALLCONTEXT dwContext,
1267 DWORD dwOptions )
1269 FIXME( "%s, %s, %d, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserSid), dwContext, dwOptions );
1270 return ERROR_SUCCESS;
1273 /******************************************************************
1274 * MsiSourceListClearAllExW (MSI.@)
1276 UINT WINAPI MsiSourceListClearAllExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1277 DWORD dwOptions )
1279 FIXME( "%s, %s, %d, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions );
1280 return ERROR_SUCCESS;
1283 /******************************************************************
1284 * MsiSourceListClearSourceA (MSI.@)
1286 UINT WINAPI MsiSourceListClearSourceA( const char *szProductCodeOrPatchCode, const char *szUserSid,
1287 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, const char *szSource )
1289 FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), dwContext,
1290 dwOptions, debugstr_a(szSource) );
1291 return ERROR_SUCCESS;
1294 /******************************************************************
1295 * MsiSourceListClearSourceW (MSI.@)
1297 UINT WINAPI MsiSourceListClearSourceW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid,
1298 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource )
1300 FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), dwContext,
1301 dwOptions, debugstr_w(szSource) );
1302 return ERROR_SUCCESS;
1305 /******************************************************************
1306 * MsiSourceListForceResolutionA (MSI.@)
1308 UINT WINAPI MsiSourceListForceResolutionA( const char *product, const char *user, DWORD reserved )
1310 FIXME( "%s, %s, %#lx\n", debugstr_a(product), debugstr_a(user), reserved );
1311 return ERROR_SUCCESS;
1314 /******************************************************************
1315 * MsiSourceListForceResolutionW (MSI.@)
1317 UINT WINAPI MsiSourceListForceResolutionW( const WCHAR *product, const WCHAR *user, DWORD reserved )
1319 FIXME( "%s, %s, %#lx\n", debugstr_w(product), debugstr_w(user), reserved );
1320 return ERROR_SUCCESS;