From 7d3e5973fef6b14becf2b063c9f2bc14ac4e658c Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Sun, 4 Jul 2004 00:36:58 +0000 Subject: [PATCH] Activate features and components based on their various conditions. --- dlls/msi/action.c | 360 +++++++++++++++++++++++++++++++++++++++------ dlls/msi/package.c | 37 ++++- 2 files changed, 346 insertions(+), 51 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 5c5376fc958..b4af03c718a 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -76,6 +76,7 @@ typedef struct tagMSICOMPONENT WCHAR KeyPath[96]; INSTALLSTATE State; + BOOL FeatureState; BOOL Enabled; INT Cost; }MSICOMPONENT; @@ -136,6 +137,8 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage); 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 @@ inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) 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 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package) } } +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 @@ UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action) {'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 @@ UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action) return ACTION_DuplicateFiles(hPackage); if (strcmpW(action,szWriteRegistryValues)==0) return ACTION_WriteRegistryValues(hPackage); + /* Current called during itunes but unimplemented @@ -602,14 +647,11 @@ UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action) CostInitialize MigrateFeatureStates ResolveSource (sets SourceDir) - FileCost ValidateProductID (sets ProductID) IsolateComponents (Empty) SetODBCFolders MigrateFeatureStates - InstallValidate RemoveExistingProducts - InstallInitialize AllocateRegistrySpace ProcessComponents UnpublishComponents @@ -1092,6 +1134,7 @@ static int load_component(MSIPACKAGE* package, MSIHANDLE row) package->components[index].State = INSTALLSTATE_UNKNOWN; package->components[index].Enabled = TRUE; + package->components[index].FeatureState= FALSE; return index; } @@ -1518,19 +1561,6 @@ static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path, 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 @@ static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path, if (set_prop) MsiSetPropertyW(hPackage,cszTargetDir,path); } + if (folder) + *folder = &(package->folders[0]); return rc; } else @@ -1568,10 +1600,24 @@ static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path, } } } + 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 @@ static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path, * 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 @@ static UINT ACTION_CostFinalize(MSIHANDLE hPackage) TRACE("Building Directory properties\n"); package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE); + rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) @@ -1742,8 +1789,77 @@ static UINT ACTION_CostFinalize(MSIHANDLE hPackage) } } - 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 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage) 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 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage) 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 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage) 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 @@ inline static UINT get_file_target(MSIHANDLE hPackage, LPCWSTR file_key, INT index; package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE); - if (!package) return ERROR_INVALID_HANDLE; @@ -2074,8 +2193,13 @@ inline static UINT get_file_target(MSIHANDLE hPackage, LPCWSTR file_key, { 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 @@ static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage) 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 @@ static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage) WCHAR file_source[MAX_PATH]; WCHAR dest_name[0x100]; WCHAR dest_path[MAX_PATH]; + WCHAR component[0x100]; + INT component_index; DWORD sz=0x100; @@ -2126,6 +2249,24 @@ static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage) break; } + 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 @@ static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage) 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 @@ static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage) 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 @@ static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage) 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 @@ static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage) 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 @@ static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data) 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 --git a/dlls/msi/package.c b/dlls/msi/package.c index f5673345fd5..87fbed87a27 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -145,6 +145,9 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/prope 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 @@ VirtualMemory PhysicalMemory Intel ShellAdvSupport -ServicePackLevel -WindowsBuild -Version9x -Version95 -VersionNT -AdminUser DefaultUIFont VersionMsi VersionDatabase @@ -268,6 +265,29 @@ Privilaged 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 @@ INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType, 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 @@ INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType, if (msg_field > 1) { - sprintf(number,"%i: ",i); + sprintf(number," %i: ",i); strcat(message,number); } strcat(message,tmp);