msi: implement FindRelatedProducts

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

msi: implement FindRelatedProducts

Aric Stewart
Add module upgrade.c
implement FindRelatedProducts

Index: include/msidefs.h
===================================================================
RCS file: /home/wine/wine/include/msidefs.h,v
retrieving revision 1.7
diff -u -r1.7 msidefs.h
--- include/msidefs.h 16 May 2005 21:37:35 -0000 1.7
+++ include/msidefs.h 8 Jun 2005 18:48:39 -0000
@@ -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,
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.27
diff -u -r1.27 Makefile.in
--- dlls/msi/Makefile.in 27 May 2005 09:11:18 -0000 1.27
+++ dlls/msi/Makefile.in 8 Jun 2005 18:48:39 -0000
@@ -34,6 +34,7 @@
  table.c \
  tokenize.c \
  update.c \
+ upgrade.c \
  where.c
 
 RC_SRCS = msi.rc
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.138
diff -u -r1.138 action.c
--- dlls/msi/action.c 8 Jun 2005 18:34:04 -0000 1.138
+++ dlls/msi/action.c 8 Jun 2005 18:48:42 -0000
@@ -305,7 +305,7 @@
     { 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 @@
     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)
 {
Index: dlls/msi/action.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.h,v
retrieving revision 1.15
diff -u -r1.15 action.h
--- dlls/msi/action.h 7 Jun 2005 20:29:51 -0000 1.15
+++ dlls/msi/action.h 8 Jun 2005 18:48:42 -0000
@@ -192,6 +192,7 @@
     LPWSTR  *Actions[TOTAL_SCRIPTS];
     UINT    ActionCount[TOTAL_SCRIPTS];
     BOOL    ExecuteSequenceRun;
+    BOOL    FindRelatedProductsRun;
     BOOL    CurrentlyScripting;
 }MSISCRIPT;
 
@@ -202,6 +203,7 @@
 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 @@
                                    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);
--- /dev/null 2005-03-17 08:20:53.000000000 -0600
+++ dlls/msi/upgrade.c 2005-06-08 13:44:17.000000000 -0500
@@ -0,0 +1,235 @@
+/*
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+#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)
+    {
+        if (lang1 == langdword)
+            return FALSE;
+        else
+            return TRUE;
+    }
+
+    if (lang1 == langdword)
+        return TRUE;
+    else
+        return FALSE;
+}
+
+static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property,
+                               LPCWSTR productid)
+{
+    LPWSTR prop;
+    LPWSTR newprop;
+    DWORD len;
+    static const WCHAR seperator[] = {';',0};
+
+    prop = load_dynamic_property(package, action_property, NULL);
+    if (prop)
+        len = strlenW(prop);
+    else
+        len = 0;
+
+    /*seperator*/
+    len ++;
+
+    len += strlenW(productid);
+
+    /*null*/
+    len++;
+
+    newprop = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
+
+    if (prop)
+    {
+        strcpyW(newprop,prop);
+        strcatW(newprop,seperator);
+    }
+    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;
+}