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
24 #define NONAMELESSUNION
31 #include "wine/debug.h"
38 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 * These apis are defined in MSI 3.0
47 typedef struct tagMediaInfo
55 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
56 MSIINSTALLCONTEXT context, BOOL create)
59 UINT rc = ERROR_FUNCTION_FAILED;
60 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
62 if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
64 if (dwOptions & MSICODE_PATCH)
65 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
67 rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
69 else if (context == MSIINSTALLCONTEXT_USERMANAGED)
71 if (dwOptions & MSICODE_PATCH)
72 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
74 rc = MSIREG_OpenLocalManagedProductKey(szProduct, &rootkey, create);
76 else if (context == MSIINSTALLCONTEXT_MACHINE)
78 if (dwOptions & MSICODE_PATCH)
79 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
81 rc = MSIREG_OpenLocalClassesProductKey(szProduct, &rootkey, create);
84 if (rc != ERROR_SUCCESS)
86 if (dwOptions & MSICODE_PATCH)
87 return ERROR_UNKNOWN_PATCH;
89 return ERROR_UNKNOWN_PRODUCT;
93 rc = RegCreateKeyW(rootkey, szSourceList, key);
96 rc = RegOpenKeyW(rootkey,szSourceList, key);
97 if (rc != ERROR_SUCCESS)
98 rc = ERROR_BAD_CONFIGURATION;
104 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
107 static const WCHAR media[] = {'M','e','d','i','a',0};
110 rc = RegCreateKeyW(rootkey, media, key);
112 rc = RegOpenKeyW(rootkey,media, key);
117 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
120 static const WCHAR net[] = {'N','e','t',0};
123 rc = RegCreateKeyW(rootkey, net, key);
125 rc = RegOpenKeyW(rootkey, net, key);
130 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
133 static const WCHAR URL[] = {'U','R','L',0};
136 rc = RegCreateKeyW(rootkey, URL, key);
138 rc = RegOpenKeyW(rootkey, URL, key);
143 /******************************************************************
144 * MsiSourceListEnumSourcesA (MSI.@)
146 UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid,
147 MSIINSTALLCONTEXT dwContext,
148 DWORD dwOptions, DWORD dwIndex,
149 LPSTR szSource, LPDWORD pcchSource)
151 LPWSTR product = NULL;
152 LPWSTR usersid = NULL;
153 LPWSTR source = NULL;
155 UINT r = ERROR_INVALID_PARAMETER;
156 static int index = 0;
158 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch),
159 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
164 if (szSource && !pcchSource)
167 if (dwIndex != index)
170 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
171 if (szUserSid) usersid = strdupAtoW(szUserSid);
173 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
174 dwIndex, NULL, &len);
175 if (r != ERROR_SUCCESS)
178 source = msi_alloc(++len * sizeof(WCHAR));
181 r = ERROR_OUTOFMEMORY;
186 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
187 dwIndex, source, &len);
188 if (r != ERROR_SUCCESS)
191 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
192 if (pcchSource && *pcchSource >= len)
193 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
198 *pcchSource = len - 1;
205 if (r == ERROR_SUCCESS)
207 if (szSource || !pcchSource) index++;
209 else if (dwIndex > index)
215 /******************************************************************
216 * MsiSourceListEnumSourcesW (MSI.@)
218 UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid,
219 MSIINSTALLCONTEXT dwContext,
220 DWORD dwOptions, DWORD dwIndex,
221 LPWSTR szSource, LPDWORD pcchSource)
223 WCHAR squished_pc[GUID_SIZE];
228 UINT r = ERROR_INVALID_PARAMETER;
229 static int index = 0;
231 static const WCHAR format[] = {'%','d',0};
233 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch),
234 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
239 if (!szProductCodeOrPatch || !squash_guid(szProductCodeOrPatch, squished_pc))
242 if (szSource && !pcchSource)
245 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
248 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
251 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
254 if (dwIndex != index)
257 r = OpenSourceKey(szProductCodeOrPatch, &source,
258 dwOptions, dwContext, FALSE);
259 if (r != ERROR_SUCCESS)
262 if (dwOptions & MSISOURCETYPE_NETWORK)
263 r = OpenNetworkSubkey(source, &subkey, FALSE);
264 else if (dwOptions & MSISOURCETYPE_URL)
265 r = OpenURLSubkey(source, &subkey, FALSE);
267 if (r != ERROR_SUCCESS)
269 r = ERROR_NO_MORE_ITEMS;
273 sprintfW(name, format, dwIndex + 1);
275 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
276 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
277 r = ERROR_NO_MORE_ITEMS;
283 if (r == ERROR_SUCCESS)
285 if (szSource || !pcchSource) index++;
287 else if (dwIndex > index)
293 /******************************************************************
294 * MsiSourceListGetInfoA (MSI.@)
296 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
297 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
298 LPCSTR szProperty, LPSTR szValue,
302 LPWSTR product = NULL;
303 LPWSTR usersid = NULL;
304 LPWSTR property = NULL;
308 if (szValue && !pcchValue)
309 return ERROR_INVALID_PARAMETER;
311 if (szProduct) product = strdupAtoW(szProduct);
312 if (szUserSid) usersid = strdupAtoW(szUserSid);
313 if (szProperty) property = strdupAtoW(szProperty);
315 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
316 property, NULL, &len);
317 if (ret != ERROR_SUCCESS)
320 value = msi_alloc(++len * sizeof(WCHAR));
322 return ERROR_OUTOFMEMORY;
325 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
326 property, value, &len);
327 if (ret != ERROR_SUCCESS)
330 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
331 if (*pcchValue >= len)
332 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
334 ret = ERROR_MORE_DATA;
336 *pcchValue = len - 1;
346 /******************************************************************
347 * MsiSourceListGetInfoW (MSI.@)
349 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
350 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
351 LPCWSTR szProperty, LPWSTR szValue,
354 WCHAR squished_pc[GUID_SIZE];
358 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
360 if (!szProduct || !squash_guid(szProduct, squished_pc))
361 return ERROR_INVALID_PARAMETER;
363 if (szValue && !pcchValue)
364 return ERROR_INVALID_PARAMETER;
366 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
367 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
368 dwContext != MSIINSTALLCONTEXT_MACHINE)
369 return ERROR_INVALID_PARAMETER;
372 return ERROR_INVALID_PARAMETER;
375 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
377 if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED)
378 FIXME("Unhandled context %d\n", dwContext);
380 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
381 if (rc != ERROR_SUCCESS)
384 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
387 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
388 if (rc == ERROR_SUCCESS)
389 rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW,
390 0, 0, (LPBYTE)szValue, pcchValue);
391 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
392 rc = ERROR_UNKNOWN_PROPERTY;
395 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0)
398 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
399 if (rc == ERROR_SUCCESS)
400 rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0,
401 (LPBYTE)szValue, pcchValue);
402 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
403 rc = ERROR_UNKNOWN_PROPERTY;
406 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
411 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
414 rc = ERROR_UNKNOWN_PROPERTY;
418 buffer = msi_alloc(size);
419 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
420 0, 0, (LPBYTE)buffer,&size);
421 ptr = strchrW(buffer,';');
422 if (ptr) ptr = strchrW(ptr+1,';');
424 rc = ERROR_UNKNOWN_PROPERTY;
428 lstrcpynW(szValue, ptr, *pcchValue);
429 if (lstrlenW(ptr) > *pcchValue)
431 *pcchValue = lstrlenW(ptr)+1;
432 rc = ERROR_MORE_DATA;
440 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0)
445 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
448 rc = ERROR_UNKNOWN_PROPERTY;
451 buffer = msi_alloc(size);
452 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
453 0, 0, (LPBYTE)buffer,&size);
456 rc = ERROR_MORE_DATA;
461 szValue[0] = buffer[0];
467 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
469 *pcchValue = *pcchValue * sizeof(WCHAR);
470 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
471 (LPBYTE)szValue, pcchValue);
472 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
480 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
482 szValue[*pcchValue] = '\0';
487 FIXME("Unknown property %s\n",debugstr_w(szProperty));
488 rc = ERROR_UNKNOWN_PROPERTY;
491 RegCloseKey(sourcekey);
495 /******************************************************************
496 * MsiSourceListSetInfoA (MSI.@)
498 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
499 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
500 LPCSTR szProperty, LPCSTR szValue)
503 LPWSTR product = NULL;
504 LPWSTR usersid = NULL;
505 LPWSTR property = NULL;
508 if (szProduct) product = strdupAtoW(szProduct);
509 if (szUserSid) usersid = strdupAtoW(szUserSid);
510 if (szProperty) property = strdupAtoW(szProperty);
511 if (szValue) value = strdupAtoW(szValue);
513 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
524 static UINT set_last_used_source(HKEY source, LPCWSTR product, LPCWSTR usersid,
525 MSIINSTALLCONTEXT context, DWORD options,
534 static const WCHAR format[] = {'%','c',';','%','i',';','%','s',0};
536 if (options & MSISOURCETYPE_NETWORK)
538 else if (options & MSISOURCETYPE_URL)
541 return ERROR_INVALID_PARAMETER;
543 /* make sure the source is registered */
544 r = MsiSourceListAddSourceExW(product, usersid, context,
546 if (r != ERROR_SUCCESS)
549 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
550 index, NULL, NULL)) == ERROR_SUCCESS)
553 if (r != ERROR_NO_MORE_ITEMS)
556 size = (lstrlenW(format) + lstrlenW(value) + 7) * sizeof(WCHAR);
557 buffer = msi_alloc(size);
559 return ERROR_OUTOFMEMORY;
561 sprintfW(buffer, format, typechar, index, value);
563 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
564 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
565 REG_SZ, (LPBYTE)buffer, size);
571 /******************************************************************
572 * MsiSourceListSetInfoW (MSI.@)
574 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
575 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
576 LPCWSTR szProperty, LPCWSTR szValue)
578 WCHAR squished_pc[GUID_SIZE];
579 HKEY sourcekey, media;
583 static const WCHAR media_package[] = {
584 'M','e','d','i','a','P','a','c','k','a','g','e',0
587 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
588 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
590 if (!szProduct || !squash_guid(szProduct, squished_pc))
591 return ERROR_INVALID_PARAMETER;
594 return ERROR_INVALID_PARAMETER;
597 return ERROR_UNKNOWN_PROPERTY;
599 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
600 return ERROR_INVALID_PARAMETER;
602 if (dwOptions & MSICODE_PATCH)
604 FIXME("Unhandled options MSICODE_PATCH\n");
605 return ERROR_UNKNOWN_PATCH;
608 property = szProperty;
609 if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW))
610 property = media_package;
612 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
613 if (rc != ERROR_SUCCESS)
616 if (lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW) &&
617 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
619 RegCloseKey(sourcekey);
620 return ERROR_INVALID_PARAMETER;
623 if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) ||
624 !lstrcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW))
626 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
627 if (rc == ERROR_SUCCESS)
629 rc = msi_reg_set_val_str(media, property, szValue);
633 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
635 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
636 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
637 REG_SZ, (const BYTE *)szValue, size);
638 if (rc != ERROR_SUCCESS)
639 rc = ERROR_UNKNOWN_PROPERTY;
641 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
642 rc = set_last_used_source(sourcekey, szProduct, szUserSid, dwContext,
645 rc = ERROR_UNKNOWN_PROPERTY;
647 RegCloseKey(sourcekey);
652 /******************************************************************
653 * MsiSourceListAddSourceW (MSI.@)
655 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
656 DWORD dwReserved, LPCWSTR szSource)
659 LPWSTR sidstr = NULL;
663 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
665 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
667 PSID psid = msi_alloc(sidsize);
669 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
670 ConvertSidToStringSidW(psid, &sidstr);
675 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
676 MSIINSTALLCONTEXT_USERMANAGED, MSISOURCETYPE_NETWORK, szSource, 0);
684 /******************************************************************
685 * MsiSourceListAddSourceA (MSI.@)
687 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
688 DWORD dwReserved, LPCSTR szSource)
695 szwproduct = strdupAtoW( szProduct );
696 szwusername = strdupAtoW( szUserName );
697 szwsource = strdupAtoW( szSource );
699 ret = MsiSourceListAddSourceW(szwproduct, szwusername, 0, szwsource);
701 msi_free(szwproduct);
702 msi_free(szwusername);
708 /******************************************************************
709 * MsiSourceListAddSourceExA (MSI.@)
711 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
712 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
715 LPWSTR product, usersid, source;
717 product = strdupAtoW(szProduct);
718 usersid = strdupAtoW(szUserSid);
719 source = strdupAtoW(szSource);
721 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
722 dwOptions, source, dwIndex);
731 static void free_source_list(struct list *sourcelist)
733 while (!list_empty(sourcelist))
735 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
736 list_remove(&info->entry);
737 msi_free(info->path);
742 static void add_source_to_list(struct list *sourcelist, media_info *info)
746 static const WCHAR fmt[] = {'%','i',0};
748 if (list_empty(sourcelist))
750 list_add_head(sourcelist, &info->entry);
754 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
756 if (!found && info->index < iter->index)
759 list_add_before(&iter->entry, &info->entry);
762 /* update the rest of the list */
764 sprintfW(iter->szIndex, fmt, ++iter->index);
768 list_add_after(&iter->entry, &info->entry);
771 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
773 UINT r = ERROR_SUCCESS;
776 DWORD size, val_size;
781 while (r == ERROR_SUCCESS)
783 size = sizeof(name) / sizeof(name[0]);
784 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
785 if (r != ERROR_SUCCESS)
788 entry = msi_alloc(sizeof(media_info));
792 entry->path = msi_alloc(val_size);
799 lstrcpyW(entry->szIndex, name);
800 entry->index = atoiW(name);
803 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
804 NULL, (LPBYTE)entry->path, &val_size);
805 if (r != ERROR_SUCCESS)
807 msi_free(entry->path);
813 add_source_to_list(sourcelist, entry);
818 free_source_list(sourcelist);
819 return ERROR_OUTOFMEMORY;
822 /******************************************************************
823 * MsiSourceListAddSourceExW (MSI.@)
825 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
826 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
832 struct list sourcelist;
834 WCHAR squished_pc[GUID_SIZE];
840 static const WCHAR fmt[] = {'%','i',0};
841 static const WCHAR one[] = {'1',0};
842 static const WCHAR backslash[] = {'\\',0};
843 static const WCHAR forwardslash[] = {'/',0};
845 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
846 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
848 if (!szProduct || !squash_guid(szProduct, squished_pc))
849 return ERROR_INVALID_PARAMETER;
851 if (!szSource || !*szSource)
852 return ERROR_INVALID_PARAMETER;
854 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
855 return ERROR_INVALID_PARAMETER;
857 if (dwOptions & MSICODE_PATCH)
859 FIXME("Unhandled options MSICODE_PATCH\n");
860 return ERROR_FUNCTION_FAILED;
863 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
864 return ERROR_INVALID_PARAMETER;
866 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
867 if (rc != ERROR_SUCCESS)
870 if (dwOptions & MSISOURCETYPE_NETWORK)
871 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
872 else if (dwOptions & MSISOURCETYPE_URL)
873 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
874 else if (dwOptions & MSISOURCETYPE_MEDIA)
875 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
878 ERR("unknown media type: %08x\n", dwOptions);
879 RegCloseKey(sourcekey);
880 return ERROR_FUNCTION_FAILED;
883 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? backslash : forwardslash;
884 if (szSource[lstrlenW(szSource) - 1] == *postfix)
885 source = strdupW(szSource);
888 size = lstrlenW(szSource) + 2;
889 source = msi_alloc(size * sizeof(WCHAR));
890 lstrcpyW(source, szSource);
891 lstrcatW(source, postfix);
894 list_init(&sourcelist);
895 rc = fill_source_list(&sourcelist, typekey, &count);
896 if (rc != ERROR_NO_MORE_ITEMS)
899 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
903 rc = RegSetValueExW(typekey, one, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
906 else if (dwIndex > count)
908 sprintfW(name, fmt, count + 1);
909 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
914 /* add to the end of the list */
918 sprintfW(name, fmt, dwIndex);
919 info = msi_alloc(sizeof(media_info));
922 rc = ERROR_OUTOFMEMORY;
926 info->path = strdupW(source);
927 lstrcpyW(info->szIndex, name);
928 info->index = dwIndex;
929 add_source_to_list(&sourcelist, info);
931 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
933 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
934 rc = RegSetValueExW(typekey, info->szIndex, 0,
935 REG_EXPAND_SZ, (LPBYTE)info->path, size);
936 if (rc != ERROR_SUCCESS)
942 free_source_list(&sourcelist);
944 RegCloseKey(typekey);
945 RegCloseKey(sourcekey);
949 /******************************************************************
950 * MsiSourceListAddMediaDisk(MSI.@)
952 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
953 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
954 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
960 static const WCHAR fmt[] = {'%','i',0};
961 static const WCHAR disk_fmt[] = {'%','s',';','%','s',0};
962 static const WCHAR empty[1] = {0};
967 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
968 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
969 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
971 if (!szProduct || lstrlenW(szProduct) > 39)
972 return ERROR_INVALID_PARAMETER;
974 if (dwOptions & MSICODE_PATCH)
976 FIXME("Unhandled options MSICODE_PATCH\n");
977 return ERROR_FUNCTION_FAILED;
981 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
983 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
984 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
986 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, TRUE);
987 if (rc != ERROR_SUCCESS)
988 return ERROR_UNKNOWN_PRODUCT;
990 OpenMediaSubkey(sourcekey,&mediakey,TRUE);
992 sprintfW(szIndex,fmt,dwDiskId);
997 size +=lstrlenW(szVolumeLabel);
1004 size +=lstrlenW(szDiskPrompt);
1010 size *=sizeof(WCHAR);
1012 buffer = msi_alloc(size);
1013 sprintfW(buffer,disk_fmt,pt1,pt2);
1015 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1018 RegCloseKey(sourcekey);
1019 RegCloseKey(mediakey);
1021 return ERROR_SUCCESS;
1024 /******************************************************************
1025 * MsiSourceListClearAllA (MSI.@)
1027 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
1029 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
1030 return ERROR_SUCCESS;
1033 /******************************************************************
1034 * MsiSourceListClearAllW (MSI.@)
1036 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
1038 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
1039 return ERROR_SUCCESS;