/* * 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 */ /* * Actions focused on in this module * * FindRelatedProducts * MigrateFeatureStates (TODO) * RemoveExistingProducts (TODO) */ #include #include "windef.h" #include "winbase.h" #include "winerror.h" #include "winreg.h" #include "wine/debug.h" #include "msidefs.h" #include "msipriv.h" #include "winuser.h" #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); extern const WCHAR szFindRelatedProducts[]; extern const WCHAR szMigrateFeatureStates[]; extern const WCHAR szRemoveExistingProducts[]; static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes) { DWORD langdword; if (!lang2 || lang2[0]==0) return TRUE; langdword = atoiW(lang2); if (attributes & msidbUpgradeAttributesLanguagesExclusive) return (lang1 != langdword); else return (lang1 == langdword); } static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property, LPCWSTR productid) { LPWSTR prop; LPWSTR newprop; DWORD len; static const WCHAR separator[] = {';',0}; prop = msi_dup_property(package, action_property ); if (prop) len = strlenW(prop); else len = 0; /*separator*/ len ++; len += strlenW(productid); /*null*/ len++; newprop = msi_alloc( len*sizeof(WCHAR) ); if (prop) { strcpyW(newprop,prop); strcatW(newprop,separator); } else newprop[0] = 0; strcatW(newprop,productid); MSI_SetPropertyW(package, action_property, newprop); TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property), debugstr_w(newprop)); msi_free( prop ); msi_free( newprop ); } static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) { MSIPACKAGE *package = (MSIPACKAGE*)param; WCHAR product[GUID_SIZE]; DWORD index = 0; DWORD attributes = 0; DWORD sz = GUID_SIZE; LPCWSTR upgrade_code; HKEY hkey = 0; UINT rc = ERROR_SUCCESS; MSIRECORD *uirow; upgrade_code = MSI_RecordGetString(rec,1); rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; uirow = MSI_CreateRecord(1); attributes = MSI_RecordGetInteger(rec,5); while (rc == ERROR_SUCCESS) { rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL); TRACE("Looking at (%i) %s\n",index,debugstr_w(product)); if (rc == ERROR_SUCCESS) { WCHAR productid[GUID_SIZE]; LPCWSTR ver; LPCWSTR language; LPCWSTR action_property; DWORD check = 0x00000000; DWORD comp_ver = 0x00000000; DWORD sz = 0x100; HKEY hukey; INT r; unsquash_guid(product,productid); rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE); if (rc != ERROR_SUCCESS) { rc = ERROR_SUCCESS; index ++; continue; } sz = sizeof(DWORD); RegQueryValueExW(hukey, INSTALLPROPERTY_VERSIONW, NULL, NULL, (LPBYTE)&check, &sz); /* check min */ ver = MSI_RecordGetString(rec,2); comp_ver = msi_version_str_to_dword(ver); r = check - comp_ver; if (r < 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMinInclusive))) { RegCloseKey(hukey); index ++; continue; } /* check max */ ver = MSI_RecordGetString(rec,3); comp_ver = msi_version_str_to_dword(ver); r = check - comp_ver; if (r > 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMaxInclusive))) { RegCloseKey(hukey); index ++; continue; } /* check language*/ sz = sizeof(DWORD); RegQueryValueExW(hukey, INSTALLPROPERTY_LANGUAGEW, NULL, NULL, (LPBYTE)&check, &sz); RegCloseKey(hukey); language = MSI_RecordGetString(rec,4); TRACE("Checking languages %x and %s\n", check, debugstr_w(language)); if (!check_language(check, language, attributes)) { index ++; continue; } action_property = MSI_RecordGetString(rec,7); append_productcode(package,action_property,productid); ui_actiondata(package,szFindRelatedProducts,uirow); } index ++; } RegCloseKey(hkey); msiobj_release( &uirow->hdr); return ERROR_SUCCESS; } UINT ACTION_FindRelatedProducts(MSIPACKAGE *package) { static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M', ' ','`','U','p','g','r','a','d','e','`',0}; UINT rc = ERROR_SUCCESS; MSIQUERY *view; if (check_unique_action(package,szFindRelatedProducts)) { TRACE("Skipping FindRelatedProducts action: already done on client side\n"); return ERROR_SUCCESS; } else register_unique_action(package,szFindRelatedProducts); rc = MSI_DatabaseOpenViewW(package->db, Query, &view); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package); msiobj_release(&view->hdr); return rc; }