MSI: activate Features and Components based on their various conditions
Mike McCormack
mike at codeweavers.com
Thu Jul 1 12:23:04 CDT 2004
ChangeLog:
<aric at codeweavers.com>
* activate Features and Components based on their various conditions
-------------- next part --------------
diff -u dlls/msi.old/action.c dlls/msi/action.c
--- dlls/msi.old/action.c 2004-07-01 12:19:53.000000000 -0500
+++ dlls/msi/action.c 2004-07-01 12:20:43.000000000 -0500
@@ -76,6 +76,7 @@
WCHAR KeyPath[96];
INSTALLSTATE State;
+ BOOL FeatureState;
BOOL Enabled;
INT Cost;
}MSICOMPONENT;
@@ -136,6 +137,8 @@
static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage);
static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage);
static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action);
+static UINT ACTION_InstallInitialize(MSIHANDLE hPackage);
+static UINT ACTION_InstallValidate(MSIHANDLE hPackage);
static UINT HANDLE_CustomType1(MSIHANDLE hPackage, const LPWSTR source,
const LPWSTR target, const INT type);
@@ -205,6 +208,22 @@
return rc;
}
+inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
+{
+ INT rc = -1;
+ INT i;
+
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ if (strcmpW(Feature,package->features[i].Feature)==0)
+ {
+ rc = i;
+ break;
+ }
+ }
+ return rc;
+}
+
static UINT track_tempfile(MSIHANDLE hPackage, LPCWSTR name, LPCWSTR path)
{
MSIPACKAGE *package;
@@ -254,6 +273,19 @@
}
}
+static void progress_message(MSIHANDLE hPackage, int a, int b, int c, int d )
+{
+ MSIHANDLE row;
+
+ row = MsiCreateRecord(4);
+ MsiRecordSetInteger(row,1,a);
+ MsiRecordSetInteger(row,2,b);
+ MsiRecordSetInteger(row,3,c);
+ MsiRecordSetInteger(row,4,d);
+ MsiProcessMessage(hPackage, INSTALLMESSAGE_PROGRESS, row);
+ MsiCloseHandle(row);
+}
+
/****************************************************
* TOP level entry points
*****************************************************/
@@ -576,15 +608,27 @@
{'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
const static WCHAR szFileCost[] =
{'F','i','l','e','C','o','s','t',0};
+ const static WCHAR szInstallInitialize[] =
+{'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
+ const static WCHAR szInstallValidate[] =
+{'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
TRACE("Performing action (%s)\n",debugstr_w(action));
+ progress_message(hPackage,2,25,0,0);
+ /* pre install, setup and configureation block */
if (strcmpW(action,szCostInitialize)==0)
return ACTION_CostInitialize(hPackage);
if (strcmpW(action,szFileCost)==0)
return ACTION_FileCost(hPackage);
if (strcmpW(action,szCostFinalize)==0)
return ACTION_CostFinalize(hPackage);
+ if (strcmpW(action,szInstallValidate)==0)
+ return ACTION_InstallValidate(hPackage);
+
+ /* install block */
+ if (strcmpW(action,szInstallInitialize)==0)
+ return ACTION_InstallInitialize(hPackage);
if (strcmpW(action,szCreateFolders)==0)
return ACTION_CreateFolders(hPackage);
if (strcmpW(action,szInstallFiles)==0)
@@ -593,6 +637,7 @@
return ACTION_DuplicateFiles(hPackage);
if (strcmpW(action,szWriteRegistryValues)==0)
return ACTION_WriteRegistryValues(hPackage);
+
/*
Current called during itunes but unimplemented
@@ -602,14 +647,11 @@
CostInitialize
MigrateFeatureStates
ResolveSource (sets SourceDir)
- FileCost
ValidateProductID (sets ProductID)
IsolateComponents (Empty)
SetODBCFolders
MigrateFeatureStates
- InstallValidate
RemoveExistingProducts
- InstallInitialize
AllocateRegistrySpace
ProcessComponents
UnpublishComponents
@@ -1092,6 +1134,7 @@
package->components[index].State = INSTALLSTATE_UNKNOWN;
package->components[index].Enabled = TRUE;
+ package->components[index].FeatureState= FALSE;
return index;
}
@@ -1518,19 +1561,6 @@
TRACE("Working to resolve %s\n",debugstr_w(name));
- for (i = 0; i < package->loaded_folders; i++)
- {
- if (strcmpW(package->folders[i].Directory,name)==0)
- break;
- }
-
- if (i >= package->loaded_folders)
- return ERROR_FUNCTION_FAILED;
-
-
- if (folder)
- *folder = &(package->folders[i]);
-
if (!path)
return rc;
@@ -1548,6 +1578,8 @@
if (set_prop)
MsiSetPropertyW(hPackage,cszTargetDir,path);
}
+ if (folder)
+ *folder = &(package->folders[0]);
return rc;
}
else
@@ -1568,10 +1600,24 @@
}
}
}
+ if (folder)
+ *folder = &(package->folders[0]);
return rc;
}
}
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ if (strcmpW(package->folders[i].Directory,name)==0)
+ break;
+ }
+
+ if (i >= package->loaded_folders)
+ return ERROR_FUNCTION_FAILED;
+
+ if (folder)
+ *folder = &(package->folders[i]);
+
if (!source && package->folders[i].ResolvedTarget[0])
{
strcpyW(path,package->folders[i].ResolvedTarget);
@@ -1624,11 +1670,11 @@
* The costing needs to be implemented at some point but for now I am going
* to focus on the directory building
*
- *
*/
static UINT ACTION_CostFinalize(MSIHANDLE hPackage)
{
static const CHAR *ExecSeqQuery = "select * from Directory";
+ static const CHAR *ConditionQuery = "select * from Condition";
UINT rc;
MSIHANDLE view;
MSIPACKAGE *package;
@@ -1637,6 +1683,7 @@
TRACE("Building Directory properties\n");
package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+
rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
@@ -1742,8 +1789,77 @@
}
}
- MsiSetPropertyA(hPackage,"CostingComplete","1");
+ TRACE("Evaluating Condition Table\n");
+
+ rc = MsiDatabaseOpenViewA(package->db, ConditionQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ WCHAR Feature[0x100];
+ WCHAR Condition[0x100];
+ MSIHANDLE row = 0;
+ DWORD sz;
+ int feature_index;
+
+ rc = MsiViewFetch(view,&row);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ sz = 0x100;
+ MsiRecordGetStringW(row,1,Feature,&sz);
+ sz = 0x100;
+ MsiRecordGetStringW(row,3,Condition,&sz);
+
+ feature_index = get_loaded_feature(package,Feature);
+ if (feature_index < 0)
+ ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
+ else
+ {
+ if (MsiEvaluateConditionW(hPackage,Condition) == MSICONDITION_TRUE)
+ {
+ int level = MsiRecordGetInteger(row,2);
+ TRACE("Reseting feature %s to level %i\n",debugstr_w(Feature),
+ level);
+ package->features[feature_index].Level = level;
+ }
+ }
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+
+ TRACE("Enabling or Disabling Components\n");
+ for (i = 0; i < package->loaded_components; i++)
+ {
+ if (package->components[i].Condition[0])
+ {
+ if (MsiEvaluateConditionW(hPackage,
+ package->components[i].Condition) == MSICONDITION_FALSE)
+ {
+ TRACE("Disabling component %s\n",
+ debugstr_w(package->components[i].Component));
+ package->components[i].Enabled = FALSE;
+ }
+ }
+ }
+
+ MsiSetPropertyA(hPackage,"CostingComplete","1");
return ERROR_SUCCESS;
}
@@ -2003,14 +2119,6 @@
INT index;
MSIPACKAGE *package;
- /* REALLY what we want to do is go through all the enabled
- * features and check all the components of that feature and
- * make sure that component is not already install and blah
- * blah blah... I will do it that way some day.. really
- * but for sheer gratification I am going to just brute force
- * install all the files
- */
-
package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
if (!package)
@@ -2023,6 +2131,17 @@
file = &package->files[index];
+ if (file->Temporary)
+ continue;
+
+ if (!package->components[file->ComponentIndex].Enabled ||
+ !package->components[file->ComponentIndex].FeatureState)
+ {
+ TRACE("File %s is not scheduled for install\n",
+ debugstr_w(file->File));
+ continue;
+ }
+
if ((file->State == 1) || (file->State == 2))
{
TRACE("Installing %s\n",debugstr_w(file->File));
@@ -2048,6 +2167,7 @@
TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
debugstr_w(file->TargetPath));
+ progress_message(hPackage,2,1,0,0);
rc = !MoveFileW(file->SourcePath,file->TargetPath);
if (rc)
ERR("Unable to move file\n");
@@ -2066,7 +2186,6 @@
INT index;
package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
-
if (!package)
return ERROR_INVALID_HANDLE;
@@ -2074,8 +2193,13 @@
{
if (strcmpW(file_key,package->files[index].File)==0)
{
- strcmpW(file_source,package->files[index].TargetPath);
- return ERROR_SUCCESS;
+ if (package->files[index].State >= 3)
+ {
+ strcmpW(file_source,package->files[index].TargetPath);
+ return ERROR_SUCCESS;
+ }
+ else
+ return ERROR_FILE_NOT_FOUND;
}
}
@@ -2088,16 +2212,13 @@
MSIHANDLE view;
MSIHANDLE row = 0;
static const CHAR *ExecSeqQuery = "select * from DuplicateFile";
- MSIHANDLE db;
+ MSIPACKAGE* package;
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- /*
- * Yes we should only do this for components that are installed
- * but again I need to do that went I track components.
- */
- db = MsiGetActiveDatabase(hPackage);
- rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
- MsiCloseHandle(db);
+ rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;
@@ -2116,6 +2237,8 @@
WCHAR file_source[MAX_PATH];
WCHAR dest_name[0x100];
WCHAR dest_path[MAX_PATH];
+ WCHAR component[0x100];
+ INT component_index;
DWORD sz=0x100;
@@ -2127,6 +2250,24 @@
}
sz=0x100;
+ rc = MsiRecordGetStringW(row,2,component,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to get component\n");
+ MsiCloseHandle(row);
+ break;
+ }
+
+ component_index = get_loaded_component(package,component);
+ if (!package->components[component_index].Enabled ||
+ !package->components[component_index].FeatureState)
+ {
+ TRACE("Skipping copy due to disabled component\n");
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ sz=0x100;
rc = MsiRecordGetStringW(row,3,file_key,&sz);
if (rc != ERROR_SUCCESS)
{
@@ -2283,14 +2424,13 @@
MSIHANDLE view;
MSIHANDLE row = 0;
static const CHAR *ExecSeqQuery = "select * from Registry";
- MSIHANDLE db;
+ MSIPACKAGE *package;
- /* Again here we want to key off of the components being installed...
- * oh well
- */
- db = MsiGetActiveDatabase(hPackage);
- rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
- MsiCloseHandle(db);
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;
@@ -2311,6 +2451,8 @@
LPSTR value_data = NULL;
HKEY root_key, hkey;
DWORD type,size;
+ WCHAR component[0x100];
+ INT component_index;
INT root;
DWORD sz=0x100;
@@ -2322,6 +2464,18 @@
break;
}
+ sz= 0x100;
+ MsiRecordGetStringW(row,6,component,&sz);
+ component_index = get_loaded_component(package,component);
+
+ if (!package->components[component_index].Enabled ||
+ !package->components[component_index].FeatureState)
+ {
+ TRACE("Skipping write due to disabled component\n");
+ MsiCloseHandle(row);
+ continue;
+ }
+
/* null values have special meanings during uninstalls and such */
if(MsiRecordIsNull(row,5))
@@ -2380,6 +2534,7 @@
RegSetValueExW(hkey, name, 0, type, value_data, size);
HeapFree(GetProcessHeap(),0,value_data);
}
+ progress_message(hPackage,2,1,0,0);
MsiCloseHandle(row);
}
@@ -2468,6 +2623,123 @@
return size;
}
+static UINT ACTION_InstallInitialize(MSIHANDLE hPackage)
+{
+ CHAR level[10000];
+ INT install_level;
+ DWORD sz;
+ MSIPACKAGE *package;
+ INT i,j;
+ /* I do not know if this is where it should happen.. but */
+
+ TRACE("Checking Install Level\n");
+ FIXME("The Attributes of the feature OVERRIDE THIS... unimplemented\n");
+ FIXME("As does the ALLLOCAL and such propertys\n");
+
+ sz = 10000;
+ if (MsiGetPropertyA(hPackage,"INSTALLLEVEL",level,&sz)==ERROR_SUCCESS)
+ install_level = atoi(level);
+ else
+ install_level = 1;
+
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ /*
+ * components FeatureState defaults to FALSE. the idea is we want to
+ * enable the component is ANY feature that uses it is enabled to install
+ */
+ for(i = 0; i < package->loaded_features; i++)
+ {
+ BOOL feature_state= ((package->features[i].Level > 0) &&
+ (package->features[i].Level <= install_level));
+ TRACE("Feature %s has a state of %i\n",
+ debugstr_w(package->features[i].Feature), feature_state);
+ for( j = 0; j < package->features[i].ComponentCount; j++)
+ {
+ package->components[package->features[i].Components[j]].FeatureState
+ |= feature_state;
+ }
+ }
+ /*
+ * so basically we ONLY want to install a component if its Enabled AND
+ * FeatureState are both TRUE
+ */
+ return ERROR_SUCCESS;
+}
+
+static UINT ACTION_InstallValidate(MSIHANDLE hPackage)
+{
+ DWORD progress = 0;
+ static const CHAR q1[]="SELECT * FROM Registry";
+ static const CHAR q2[]=
+"select Action from InstallExecuteSequence where Sequence > 0 order by Sequence";
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ MSIHANDLE db;
+ BOOL flipit= FALSE;
+ MSIPACKAGE* package;
+
+ TRACE(" InstallValidate \n");
+
+ db = MsiGetActiveDatabase(hPackage);
+ rc = MsiDatabaseOpenViewA(db, q2, &view);
+ rc = MsiViewExecute(view, 0);
+
+ while (1)
+ {
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+ if (!flipit)
+ {
+ CHAR buf[0x100];
+ DWORD sz=0x100;
+ MsiRecordGetStringA(row,1,buf,&sz);
+ if (strcmp(buf,"InstallValidate")==0)
+ flipit=TRUE;
+ }
+ else
+ progress +=25;
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+
+ rc = MsiDatabaseOpenViewA(db, q1, &view);
+ rc = MsiViewExecute(view, 0);
+ while (1)
+ {
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+ progress +=1;
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ MsiCloseHandle(db);
+
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ progress_message(hPackage,0,progress+package->loaded_files,0,0);
+
+ return ERROR_SUCCESS;
+}
+
+
+
+
+
/* Msi functions that seem approperate here */
UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
{
diff -u dlls/msi.old/package.c dlls/msi/package.c
--- dlls/msi.old/package.c 2004-07-01 12:19:53.000000000 -0500
+++ dlls/msi/package.c 2004-07-01 12:20:43.000000000 -0500
@@ -145,6 +145,9 @@
static VOID set_installer_properties(MSIHANDLE hPackage)
{
WCHAR pth[MAX_PATH];
+ OSVERSIONINFOA OSVersion;
+ DWORD verval;
+ CHAR verstr[10];
static const WCHAR cszbs[]={'\\',0};
static const WCHAR CFF[] =
@@ -204,12 +207,6 @@
PhysicalMemory
Intel
ShellAdvSupport
-ServicePackLevel
-WindowsBuild
-Version9x
-Version95
-VersionNT
-AdminUser
DefaultUIFont
VersionMsi
VersionDatabase
@@ -268,6 +265,29 @@
GetTempPathW(MAX_PATH,pth);
MsiSetPropertyW(hPackage, TF, pth);
+
+ /* in a wine enviroment the user is always admin and privlaged */
+ MsiSetPropertyA(hPackage,"AdminUser","1");
+ MsiSetPropertyA(hPackage,"Privileged","1");
+
+ /* set the os things */
+ OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+ GetVersionExA(&OSVersion);
+ verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
+ sprintf(verstr,"%li",verval);
+ switch (OSVersion.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_WINDOWS:
+ MsiSetPropertyA(hPackage,"Version9X",verstr);
+ break;
+ case VER_PLATFORM_WIN32_NT:
+ MsiSetPropertyA(hPackage,"VersionNT",verstr);
+ break;
+ }
+ sprintf(verstr,"%li",OSVersion.dwBuildNumber);
+ MsiSetPropertyA(hPackage,"WindowsBuild",verstr);
+ /* just fudge this */
+ MsiSetPropertyA(hPackage,"ServicePackLevel","6");
}
@@ -377,6 +397,9 @@
log_type |= INSTALLLOGMODE_ACTIONSTART;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
log_type |= INSTALLLOGMODE_ACTIONDATA;
+ /* just a guess */
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
+ log_type |= 0x800;
message = HeapAlloc(GetProcessHeap(),0,1);
message[0]=0;
@@ -396,7 +419,7 @@
if (msg_field > 1)
{
- sprintf(number,"%i: ",i);
+ sprintf(number," %i: ",i);
strcat(message,number);
}
strcat(message,tmp);
More information about the wine-patches
mailing list