1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2005 Aric Stewart for CodeWeavers 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 /* 22 * Actions focused on in this module 23 * 24 * FindRelatedProducts 25 * MigrateFeatureStates (TODO) 26 * RemoveExistingProducts (TODO) 27 */ 28 29 #include <stdarg.h> 30 31 #include "windef.h" 32 #include "winbase.h" 33 #include "winerror.h" 34 #include "winreg.h" 35 #include "wine/debug.h" 36 #include "msidefs.h" 37 #include "msipriv.h" 38 #include "winuser.h" 39 #include "wine/unicode.h" 40 41 WINE_DEFAULT_DEBUG_CHANNEL(msi); 42 43 static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes) 44 { 45 DWORD langdword; 46 47 if (!lang2 || lang2[0]==0) 48 return TRUE; 49 50 langdword = atoiW(lang2); 51 52 if (attributes & msidbUpgradeAttributesLanguagesExclusive) 53 return (lang1 != langdword); 54 else 55 return (lang1 == langdword); 56 } 57 58 static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property, 59 LPCWSTR productid) 60 { 61 LPWSTR prop; 62 LPWSTR newprop; 63 DWORD len; 64 UINT r; 65 66 prop = msi_dup_property(package->db, action_property ); 67 if (prop) 68 len = strlenW(prop); 69 else 70 len = 0; 71 72 /*separator*/ 73 len ++; 74 75 len += strlenW(productid); 76 77 /*null*/ 78 len++; 79 80 newprop = msi_alloc( len*sizeof(WCHAR) ); 81 82 if (prop) 83 { 84 strcpyW(newprop,prop); 85 strcatW(newprop,szSemiColon); 86 } 87 else 88 newprop[0] = 0; 89 strcatW(newprop,productid); 90 91 r = msi_set_property( package->db, action_property, newprop, -1 ); 92 if (r == ERROR_SUCCESS && !strcmpW( action_property, szSourceDir )) 93 msi_reset_folders( package, TRUE ); 94 95 TRACE("Found Related Product... %s now %s\n", 96 debugstr_w(action_property), debugstr_w(newprop)); 97 98 msi_free( prop ); 99 msi_free( newprop ); 100 } 101 102 static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) 103 { 104 MSIPACKAGE *package = param; 105 WCHAR product[SQUASHED_GUID_SIZE]; 106 DWORD index = 0, attributes = 0, sz = sizeof(product)/sizeof(product[0]); 107 LPCWSTR upgrade_code; 108 HKEY hkey = 0; 109 UINT rc = ERROR_SUCCESS; 110 MSIRECORD *uirow; 111 112 upgrade_code = MSI_RecordGetString(rec,1); 113 114 rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE); 115 if (rc != ERROR_SUCCESS) 116 return ERROR_SUCCESS; 117 118 uirow = MSI_CreateRecord(1); 119 attributes = MSI_RecordGetInteger(rec,5); 120 121 while (rc == ERROR_SUCCESS) 122 { 123 rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL); 124 if (rc == ERROR_SUCCESS) 125 { 126 WCHAR productid[GUID_SIZE]; 127 LPCWSTR ver, language, action_property; 128 DWORD check = 0, comp_ver, sz = 0x100; 129 HKEY hukey; 130 INT r; 131 132 TRACE("Looking at index %u product %s\n", index, debugstr_w(product)); 133 134 unsquash_guid(product, productid); 135 if (MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_USERMANAGED, &hukey, FALSE) && 136 MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hukey, FALSE) && 137 MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_MACHINE, &hukey, FALSE)) 138 { 139 TRACE("product key not found\n"); 140 rc = ERROR_SUCCESS; 141 index ++; 142 continue; 143 } 144 145 sz = sizeof(DWORD); 146 RegQueryValueExW(hukey, INSTALLPROPERTY_VERSIONW, NULL, NULL, (LPBYTE)&check, &sz); 147 148 /* check version minimum */ 149 ver = MSI_RecordGetString(rec,2); 150 if (ver) 151 { 152 comp_ver = msi_version_str_to_dword(ver); 153 r = check - comp_ver; 154 if (r < 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMinInclusive))) 155 { 156 TRACE("version below minimum\n"); 157 RegCloseKey(hukey); 158 index ++; 159 continue; 160 } 161 } 162 163 /* check version maximum */ 164 ver = MSI_RecordGetString(rec,3); 165 if (ver) 166 { 167 comp_ver = msi_version_str_to_dword(ver); 168 r = check - comp_ver; 169 if (r > 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMaxInclusive))) 170 { 171 RegCloseKey(hukey); 172 index ++; 173 continue; 174 } 175 TRACE("version above maximum\n"); 176 } 177 178 /* check language */ 179 sz = sizeof(DWORD); 180 RegQueryValueExW(hukey, INSTALLPROPERTY_LANGUAGEW, NULL, NULL, (LPBYTE)&check, &sz); 181 RegCloseKey(hukey); 182 language = MSI_RecordGetString(rec,4); 183 if (!check_language(check, language, attributes)) 184 { 185 index ++; 186 TRACE("language doesn't match\n"); 187 continue; 188 } 189 TRACE("found related product\n"); 190 191 action_property = MSI_RecordGetString(rec, 7); 192 append_productcode(package, action_property, productid); 193 MSI_RecordSetStringW(uirow, 1, productid); 194 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 195 } 196 index ++; 197 } 198 RegCloseKey(hkey); 199 msiobj_release( &uirow->hdr); 200 201 return ERROR_SUCCESS; 202 } 203 204 UINT ACTION_FindRelatedProducts(MSIPACKAGE *package) 205 { 206 static const WCHAR query[] = { 207 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 208 '`','U','p','g','r','a','d','e','`',0}; 209 MSIQUERY *view; 210 UINT rc; 211 212 if (msi_get_property_int(package->db, szInstalled, 0)) 213 { 214 TRACE("Skipping FindRelatedProducts action: product already installed\n"); 215 return ERROR_SUCCESS; 216 } 217 if (msi_action_is_unique(package, szFindRelatedProducts)) 218 { 219 TRACE("Skipping FindRelatedProducts action: already done in UI sequence\n"); 220 return ERROR_SUCCESS; 221 } 222 else 223 msi_register_unique_action(package, szFindRelatedProducts); 224 225 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 226 if (rc != ERROR_SUCCESS) 227 return ERROR_SUCCESS; 228 229 rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package); 230 msiobj_release(&view->hdr); 231 return rc; 232 } 233