/* * Implementation of the Microsoft Installer (msi.dll) * * Copyright 2005 Aric Stewart for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "msipriv.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); /* * These apis are defined in MSI 3.0 */ typedef struct tagMediaInfo { struct list entry; LPWSTR path; WCHAR szIndex[10]; DWORD index; } media_info; static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions, MSIINSTALLCONTEXT context, BOOL create) { HKEY rootkey = 0; UINT rc = ERROR_FUNCTION_FAILED; if (context == MSIINSTALLCONTEXT_USERUNMANAGED) { if (dwOptions & MSICODE_PATCH) rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create); else rc = MSIREG_OpenProductKey(szProduct, NULL, context, &rootkey, create); } else if (context == MSIINSTALLCONTEXT_USERMANAGED) { if (dwOptions & MSICODE_PATCH) rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create); else rc = MSIREG_OpenProductKey(szProduct, NULL, context, &rootkey, create); } else if (context == MSIINSTALLCONTEXT_MACHINE) { if (dwOptions & MSICODE_PATCH) rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create); else rc = MSIREG_OpenProductKey(szProduct, NULL, context, &rootkey, create); } if (rc != ERROR_SUCCESS) { if (dwOptions & MSICODE_PATCH) return ERROR_UNKNOWN_PATCH; else return ERROR_UNKNOWN_PRODUCT; } if (create) rc = RegCreateKeyW(rootkey, szSourceList, key); else { rc = RegOpenKeyW(rootkey,szSourceList, key); if (rc != ERROR_SUCCESS) rc = ERROR_BAD_CONFIGURATION; } return rc; } static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create) { UINT rc; static const WCHAR media[] = {'M','e','d','i','a',0}; if (create) rc = RegCreateKeyW(rootkey, media, key); else rc = RegOpenKeyW(rootkey,media, key); return rc; } static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create) { UINT rc; static const WCHAR net[] = {'N','e','t',0}; if (create) rc = RegCreateKeyW(rootkey, net, key); else rc = RegOpenKeyW(rootkey, net, key); return rc; } static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create) { UINT rc; static const WCHAR URL[] = {'U','R','L',0}; if (create) rc = RegCreateKeyW(rootkey, URL, key); else rc = RegOpenKeyW(rootkey, URL, key); return rc; } /****************************************************************** * MsiSourceListEnumMediaDisksA (MSI.@) */ UINT WINAPI MsiSourceListEnumMediaDisksA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId, LPSTR szVolumeLabel, LPDWORD pcchVolumeLabel, LPSTR szDiskPrompt, LPDWORD pcchDiskPrompt) { LPWSTR product = NULL; LPWSTR usersid = NULL; LPWSTR volume = NULL; LPWSTR prompt = NULL; UINT r = ERROR_INVALID_PARAMETER; TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId, szVolumeLabel, pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt); if (szDiskPrompt && !pcchDiskPrompt) return ERROR_INVALID_PARAMETER; if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode); if (szUserSid) usersid = strdupAtoW(szUserSid); /* FIXME: add tests for an invalid format */ if (pcchVolumeLabel) volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR)); if (pcchDiskPrompt) prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR)); if (volume) *volume = '\0'; if (prompt) *prompt = '\0'; r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions, dwIndex, pdwDiskId, volume, pcchVolumeLabel, prompt, pcchDiskPrompt); if (r != ERROR_SUCCESS) goto done; if (szVolumeLabel && pcchVolumeLabel) WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel, *pcchVolumeLabel + 1, NULL, NULL); if (szDiskPrompt) WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt, *pcchDiskPrompt + 1, NULL, NULL); done: msi_free(product); msi_free(usersid); msi_free(volume); msi_free(prompt); return r; } /****************************************************************** * MsiSourceListEnumMediaDisksW (MSI.@) */ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId, LPWSTR szVolumeLabel, LPDWORD pcchVolumeLabel, LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt) { WCHAR squished_pc[GUID_SIZE]; WCHAR convert[11]; LPWSTR value = NULL; LPWSTR data = NULL; LPWSTR ptr, ptr2; HKEY source, media; DWORD valuesz, datasz = 0; DWORD type; DWORD numvals, size; LONG res; UINT r; static DWORD index = 0; static const WCHAR fmt[] = {'#','%','d',0}; TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel, pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt); if (!szProductCodeOrPatchCode || !squash_guid(szProductCodeOrPatchCode, squished_pc)) return ERROR_INVALID_PARAMETER; if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid) return ERROR_INVALID_PARAMETER; if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH) return ERROR_INVALID_PARAMETER; if (szDiskPrompt && !pcchDiskPrompt) return ERROR_INVALID_PARAMETER; if (dwIndex == 0) index = 0; if (dwIndex != index) return ERROR_INVALID_PARAMETER; r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE); if (r != ERROR_SUCCESS) return r; r = OpenMediaSubkey(source, &media, FALSE); if (r != ERROR_SUCCESS) { RegCloseKey(source); return ERROR_NO_MORE_ITEMS; } if (!pcchVolumeLabel && !pcchDiskPrompt) { r = RegEnumValueW(media, dwIndex, NULL, NULL, NULL, &type, NULL, NULL); goto done; } res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL, NULL, &numvals, &valuesz, &datasz, NULL, NULL); if (res != ERROR_SUCCESS) { r = ERROR_BAD_CONFIGURATION; goto done; } value = msi_alloc(++valuesz * sizeof(WCHAR)); data = msi_alloc(++datasz * sizeof(WCHAR)); if (!value || !data) { r = ERROR_OUTOFMEMORY; goto done; } r = RegEnumValueW(media, dwIndex, value, &valuesz, NULL, &type, (LPBYTE)data, &datasz); if (r != ERROR_SUCCESS) goto done; if (pdwDiskId) *pdwDiskId = atolW(value); ptr2 = data; ptr = strchrW(data, ';'); if (!ptr) ptr = data; else *ptr = '\0'; if (pcchVolumeLabel) { if (type == REG_DWORD) { sprintfW(convert, fmt, *data); size = lstrlenW(convert); ptr2 = convert; } else size = lstrlenW(data); if (size >= *pcchVolumeLabel) r = ERROR_MORE_DATA; else if (szVolumeLabel) lstrcpyW(szVolumeLabel, ptr2); *pcchVolumeLabel = size; } if (pcchDiskPrompt) { if (!*ptr) ptr++; if (type == REG_DWORD) { sprintfW(convert, fmt, *ptr); size = lstrlenW(convert); ptr = convert; } else size = lstrlenW(ptr); if (size >= *pcchDiskPrompt) r = ERROR_MORE_DATA; else if (szDiskPrompt) lstrcpyW(szDiskPrompt, ptr); *pcchDiskPrompt = size; } index++; done: msi_free(value); msi_free(data); RegCloseKey(source); return r; } /****************************************************************** * MsiSourceListEnumSourcesA (MSI.@) */ UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, LPSTR szSource, LPDWORD pcchSource) { LPWSTR product = NULL; LPWSTR usersid = NULL; LPWSTR source = NULL; DWORD len = 0; UINT r = ERROR_INVALID_PARAMETER; static DWORD index = 0; TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch), debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource); if (dwIndex == 0) index = 0; if (szSource && !pcchSource) goto done; if (dwIndex != index) goto done; if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch); if (szUserSid) usersid = strdupAtoW(szUserSid); r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions, dwIndex, NULL, &len); if (r != ERROR_SUCCESS) goto done; source = msi_alloc(++len * sizeof(WCHAR)); if (!source) { r = ERROR_OUTOFMEMORY; goto done; } *source = '\0'; r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions, dwIndex, source, &len); if (r != ERROR_SUCCESS) goto done; len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL); if (pcchSource && *pcchSource >= len) WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL); else if (szSource) r = ERROR_MORE_DATA; if (pcchSource) *pcchSource = len - 1; done: msi_free(product); msi_free(usersid); msi_free(source); if (r == ERROR_SUCCESS) { if (szSource || !pcchSource) index++; } else if (dwIndex > index) index = 0; return r; } /****************************************************************** * MsiSourceListEnumSourcesW (MSI.@) */ UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, LPWSTR szSource, LPDWORD pcchSource) { WCHAR squished_pc[GUID_SIZE]; WCHAR name[32]; HKEY source = NULL; HKEY subkey = NULL; LONG res; UINT r = ERROR_INVALID_PARAMETER; static DWORD index = 0; static const WCHAR format[] = {'%','d',0}; TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch), debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource); if (dwIndex == 0) index = 0; if (!szProductCodeOrPatch || !squash_guid(szProductCodeOrPatch, squished_pc)) goto done; if (szSource && !pcchSource) goto done; if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))) goto done; if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL)) goto done; if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid) goto done; if (dwIndex != index) goto done; r = OpenSourceKey(szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE); if (r != ERROR_SUCCESS) goto done; if (dwOptions & MSISOURCETYPE_NETWORK) r = OpenNetworkSubkey(source, &subkey, FALSE); else if (dwOptions & MSISOURCETYPE_URL) r = OpenURLSubkey(source, &subkey, FALSE); if (r != ERROR_SUCCESS) { r = ERROR_NO_MORE_ITEMS; goto done; } sprintfW(name, format, dwIndex + 1); res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource); if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) r = ERROR_NO_MORE_ITEMS; done: RegCloseKey(subkey); RegCloseKey(source); if (r == ERROR_SUCCESS) { if (szSource || !pcchSource) index++; } else if (dwIndex > index) index = 0; return r; } /****************************************************************** * MsiSourceListGetInfoA (MSI.@) */ UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szProperty, LPSTR szValue, LPDWORD pcchValue) { UINT ret; LPWSTR product = NULL; LPWSTR usersid = NULL; LPWSTR property = NULL; LPWSTR value = NULL; DWORD len = 0; if (szValue && !pcchValue) return ERROR_INVALID_PARAMETER; if (szProduct) product = strdupAtoW(szProduct); if (szUserSid) usersid = strdupAtoW(szUserSid); if (szProperty) property = strdupAtoW(szProperty); ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions, property, NULL, &len); if (ret != ERROR_SUCCESS) goto done; value = msi_alloc(++len * sizeof(WCHAR)); if (!value) return ERROR_OUTOFMEMORY; *value = '\0'; ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions, property, value, &len); if (ret != ERROR_SUCCESS) goto done; len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL); if (*pcchValue >= len) WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL); else if (szValue) ret = ERROR_MORE_DATA; *pcchValue = len - 1; done: msi_free(product); msi_free(usersid); msi_free(property); msi_free(value); return ret; } /****************************************************************** * MsiSourceListGetInfoW (MSI.@) */ UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szProperty, LPWSTR szValue, LPDWORD pcchValue) { WCHAR squished_pc[GUID_SIZE]; HKEY sourcekey, media; LPWSTR source, ptr; DWORD size; UINT rc; static const WCHAR mediapack[] = { 'M','e','d','i','a','P','a','c','k','a','g','e',0}; TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty)); if (!szProduct || !squash_guid(szProduct, squished_pc)) return ERROR_INVALID_PARAMETER; if (szValue && !pcchValue) return ERROR_INVALID_PARAMETER; if (dwContext != MSIINSTALLCONTEXT_USERMANAGED && dwContext != MSIINSTALLCONTEXT_USERUNMANAGED && dwContext != MSIINSTALLCONTEXT_MACHINE) return ERROR_INVALID_PARAMETER; if (!szProperty) return ERROR_INVALID_PARAMETER; if (szUserSid) FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid)); rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE); if (rc != ERROR_SUCCESS) return rc; if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) || !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW )) { rc = OpenMediaSubkey(sourcekey, &media, FALSE); if (rc != ERROR_SUCCESS) { RegCloseKey(sourcekey); return ERROR_SUCCESS; } if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW )) szProperty = mediapack; RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue); RegCloseKey(media); } else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) || !strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW )) { rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0, NULL, &size); if (rc != ERROR_SUCCESS) { RegCloseKey(sourcekey); return ERROR_SUCCESS; } source = msi_alloc(size); RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0, (LPBYTE)source, &size); if (!*source) { msi_free(source); RegCloseKey(sourcekey); return ERROR_SUCCESS; } if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW )) { if (*source != 'n' && *source != 'u' && *source != 'm') { msi_free(source); RegCloseKey(sourcekey); return ERROR_SUCCESS; } ptr = source; source[1] = '\0'; } else { ptr = strrchrW(source, ';'); if (!ptr) ptr = source; else ptr++; } if (szValue) { if (strlenW(ptr) < *pcchValue) lstrcpyW(szValue, ptr); else rc = ERROR_MORE_DATA; } *pcchValue = lstrlenW(ptr); msi_free(source); } else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW )) { *pcchValue = *pcchValue * sizeof(WCHAR); rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0, (LPBYTE)szValue, pcchValue); if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA) { *pcchValue = 0; rc = ERROR_SUCCESS; } else { if (*pcchValue) *pcchValue = (*pcchValue - 1) / sizeof(WCHAR); if (szValue) szValue[*pcchValue] = '\0'; } } else { FIXME("Unknown property %s\n",debugstr_w(szProperty)); rc = ERROR_UNKNOWN_PROPERTY; } RegCloseKey(sourcekey); return rc; } /****************************************************************** * MsiSourceListSetInfoA (MSI.@) */ UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szProperty, LPCSTR szValue) { UINT ret; LPWSTR product = NULL; LPWSTR usersid = NULL; LPWSTR property = NULL; LPWSTR value = NULL; if (szProduct) product = strdupAtoW(szProduct); if (szUserSid) usersid = strdupAtoW(szUserSid); if (szProperty) property = strdupAtoW(szProperty); if (szValue) value = strdupAtoW(szValue); ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions, property, value); msi_free(product); msi_free(usersid); msi_free(property); msi_free(value); return ret; } UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid, MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value) { HKEY source; LPWSTR buffer; WCHAR typechar; DWORD size; UINT r; int index = 1; static const WCHAR format[] = {'%','c',';','%','i',';','%','s',0}; if (options & MSISOURCETYPE_NETWORK) typechar = 'n'; else if (options & MSISOURCETYPE_URL) typechar = 'u'; else if (options & MSISOURCETYPE_MEDIA) typechar = 'm'; else return ERROR_INVALID_PARAMETER; if (!(options & MSISOURCETYPE_MEDIA)) { r = MsiSourceListAddSourceExW(product, usersid, context, options, value, 0); if (r != ERROR_SUCCESS) return r; index = 0; while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options, index, NULL, NULL)) == ERROR_SUCCESS) index++; if (r != ERROR_NO_MORE_ITEMS) return r; } size = (lstrlenW(format) + lstrlenW(value) + 7) * sizeof(WCHAR); buffer = msi_alloc(size); if (!buffer) return ERROR_OUTOFMEMORY; r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE); if (r != ERROR_SUCCESS) { msi_free(buffer); return r; } sprintfW(buffer, format, typechar, index, value); size = (lstrlenW(buffer) + 1) * sizeof(WCHAR); r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, REG_SZ, (LPBYTE)buffer, size); msi_free(buffer); RegCloseKey(source); return r; } /****************************************************************** * MsiSourceListSetInfoW (MSI.@) */ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szProperty, LPCWSTR szValue) { WCHAR squished_pc[GUID_SIZE]; HKEY sourcekey, media; LPCWSTR property; UINT rc; static const WCHAR media_package[] = { 'M','e','d','i','a','P','a','c','k','a','g','e',0 }; TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue)); if (!szProduct || !squash_guid(szProduct, squished_pc)) return ERROR_INVALID_PARAMETER; if (!szProperty) return ERROR_INVALID_PARAMETER; if (!szValue) return ERROR_UNKNOWN_PROPERTY; if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid) return ERROR_INVALID_PARAMETER; if (dwOptions & MSICODE_PATCH) { FIXME("Unhandled options MSICODE_PATCH\n"); return ERROR_UNKNOWN_PATCH; } property = szProperty; if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW )) property = media_package; rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); if (rc != ERROR_SUCCESS) return rc; if (strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) && dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)) { RegCloseKey(sourcekey); return ERROR_INVALID_PARAMETER; } if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) || !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW )) { rc = OpenMediaSubkey(sourcekey, &media, TRUE); if (rc == ERROR_SUCCESS) { rc = msi_reg_set_val_str(media, property, szValue); RegCloseKey(media); } } else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW )) { DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR); rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, REG_SZ, (const BYTE *)szValue, size); if (rc != ERROR_SUCCESS) rc = ERROR_UNKNOWN_PROPERTY; } else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW )) { if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))) rc = ERROR_INVALID_PARAMETER; else rc = msi_set_last_used_source(szProduct, szUserSid, dwContext, dwOptions, szValue); } else rc = ERROR_UNKNOWN_PROPERTY; RegCloseKey(sourcekey); return rc; } /****************************************************************** * MsiSourceListAddSourceW (MSI.@) */ UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved, LPCWSTR szSource) { WCHAR squished_pc[GUID_SIZE]; INT ret; LPWSTR sidstr = NULL; DWORD sidsize = 0; DWORD domsize = 0; DWORD context; HKEY hkey = 0; UINT r; TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource)); if (!szSource || !*szSource) return ERROR_INVALID_PARAMETER; if (dwReserved != 0) return ERROR_INVALID_PARAMETER; if (!szProduct || !squash_guid(szProduct, squished_pc)) return ERROR_INVALID_PARAMETER; if (!szUserName || !*szUserName) context = MSIINSTALLCONTEXT_MACHINE; else { if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL)) { PSID psid = msi_alloc(sidsize); if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL)) ConvertSidToStringSidW(psid, &sidstr); msi_free(psid); } r = MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE); if (r == ERROR_SUCCESS) context = MSIINSTALLCONTEXT_USERMANAGED; else { r = MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hkey, FALSE); if (r != ERROR_SUCCESS) return ERROR_UNKNOWN_PRODUCT; context = MSIINSTALLCONTEXT_USERUNMANAGED; } RegCloseKey(hkey); } ret = MsiSourceListAddSourceExW(szProduct, sidstr, context, MSISOURCETYPE_NETWORK, szSource, 0); if (sidstr) LocalFree(sidstr); return ret; } /****************************************************************** * MsiSourceListAddSourceA (MSI.@) */ UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved, LPCSTR szSource) { INT ret; LPWSTR szwproduct; LPWSTR szwusername; LPWSTR szwsource; szwproduct = strdupAtoW( szProduct ); szwusername = strdupAtoW( szUserName ); szwsource = strdupAtoW( szSource ); ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource); msi_free(szwproduct); msi_free(szwusername); msi_free(szwsource); return ret; } /****************************************************************** * MsiSourceListAddSourceExA (MSI.@) */ UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex) { UINT ret; LPWSTR product, usersid, source; product = strdupAtoW(szProduct); usersid = strdupAtoW(szUserSid); source = strdupAtoW(szSource); ret = MsiSourceListAddSourceExW(product, usersid, dwContext, dwOptions, source, dwIndex); msi_free(product); msi_free(usersid); msi_free(source); return ret; } static void free_source_list(struct list *sourcelist) { while (!list_empty(sourcelist)) { media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry); list_remove(&info->entry); msi_free(info->path); msi_free(info); } } static void add_source_to_list(struct list *sourcelist, media_info *info, DWORD *index) { media_info *iter; BOOL found = FALSE; static const WCHAR fmt[] = {'%','i',0}; if (index) *index = 0; if (list_empty(sourcelist)) { list_add_head(sourcelist, &info->entry); return; } LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry) { if (!found && info->index < iter->index) { found = TRUE; list_add_before(&iter->entry, &info->entry); } /* update the rest of the list */ if (found) sprintfW(iter->szIndex, fmt, ++iter->index); else if (index) (*index)++; } if (!found) list_add_after(&iter->entry, &info->entry); } static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count) { UINT r = ERROR_SUCCESS; DWORD index = 0; WCHAR name[10]; DWORD size, val_size; media_info *entry; *count = 0; while (r == ERROR_SUCCESS) { size = sizeof(name) / sizeof(name[0]); r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size); if (r != ERROR_SUCCESS) return r; entry = msi_alloc(sizeof(media_info)); if (!entry) goto error; entry->path = msi_alloc(val_size); if (!entry->path) { msi_free(entry); goto error; } lstrcpyW(entry->szIndex, name); entry->index = atoiW(name); size++; r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, (LPBYTE)entry->path, &val_size); if (r != ERROR_SUCCESS) { msi_free(entry->path); msi_free(entry); goto error; } index = ++(*count); add_source_to_list(sourcelist, entry, NULL); } error: *count = -1; free_source_list(sourcelist); return ERROR_OUTOFMEMORY; } /****************************************************************** * MsiSourceListAddSourceExW (MSI.@) */ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource, DWORD dwIndex) { HKEY sourcekey; HKEY typekey; UINT rc; struct list sourcelist; media_info *info; WCHAR squished_pc[GUID_SIZE]; WCHAR name[10]; LPWSTR source; LPCWSTR postfix; DWORD size, count; DWORD index; static const WCHAR fmt[] = {'%','i',0}; TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szSource), dwIndex); if (!szProduct || !squash_guid(szProduct, squished_pc)) return ERROR_INVALID_PARAMETER; if (!szSource || !*szSource) return ERROR_INVALID_PARAMETER; if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))) return ERROR_INVALID_PARAMETER; if (dwOptions & MSICODE_PATCH) { FIXME("Unhandled options MSICODE_PATCH\n"); return ERROR_FUNCTION_FAILED; } if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE)) return ERROR_INVALID_PARAMETER; rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); if (rc != ERROR_SUCCESS) return rc; if (dwOptions & MSISOURCETYPE_NETWORK) rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE); else if (dwOptions & MSISOURCETYPE_URL) rc = OpenURLSubkey(sourcekey, &typekey, TRUE); else if (dwOptions & MSISOURCETYPE_MEDIA) rc = OpenMediaSubkey(sourcekey, &typekey, TRUE); else { ERR("unknown media type: %08x\n", dwOptions); RegCloseKey(sourcekey); return ERROR_FUNCTION_FAILED; } if (rc != ERROR_SUCCESS) { ERR("can't open subkey %u\n", rc); RegCloseKey(sourcekey); return rc; } postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? szBackSlash : szForwardSlash; if (szSource[lstrlenW(szSource) - 1] == *postfix) source = strdupW(szSource); else { size = lstrlenW(szSource) + 2; source = msi_alloc(size * sizeof(WCHAR)); lstrcpyW(source, szSource); lstrcatW(source, postfix); } list_init(&sourcelist); rc = fill_source_list(&sourcelist, typekey, &count); if (rc != ERROR_NO_MORE_ITEMS) return rc; size = (lstrlenW(source) + 1) * sizeof(WCHAR); if (count == 0) { rc = RegSetValueExW(typekey, szOne, 0, REG_EXPAND_SZ, (LPBYTE)source, size); goto done; } else if (dwIndex > count || dwIndex == 0) { sprintfW(name, fmt, count + 1); rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size); goto done; } else { sprintfW(name, fmt, dwIndex); info = msi_alloc(sizeof(media_info)); if (!info) { rc = ERROR_OUTOFMEMORY; goto done; } info->path = strdupW(source); lstrcpyW(info->szIndex, name); info->index = dwIndex; add_source_to_list(&sourcelist, info, &index); LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry) { if (info->index < index) continue; size = (lstrlenW(info->path) + 1) * sizeof(WCHAR); rc = RegSetValueExW(typekey, info->szIndex, 0, REG_EXPAND_SZ, (LPBYTE)info->path, size); if (rc != ERROR_SUCCESS) goto done; } } done: free_source_list(&sourcelist); msi_free(source); RegCloseKey(typekey); RegCloseKey(sourcekey); return rc; } /****************************************************************** * MsiSourceListAddMediaDiskA (MSI.@) */ UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, LPCSTR szVolumeLabel, LPCSTR szDiskPrompt) { UINT r; LPWSTR product = NULL; LPWSTR usersid = NULL; LPWSTR volume = NULL; LPWSTR prompt = NULL; if (szProduct) product = strdupAtoW(szProduct); if (szUserSid) usersid = strdupAtoW(szUserSid); if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel); if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt); r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions, dwDiskId, volume, prompt); msi_free(product); msi_free(usersid); msi_free(volume); msi_free(prompt); return r; } /****************************************************************** * MsiSourceListAddMediaDiskW (MSI.@) */ UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt) { HKEY sourcekey; HKEY mediakey; UINT rc; WCHAR szIndex[10]; WCHAR squished_pc[GUID_SIZE]; LPWSTR buffer; DWORD size; static const WCHAR fmt[] = {'%','i',0}; TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId, debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt)); if (!szProduct || !squash_guid(szProduct, squished_pc)) return ERROR_INVALID_PARAMETER; if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH) return ERROR_INVALID_PARAMETER; if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt)) return ERROR_INVALID_PARAMETER; if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid) return ERROR_INVALID_PARAMETER; if (dwOptions & MSICODE_PATCH) { FIXME("Unhandled options MSICODE_PATCH\n"); return ERROR_FUNCTION_FAILED; } rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); if (rc != ERROR_SUCCESS) return rc; OpenMediaSubkey(sourcekey, &mediakey, TRUE); sprintfW(szIndex, fmt, dwDiskId); size = 2; if (szVolumeLabel) size += lstrlenW(szVolumeLabel); if (szDiskPrompt) size += lstrlenW(szDiskPrompt); size *= sizeof(WCHAR); buffer = msi_alloc(size); *buffer = '\0'; if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel); lstrcatW(buffer, szSemiColon); if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt); RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size); msi_free(buffer); RegCloseKey(sourcekey); RegCloseKey(mediakey); return ERROR_SUCCESS; } /****************************************************************** * MsiSourceListClearAllA (MSI.@) */ UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved ) { FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved); return ERROR_SUCCESS; } /****************************************************************** * MsiSourceListClearAllW (MSI.@) */ UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved ) { FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved); return ERROR_SUCCESS; } /****************************************************************** * MsiSourceListClearAllExA (MSI.@) */ UINT WINAPI MsiSourceListClearAllExA( LPCSTR szProduct, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions ) { FIXME("(%s %s %d %08x)\n", debugstr_a(szProduct), debugstr_a(szUserSid), dwContext, dwOptions); return ERROR_SUCCESS; } /****************************************************************** * MsiSourceListClearAllExW (MSI.@) */ UINT WINAPI MsiSourceListClearAllExW( LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions ) { FIXME("(%s %s %d %08x)\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions); return ERROR_SUCCESS; } /****************************************************************** * MsiSourceListClearSourceA (MSI.@) */ UINT WINAPI MsiSourceListClearSourceA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource) { FIXME("(%s %s %x %x %s)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), dwContext, dwOptions, debugstr_a(szSource)); return ERROR_SUCCESS; } /****************************************************************** * MsiSourceListClearSourceW (MSI.@) */ UINT WINAPI MsiSourceListClearSourceW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource) { FIXME("(%s %s %x %x %s)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szSource)); return ERROR_SUCCESS; }