From b6bc6aa6f8913d02549636607137021646306852 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Thu, 24 Feb 2005 12:47:43 +0000 Subject: [PATCH] Add the ExecuteAction handler. Store the keypath, and do refcounting and registration of SharedDLLs. Fix a bug with handing dword values in the registry. Fix bugs with writing registry keys where value == NULL. Make use of msidefs.h. Lay some groundwork for uninstalls. --- dlls/msi/action.c | 331 ++++++++++++++++++++++++++++++++++++++------- dlls/msi/action.h | 3 + dlls/msi/msipriv.h | 2 + 3 files changed, 285 insertions(+), 51 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 92d9c987d40..57a35c87502 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -39,6 +39,7 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #include "fdi.h" #include "msi.h" #include "msiquery.h" +#include "msidefs.h" #include "msvcrt/fcntl.h" #include "objbase.h" #include "objidl.h" @@ -96,6 +97,7 @@ static UINT ACTION_InstallExecute(MSIPACKAGE *package); static UINT ACTION_InstallFinalize(MSIPACKAGE *package); static UINT ACTION_ForceReboot(MSIPACKAGE *package); static UINT ACTION_ResolveSource(MSIPACKAGE *package); +static UINT ACTION_ExecuteAction(MSIPACKAGE *package); /* @@ -280,8 +282,8 @@ static struct _actions StandardActions[] = { { szCreateShortcuts, ACTION_CreateShortcuts }, { szDeleteServices, NULL}, { szDisableRollback, NULL}, - { szDuplicateFiles, ACTION_DuplicateFiles}, - { szExecuteAction, NULL}, + { szDuplicateFiles, ACTION_DuplicateFiles }, + { szExecuteAction, ACTION_ExecuteAction }, { szFileCost, ACTION_FileCost }, { szFindRelatedProducts, NULL}, { szForceReboot, ACTION_ForceReboot }, @@ -567,7 +569,9 @@ void ACTION_free_package_structures( MSIPACKAGE* package) if (package->folders && package->loaded_folders > 0) HeapFree(GetProcessHeap(),0,package->folders); - /* no dynamic buffers in components */ + for (i = 0; i < package->loaded_components; i++) + HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath); + if (package->components && package->loaded_components > 0) HeapFree(GetProcessHeap(),0,package->components); @@ -816,6 +820,18 @@ static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index, return FALSE; } +static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, + INSTALLSTATE check ) +{ + if (package->features[index].Installed == check) + return FALSE; + + if (package->features[index].ActionRequest == check) + return TRUE; + else + return FALSE; +} + /**************************************************** * TOP level entry points @@ -832,6 +848,7 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; MSI_SetPropertyW(package, szAction, szInstall); + package->ExecuteSequenceRun = FALSE; if (szPackagePath) { @@ -1056,6 +1073,15 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) 0}; INT seq = 0; + + if (package->ExecuteSequenceRun) + { + TRACE("Execute Sequence already Run\n"); + return ERROR_SUCCESS; + } + + package->ExecuteSequenceRun = TRUE; + /* get the sequence number */ if (UIran) { @@ -3149,7 +3175,6 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) } package->components[component_index].Action = INSTALLSTATE_LOCAL; - package->components[component_index].Installed = INSTALLSTATE_LOCAL; sz=0x100; rc = MSI_RecordGetStringW(row,3,file_key,&sz); @@ -3274,13 +3299,28 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, else { LPWSTR deformated; + LPWSTR p; + DWORD d = 0; deformat_string(package, &value[1], &deformated); *type=REG_DWORD; *size = sizeof(DWORD); data = HeapAlloc(GetProcessHeap(),0,*size); - *(LPDWORD)data = atoiW(deformated); - TRACE("DWORD %i\n",*data); + p = deformated; + if (*p == '-') + p++; + while (*p) + { + if ( (*p < '0') || (*p > '9') ) + break; + d *= 10; + d += (*p - '0'); + p++; + } + if (deformated[0] == '-') + d = -d; + *(LPDWORD)data = d; + TRACE("DWORD %li\n",*(LPDWORD)data); HeapFree(GetProcessHeap(),0,deformated); } @@ -3390,20 +3430,27 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) } package->components[component_index].Action = INSTALLSTATE_LOCAL; - package->components[component_index].Installed = INSTALLSTATE_LOCAL; - /* null values have special meanings during uninstalls and such */ - - if(MSI_RecordIsNull(row,5)) + name = load_dynamic_stringW(row, 4); + if( MSI_RecordIsNull(row,5) && name ) { - msiobj_release(&row->hdr); - goto next; + /* null values can have special meanings */ + if (name[0]=='-' && name[1] == 0) + { + msiobj_release(&row->hdr); + goto next; + } + else if ((name[0]=='+' && name[1] == 0) || + (name[0] == '*' && name[1] == 0)) + { + HeapFree(GetProcessHeap(),0,name); + name = NULL; + } } root = MSI_RecordGetInteger(row,2); key = load_dynamic_stringW(row, 3); - name = load_dynamic_stringW(row, 4); /* get the root key */ switch (root) @@ -3448,29 +3495,33 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) HeapFree(GetProcessHeap(),0,deformated); value = load_dynamic_stringW(row,5); - value_data = parse_value(package, value, &type, &size); + if (value) + value_data = parse_value(package, value, &type, &size); + else + { + value_data = NULL; + size = 0; + type = REG_SZ; + } deformat_string(package, name, &deformated); - if (value_data) - { - TRACE("Setting value %s\n",debugstr_w(deformated)); - RegSetValueExW(hkey, deformated, 0, type, value_data, size); + TRACE("Setting value %s\n",debugstr_w(deformated)); + RegSetValueExW(hkey, deformated, 0, type, value_data, size); - uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,2,deformated); - MSI_RecordSetStringW(uirow,1,uikey); + uirow = MSI_CreateRecord(3); + MSI_RecordSetStringW(uirow,2,deformated); + MSI_RecordSetStringW(uirow,1,uikey); - if (type == REG_SZ) - MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); - else - MSI_RecordSetStringW(uirow,3,value); + if (type == REG_SZ) + MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); + else + MSI_RecordSetStringW(uirow,3,value); - ui_actiondata(package,szWriteRegistryValues,uirow); - msiobj_release( &uirow->hdr ); + ui_actiondata(package,szWriteRegistryValues,uirow); + msiobj_release( &uirow->hdr ); - HeapFree(GetProcessHeap(),0,value_data); - } + HeapFree(GetProcessHeap(),0,value_data); HeapFree(GetProcessHeap(),0,value); HeapFree(GetProcessHeap(),0,deformated); @@ -3610,7 +3661,7 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL); return p; } - if (cmp->Attributes & 0x4) + if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) { MSIQUERY * view; MSIRECORD * row = 0; @@ -3621,8 +3672,8 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ', 'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' ' ,'`','%','s','`',0 }; - static const WCHAR fmt[]={'%','0','2','i',':','%','s',0}; - static const WCHAR fmt2[]={'%','0','2','i',':','%','s','\\','%','s',0}; + static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0}; + static const WCHAR fmt2[]={'%','0','2','i',':','\\','%','s','\\','%','s',0}; rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath); @@ -3672,7 +3723,7 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT return buffer; } - else if (cmp->Attributes & 0x20) + else if (cmp->Attributes & msidbComponentAttributesODBCDataSource) { FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); return NULL; @@ -3691,6 +3742,127 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT return NULL; } +static HKEY openSharedDLLsKey() +{ + HKEY hkey=0; + static const WCHAR path[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'S','h','a','r','e','d','D','L','L','s',0}; + + RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey); + return hkey; +} + +static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll) +{ + HKEY hkey; + DWORD count=0; + DWORD type; + DWORD sz = sizeof(count); + DWORD rc; + + hkey = openSharedDLLsKey(); + rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz); + if (rc != ERROR_SUCCESS) + count = 0; + RegCloseKey(hkey); + return count; +} + +static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count) +{ + HKEY hkey; + + hkey = openSharedDLLsKey(); + if (count > 0) + RegSetValueExW(hkey,path,0,REG_DWORD, + (LPBYTE)&count,sizeof(count)); + else + RegDeleteValueW(hkey,path); + RegCloseKey(hkey); + return count; +} + +/* + * Return TRUE if the count should be written out and FALSE if not + */ +static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index) +{ + INT count = 0; + BOOL write = FALSE; + INT j; + + /* only refcount DLLs */ + if (package->components[index].KeyPath[0]==0 || + package->components[index].Attributes & + msidbComponentAttributesRegistryKeyPath || + package->components[index].Attributes & + msidbComponentAttributesODBCDataSource) + write = FALSE; + else + { + count = ACTION_GetSharedDLLsCount(package->components[index]. + FullKeypath); + write = (count > 0); + + if (package->components[index].Attributes & + msidbComponentAttributesSharedDllRefCount) + write = TRUE; + } + + /* increment counts */ + for (j = 0; j < package->loaded_features; j++) + { + int i; + + if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL)) + continue; + + for (i = 0; i < package->features[j].ComponentCount; i++) + { + if (package->features[j].Components[i] == index) + count++; + } + } + /* decrement counts */ + for (j = 0; j < package->loaded_features; j++) + { + int i; + if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT)) + continue; + + for (i = 0; i < package->features[j].ComponentCount; i++) + { + if (package->features[j].Components[i] == index) + count--; + } + } + + /* ref count all the files in the component */ + if (write) + for (j = 0; j < package->loaded_files; j++) + { + if (package->files[j].Temporary) + continue; + if (package->files[j].ComponentIndex == index) + ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count); + } + + /* add a count for permenent */ + if (package->components[index].Attributes & + msidbComponentAttributesPermanent) + count ++; + + package->components[index].RefCount = count; + + if (write) + ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath, + package->components[index].RefCount); +} + /* * Ok further analysis makes me think that this work is * actually done in the PublishComponents and PublishFeatures @@ -3735,21 +3907,70 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) continue; keypath = resolve_keypath(package,i); - if (keypath) + package->components[i].FullKeypath = keypath; + + /* do the refcounting */ + ACTION_RefCountComponent( package, i); + + TRACE("Component %s, Keypath=%s, RefCount=%i\n", + debugstr_w(package->components[i].Component), + debugstr_w(package->components[i].FullKeypath), + package->components[i].RefCount); + /* + * Write the keypath out if the component is to be registered + * and delete the key if the component is to be deregistered + */ + if (ACTION_VerifyComponentForAction(package, i, + INSTALLSTATE_LOCAL)) { - RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath, - (strlenW(keypath)+1)*sizeof(WCHAR)); + if (keypath) + { + RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath, + (strlenW(keypath)+1)*sizeof(WCHAR)); + + if (package->components[i].Attributes & + msidbComponentAttributesPermanent) + { + static const WCHAR szPermKey[] = { +'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', +'0','0','0','0','0','0','0','0','0','0','0','0','0',0}; + + RegSetValueExW(hkey2,szPermKey,0,REG_SZ, + (LPVOID)keypath, + (strlenW(keypath)+1)*sizeof(WCHAR)); + } + + RegCloseKey(hkey2); + + /* UI stuff */ + uirow = MSI_CreateRecord(3); + MSI_RecordSetStringW(uirow,1,productcode); + MSI_RecordSetStringW(uirow,2,package->components[i]. + ComponentId); + MSI_RecordSetStringW(uirow,3,keypath); + ui_actiondata(package,szProcessComponents,uirow); + msiobj_release( &uirow->hdr ); + } + } + else if (ACTION_VerifyComponentForAction(package, i, + INSTALLSTATE_ABSENT)) + { + DWORD res; + RegDeleteValueW(hkey2,squished_pc); + + /* if the key is empty delete it */ + res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL); RegCloseKey(hkey2); + if (res == ERROR_NO_MORE_ITEMS) + RegDeleteKeyW(hkey,squished_cc); /* UI stuff */ - uirow = MSI_CreateRecord(3); + uirow = MSI_CreateRecord(2); MSI_RecordSetStringW(uirow,1,productcode); MSI_RecordSetStringW(uirow,2,package->components[i]. - ComponentId); - MSI_RecordSetStringW(uirow,3,keypath); + ComponentId); ui_actiondata(package,szProcessComponents,uirow); msiobj_release( &uirow->hdr ); - HeapFree(GetProcessHeap(),0,keypath); } } } @@ -3827,7 +4048,6 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) } package->components[index].Action = INSTALLSTATE_LOCAL; - package->components[index].Installed = INSTALLSTATE_LOCAL; index = get_loaded_file(package,package->components[index].KeyPath); @@ -4082,7 +4302,6 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) } package->components[index].Action = INSTALLSTATE_LOCAL; - package->components[index].Installed = INSTALLSTATE_LOCAL; sz=0x100; MSI_RecordGetStringW(row,1,clsid,&sz); @@ -4583,7 +4802,6 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) } package->components[index].Action = INSTALLSTATE_LOCAL; - package->components[index].Installed = INSTALLSTATE_LOCAL; ui_actiondata(package,szCreateShortcuts,row); @@ -4631,11 +4849,11 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) } else { - FIXME("UNHANDLED shortcut format, advertised shortcut\n"); - IPersistFile_Release( pf ); - IShellLinkW_Release( sl ); - msiobj_release(&row->hdr); - continue; + LPWSTR keypath; + FIXME("poorly handled shortcut format, advertised shortcut\n"); + keypath = dupstrW(package->components[index].FullKeypath); + IShellLinkW_SetPath(sl,keypath); + HeapFree(GetProcessHeap(),0,keypath); } if (!MSI_RecordIsNull(row,6)) @@ -4931,7 +5149,6 @@ static UINT ACTION_WriteIniValues(MSIPACKAGE *package) } package->components[component_index].Action = INSTALLSTATE_LOCAL; - package->components[component_index].Installed = INSTALLSTATE_LOCAL; identifier = load_dynamic_stringW(row,1); filename = load_dynamic_stringW(row,2); @@ -5126,6 +5343,9 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) int j; INT size; + if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL)) + continue; + size = package->features[i].ComponentCount*21; size +=1; if (package->features[i].Feature_Parent[0]) @@ -5402,6 +5622,8 @@ static UINT ACTION_ForceReboot(MSIPACKAGE *package) RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); sprintfW(buffer,install_fmt,productcode,squished_pc); + + size = strlenW(buffer)*sizeof(WCHAR); RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); RegCloseKey(hkey); @@ -5510,7 +5732,6 @@ static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) } package->components[index].Action = INSTALLSTATE_LOCAL; - package->components[index].Installed = INSTALLSTATE_LOCAL; exten = load_dynamic_stringW(row,1); extension[0] = '.'; @@ -5711,6 +5932,14 @@ end: return ERROR_SUCCESS; } + +static UINT ACTION_ExecuteAction(MSIPACKAGE *package) +{ + UINT rc; + rc = ACTION_ProcessExecSequence(package,TRUE); + return rc; +} + /* Msi functions that seem appropriate here */ UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) { @@ -5745,7 +5974,7 @@ UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction ) package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); if( package ) { - ret = ACTION_PerformAction(package,szAction); + ret = ACTION_PerformUIAction(package,szAction); msiobj_release( &package->hdr ); } return ret; diff --git a/dlls/msi/action.h b/dlls/msi/action.h index 221e2a22275..1ac1430c32e 100644 --- a/dlls/msi/action.h +++ b/dlls/msi/action.h @@ -53,6 +53,9 @@ typedef struct tagMSICOMPONENT BOOL Enabled; INT Cost; + INT RefCount; + + LPWSTR FullKeypath; } MSICOMPONENT; typedef struct tagMSIFOLDER diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index cb20887157e..6763295f3bc 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -214,6 +214,8 @@ typedef struct tagMSIPACKAGE UINT CurrentInstallState; msi_dialog *dialog; LPWSTR next_dialog; + + BOOL ExecuteSequenceRun; } MSIPACKAGE; typedef struct tagMSIPREVIEW