diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in index 702699d02e1..e89d1d74a81 100644 --- a/dlls/msi/Makefile.in +++ b/dlls/msi/Makefile.in @@ -34,6 +34,7 @@ C_SRCS = \ table.c \ tokenize.c \ update.c \ + upgrade.c \ where.c RC_SRCS = msi.rc diff --git a/dlls/msi/action.c b/dlls/msi/action.c index c97a03b0b33..165643f2ac6 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -305,7 +305,7 @@ static struct _actions StandardActions[] = { { szDuplicateFiles, ACTION_DuplicateFiles }, { szExecuteAction, ACTION_ExecuteAction }, { szFileCost, ACTION_FileCost }, - { szFindRelatedProducts, NULL}, + { szFindRelatedProducts, ACTION_FindRelatedProducts }, { szForceReboot, ACTION_ForceReboot }, { szInstallAdminPackage, NULL}, { szInstallExecute, ACTION_InstallExecute }, @@ -571,6 +571,47 @@ DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ) return 0; } +DWORD build_version_dword(LPCWSTR version_string) +{ + SHORT major,minor; + WORD build; + DWORD rc = 0x00000000; + LPCWSTR ptr1; + + ptr1 = version_string; + + if (!ptr1) + return rc; + else + major = atoiW(ptr1); + + + if(ptr1) + ptr1 = strchrW(ptr1,'.'); + if (ptr1) + { + ptr1++; + minor = atoiW(ptr1); + } + else + minor = 0; + + if (ptr1) + ptr1 = strchrW(ptr1,'.'); + + if (ptr1) + { + ptr1++; + build = atoiW(ptr1); + } + else + build = 0; + + rc = MAKELONG(build,MAKEWORD(minor,major)); + TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc); + return rc; +} + /* Called when the package is being closed */ void ACTION_free_package_structures( MSIPACKAGE* package) { diff --git a/dlls/msi/action.h b/dlls/msi/action.h index 351596ff833..2ad66290b22 100644 --- a/dlls/msi/action.h +++ b/dlls/msi/action.h @@ -192,6 +192,7 @@ typedef struct tagMSISCRIPT LPWSTR *Actions[TOTAL_SCRIPTS]; UINT ActionCount[TOTAL_SCRIPTS]; BOOL ExecuteSequenceRun; + BOOL FindRelatedProductsRun; BOOL CurrentlyScripting; }MSISCRIPT; @@ -202,6 +203,7 @@ void ACTION_FinishCustomActions( MSIPACKAGE* package); UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute); void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); UINT ACTION_AppSearch(MSIPACKAGE *package); +UINT ACTION_FindRelatedProducts(MSIPACKAGE *package); DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ); WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index); @@ -222,3 +224,6 @@ VOID ControlEvent_SubscribeToEvent(MSIPACKAGE *package, LPCWSTR event, LPCWSTR control, LPCWSTR attribute); VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, LPCWSTR control, LPCWSTR attribute ); + +/* version stuff for upgrades */ +DWORD build_version_dword(LPCWSTR version_string); diff --git a/dlls/msi/upgrade.c b/dlls/msi/upgrade.c new file mode 100644 index 00000000000..516f22e0bab --- /dev/null +++ b/dlls/msi/upgrade.c @@ -0,0 +1,227 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Actions focused on in this module + * + * FindRelatedProducts + * MigrateFeatureStates (TODO) + * RemoveExistingProducts (TODO) + */ + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msidefs.h" +#include "msipriv.h" +#include "winnls.h" +#include "winuser.h" +#include "winver.h" +#include "action.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +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 = load_dynamic_property(package, action_property, NULL); + if (prop) + len = strlenW(prop); + else + len = 0; + + /*separator*/ + len ++; + + len += strlenW(productid); + + /*null*/ + len++; + + newprop = HeapAlloc(GetProcessHeap(),0,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)); + HeapFree(GetProcessHeap(),0,prop); + HeapFree(GetProcessHeap(),0,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; + + upgrade_code = MSI_RecordGetString(rec,1); + + rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + attributes = MSI_RecordGetInteger(rec,5); + + while (rc == ERROR_SUCCESS) + { + rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL); + TRACE("Looking at (%li) %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; + static const WCHAR szVersion[] = + {'V','e','r','s','i','o','n',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + + unsquash_guid(product,productid); + rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + index ++; + continue; + } + + sz = sizeof(DWORD); + RegQueryValueExW(hukey, szVersion, NULL, NULL, (LPBYTE)&check, + &sz); + /* check min */ + ver = MSI_RecordGetString(rec,2); + comp_ver = build_version_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 = build_version_dword(ver); + r = check - comp_ver; + if (r > 0 || (r == 0 && !(attributes & + msidbUpgradeAttributesVersionMaxInclusive))) + { + RegCloseKey(hukey); + index ++; + continue; + } + + /* check language*/ + sz = sizeof(DWORD); + RegQueryValueExW(hukey, szLanguage, NULL, NULL, (LPBYTE)&check, + &sz); + RegCloseKey(hukey); + language = MSI_RecordGetString(rec,4); + TRACE("Checking languages 0x%lx 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); + } + index ++; + } + RegCloseKey(hkey); + + 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 (package->script && package->script->FindRelatedProductsRun) + return ERROR_SUCCESS; + + if (package->script) + package->script->FindRelatedProductsRun = TRUE; + + 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; +} diff --git a/include/msidefs.h b/include/msidefs.h index 71b054b80ca..a8878930dfa 100644 --- a/include/msidefs.h +++ b/include/msidefs.h @@ -23,6 +23,15 @@ extern "C" { #endif +enum msidbUpgradeAttributes { + msidbUpgradeAttributesMigrateFeatures = 0x0000001, + msidbUpgradeAttributesOnlyDetect = 0x00000002, + msidbUpgradeAttributesIgnoreRemoveFailure = 0x00000004, + msidbUpgradeAttributesVersionMinInclusive = 0x00000100, + msidbUpgradeAttributesVersionMaxInclusive = 0x00000200, + msidbUpgradeAttributesLanguagesExclusive = 0x00000400 +}; + enum msidbFileAttributes { msidbFileAttributesReadOnly = 0x00000001, msidbFileAttributesHidden = 0x00000002,