From 16d979e4add671a34557b0db3df9ce70b61ccf07 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Fri, 3 Dec 2010 13:37:09 +0000 Subject: [PATCH] - Merge from trunk - Hackfixed to build svn path=/branches/audio-bringup/; revision=49924 --- dll/win32/msi/action.c | 73 +++++-- dll/win32/msi/appsearch.c | 8 +- dll/win32/msi/classes.c | 20 +- dll/win32/msi/cond.tab.c | 14 +- dll/win32/msi/cond.y | 14 +- dll/win32/msi/custom.c | 32 ++-- dll/win32/msi/database.c | 71 +++++-- dll/win32/msi/join.c | 8 +- dll/win32/msi/media.c | 43 ++++- dll/win32/msi/msi.c | 42 +++++ dll/win32/msi/msi.spec | 10 +- dll/win32/msi/msi_Fi.rc | 48 ++--- dll/win32/msi/msipriv.h | 44 ++++- dll/win32/msi/msiquery.c | 7 +- dll/win32/msi/package.c | 386 ++++++++++++++++++++++++++------------ dll/win32/msi/record.c | 47 +++++ dll/win32/msi/registry.c | 34 +++- dll/win32/msi/storages.c | 6 +- dll/win32/msi/string.c | 17 +- dll/win32/msi/suminfo.c | 14 +- dll/win32/msi/table.c | 273 +++++++++++++++++---------- dll/win32/msi/version.rc | 8 +- 22 files changed, 862 insertions(+), 357 deletions(-) diff --git a/dll/win32/msi/action.c b/dll/win32/msi/action.c index bb559c016af..808386f96e9 100644 --- a/dll/win32/msi/action.c +++ b/dll/win32/msi/action.c @@ -1785,7 +1785,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) BOOL feature_state = ((feature->Level > 0) && (feature->Level <= level)); - if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN)) + if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN) { if (feature->Attributes & msidbFeatureAttributesFavorSource) msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE); @@ -1814,7 +1814,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) { BOOL selected = feature->Level > 0 && feature->Level <= level; - if (selected && feature->Action == INSTALLSTATE_UNKNOWN) + if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN) { msi_feature_set_state(package, feature, feature->Installed); } @@ -1839,7 +1839,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) { if (cl->component->ForceLocalState && - feature->Action == INSTALLSTATE_SOURCE) + feature->ActionRequest == INSTALLSTATE_SOURCE) { msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL); break; @@ -1850,7 +1850,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) { component = cl->component; - switch (feature->Action) + switch (feature->ActionRequest) { case INSTALLSTATE_ABSENT: component->anyAbsent = 1; @@ -1985,7 +1985,7 @@ static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename ) { static const WCHAR name[] = {'\\',0}; - VS_FIXEDFILEINFO *ret; + VS_FIXEDFILEINFO *ptr, *ret; LPVOID version; DWORD versize, handle; UINT sz; @@ -2002,12 +2002,15 @@ VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename ) GetFileVersionInfoW( filename, 0, versize, version ); - if (!VerQueryValueW( version, name, (LPVOID *)&ret, &sz )) + if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz )) { msi_free( version ); return NULL; } + ret = msi_alloc( sz ); + memcpy( ret, ptr, sz ); + msi_free( version ); return ret; } @@ -2371,17 +2374,43 @@ static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key return ret; } +static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path ) +{ + static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'}; + static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]); + + if (is_64bit && package->platform == PLATFORM_INTEL && + root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len )) + { + UINT size; + WCHAR *path_32node; + + size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR); + path_32node = msi_alloc( size ); + if (!path_32node) + return NULL; + + memcpy( path_32node, path, len * sizeof(WCHAR) ); + path_32node[len] = 0; + strcatW( path_32node, szWow6432Node ); + strcatW( path_32node, szBackSlash ); + strcatW( path_32node, path + len ); + return path_32node; + } + + return strdupW( path ); +} + static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) { MSIPACKAGE *package = param; LPSTR value_data = NULL; HKEY root_key, hkey; DWORD type,size; - LPWSTR deformated; + LPWSTR deformated, uikey, keypath; LPCWSTR szRoot, component, name, key, value; MSICOMPONENT *comp; MSIRECORD * uirow; - LPWSTR uikey; INT root; BOOL check_first = FALSE; UINT rc; @@ -2432,14 +2461,14 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) strcpyW(uikey,szRoot); strcatW(uikey,deformated); - if (RegCreateKeyW( root_key, deformated, &hkey)) + keypath = get_keypath( package, root_key, deformated ); + msi_free( deformated ); + if (RegCreateKeyW( root_key, keypath, &hkey )) { - ERR("Could not create key %s\n",debugstr_w(deformated)); - msi_free(deformated); + ERR("Could not create key %s\n", debugstr_w(keypath)); msi_free(uikey); return ERROR_SUCCESS; } - msi_free(deformated); value = MSI_RecordGetString(row,5); if (value) @@ -2554,7 +2583,7 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para { MSIPACKAGE *package = param; LPCWSTR component, name, key_str, root_key_str; - LPWSTR deformated_key, deformated_name, ui_key_str; + LPWSTR deformated_key, deformated_name, ui_key_str, keypath; MSICOMPONENT *comp; MSIRECORD *uirow; BOOL delete_key = FALSE; @@ -2610,8 +2639,10 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para deformat_string( package, name, &deformated_name ); - delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key ); + keypath = get_keypath( package, hkey_root, deformated_key ); msi_free( deformated_key ); + delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key ); + msi_free( keypath ); uirow = MSI_CreateRecord( 2 ); MSI_RecordSetStringW( uirow, 1, ui_key_str ); @@ -2629,7 +2660,7 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param { MSIPACKAGE *package = param; LPCWSTR component, name, key_str, root_key_str; - LPWSTR deformated_key, deformated_name, ui_key_str; + LPWSTR deformated_key, deformated_name, ui_key_str, keypath; MSICOMPONENT *comp; MSIRECORD *uirow; BOOL delete_key = FALSE; @@ -2682,8 +2713,10 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param deformat_string( package, name, &deformated_name ); - delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key ); + keypath = get_keypath( package, hkey_root, deformated_key ); msi_free( deformated_key ); + delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key ); + msi_free( keypath ); uirow = MSI_CreateRecord( 2 ); MSI_RecordSetStringW( uirow, 1, ui_key_str ); @@ -3891,7 +3924,7 @@ static UINT msi_publish_patches( MSIPACKAGE *package ) WCHAR *p, *all_patches = NULL; DWORD len = 0; - r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, FALSE ); + r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE ); if (r != ERROR_SUCCESS) return ERROR_FUNCTION_FAILED; @@ -4759,7 +4792,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) if (!msi_check_publish(package)) return ERROR_SUCCESS; - rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE); + rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE); if (rc != ERROR_SUCCESS) return rc; @@ -4839,7 +4872,7 @@ static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove) MSIREG_DeleteProductKey(package->ProductCode); MSIREG_DeleteUserDataProductKey(package->ProductCode); - MSIREG_DeleteUninstallKey(package->ProductCode); + MSIREG_DeleteUninstallKey(package); if (package->Context == MSIINSTALLCONTEXT_MACHINE) { @@ -7498,7 +7531,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, msi_clone_properties( package ); msi_parse_command_line( package, szCommandLine, FALSE ); - msi_adjust_allusers_property( package ); + msi_adjust_privilege_properties( package ); msi_set_context( package ); if (needs_ui_sequence( package)) diff --git a/dll/win32/msi/appsearch.c b/dll/win32/msi/appsearch.c index a516bdad1c8..dfab3960b01 100644 --- a/dll/win32/msi/appsearch.c +++ b/dll/win32/msi/appsearch.c @@ -89,7 +89,7 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, 'S','i','g','n','a','t','u','r','e',' ', 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e',' ','=',' ', '\'','%','s','\'',0}; - LPWSTR minVersion, maxVersion; + LPWSTR minVersion, maxVersion, p; MSIRECORD *row; DWORD time; @@ -106,6 +106,12 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, /* get properties */ sig->File = msi_dup_record_field(row,2); + if ((p = strchrW(sig->File, '|'))) + { + p++; + memmove(sig->File, p, (strlenW(p) + 1) * sizeof(WCHAR)); + } + minVersion = msi_dup_record_field(row,3); if (minVersion) { diff --git a/dll/win32/msi/classes.c b/dll/win32/msi/classes.c index 30ee36b4bfd..beaf1f0ff93 100644 --- a/dll/win32/msi/classes.c +++ b/dll/win32/msi/classes.c @@ -804,12 +804,19 @@ static UINT register_appid(const MSIAPPID *appid, LPCWSTR app ) UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) { static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0}; + const WCHAR *keypath; MSIRECORD *uirow; HKEY hkey,hkey2,hkey3; MSICLASS *cls; load_classes_and_such(package); - if (RegCreateKeyW(HKEY_CLASSES_ROOT, szCLSID, &hkey) != ERROR_SUCCESS) + + if (is_64bit && package->platform == PLATFORM_INTEL) + keypath = szWow6432NodeCLSID; + else + keypath = szCLSID; + + if (RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, &hkey) != ERROR_SUCCESS) return ERROR_FUNCTION_FAILED; LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) @@ -963,12 +970,19 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package ) { static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0}; + const WCHAR *keypath; MSIRECORD *uirow; MSICLASS *cls; HKEY hkey, hkey2; load_classes_and_such( package ); - if (RegOpenKeyW( HKEY_CLASSES_ROOT, szCLSID, &hkey ) != ERROR_SUCCESS) + + if (is_64bit && package->platform == PLATFORM_INTEL) + keypath = szWow6432NodeCLSID; + else + keypath = szCLSID; + + if (RegOpenKeyW( HKEY_CLASSES_ROOT, keypath, &hkey ) != ERROR_SUCCESS) return ERROR_SUCCESS; LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) @@ -1072,7 +1086,7 @@ static UINT register_progid( const MSIPROGID* progid ) if (clsid) msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid ); else - ERR("%s has no class\n", debugstr_w( progid->ProgID ) ); + TRACE("%s has no class\n", debugstr_w( progid->ProgID ) ); if (progid->Description) msi_reg_set_val_str( hkey, NULL, progid->Description ); diff --git a/dll/win32/msi/cond.tab.c b/dll/win32/msi/cond.tab.c index 2b10d209be6..e68723db89b 100644 --- a/dll/win32/msi/cond.tab.c +++ b/dll/win32/msi/cond.tab.c @@ -2329,11 +2329,21 @@ static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b ) case COND_LHS: return 0 == strncmpW( a, b, lstrlenW( b ) ); case COND_RHS: - return 0 == lstrcmpW( a + (lstrlenW( a ) - lstrlenW( b )), b ); + { + int l = lstrlenW( a ); + int r = lstrlenW( b ); + if (r > l) return 0; + return 0 == lstrcmpW( a + (l - r), b ); + } case COND_ILHS: return 0 == strncmpiW( a, b, lstrlenW( b ) ); case COND_IRHS: - return 0 == lstrcmpiW( a + (lstrlenW( a ) - lstrlenW( b )), b ); + { + int l = lstrlenW( a ); + int r = lstrlenW( b ); + if (r > l) return 0; + return 0 == lstrcmpiW( a + (l - r), b ); + } default: ERR("invalid substring operator\n"); return 0; diff --git a/dll/win32/msi/cond.y b/dll/win32/msi/cond.y index 9a7a16d67df..03ea4938ade 100644 --- a/dll/win32/msi/cond.y +++ b/dll/win32/msi/cond.y @@ -462,11 +462,21 @@ static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b ) case COND_LHS: return 0 == strncmpW( a, b, lstrlenW( b ) ); case COND_RHS: - return 0 == lstrcmpW( a + (lstrlenW( a ) - lstrlenW( b )), b ); + { + int l = lstrlenW( a ); + int r = lstrlenW( b ); + if (r > l) return 0; + return 0 == lstrcmpW( a + (l - r), b ); + } case COND_ILHS: return 0 == strncmpiW( a, b, lstrlenW( b ) ); case COND_IRHS: - return 0 == lstrcmpiW( a + (lstrlenW( a ) - lstrlenW( b )), b ); + { + int l = lstrlenW( a ); + int r = lstrlenW( b ); + if (r > l) return 0; + return 0 == lstrcmpiW( a + (l - r), b ); + } default: ERR("invalid substring operator\n"); return 0; diff --git a/dll/win32/msi/custom.c b/dll/win32/msi/custom.c index 5a1787f7d15..b56139fb665 100644 --- a/dll/win32/msi/custom.c +++ b/dll/win32/msi/custom.c @@ -222,13 +222,6 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL if (type & msidbCustomActionTypeNoImpersonate) WARN("msidbCustomActionTypeNoImpersonate not handled\n"); - if (type & msidbCustomActionTypeRollback) - { - FIXME("Rollback only action... rollbacks not supported yet\n"); - schedule_action(package, ROLLBACK_SCRIPT, action); - rc = ERROR_SUCCESS; - goto end; - } if (!execute) { LPWSTR actiondata = msi_dup_property(package->db, action); @@ -238,12 +231,17 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL if (type & msidbCustomActionTypeCommit) { - TRACE("Deferring Commit Action!\n"); + TRACE("Deferring commit action\n"); schedule_action(package, COMMIT_SCRIPT, deferred); } + else if (type & msidbCustomActionTypeRollback) + { + FIXME("Deferring rollback only action... rollbacks not supported yet\n"); + schedule_action(package, ROLLBACK_SCRIPT, deferred); + } else { - TRACE("Deferring Action!\n"); + TRACE("Deferring action\n"); schedule_action(package, INSTALL_SCRIPT, deferred); } @@ -258,20 +256,14 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL { LPWSTR actiondata = msi_dup_property( package->db, action ); - switch (script) - { - case INSTALL_SCRIPT: + if (type & msidbCustomActionTypeInScript) package->scheduled_action_running = TRUE; - break; - case COMMIT_SCRIPT: + + if (type & msidbCustomActionTypeCommit) package->commit_action_running = TRUE; - break; - case ROLLBACK_SCRIPT: + + if (type & msidbCustomActionTypeRollback) package->rollback_action_running = TRUE; - break; - default: - break; - } if (deferred_data) set_deferred_action_props(package, deferred_data); diff --git a/dll/win32/msi/database.c b/dll/win32/msi/database.c index 01c32497a37..3007d485b2b 100644 --- a/dll/win32/msi/database.c +++ b/dll/win32/msi/database.c @@ -241,7 +241,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) free_cached_tables( db ); free_streams( db ); free_transforms( db ); - msi_destroy_stringtable( db->strings ); + if (db->strings) msi_destroy_stringtable( db->strings ); IStorage_Release( db->storage ); if (db->deletefile) { @@ -255,6 +255,43 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) } } +static HRESULT db_initialize( IStorage *stg, const GUID *clsid ) +{ + static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; + HRESULT hr; + + hr = IStorage_SetClass( stg, clsid ); + if (FAILED( hr )) + { + WARN("failed to set class id 0x%08x\n", hr); + return hr; + } + + /* create the _Tables stream */ + hr = write_stream_data( stg, szTables, NULL, 0, TRUE ); + if (FAILED( hr )) + { + WARN("failed to create _Tables stream 0x%08x\n", hr); + return hr; + } + + hr = msi_init_string_table( stg ); + if (FAILED( hr )) + { + WARN("failed to initialize string table 0x%08x\n", hr); + return hr; + } + + hr = IStorage_Commit( stg, 0 ); + if (FAILED( hr )) + { + WARN("failed to commit changes 0x%08x\n", hr); + return hr; + } + + return S_OK; +} + UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) { IStorage *stg = NULL; @@ -266,8 +303,6 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) BOOL created = FALSE, patch = FALSE; WCHAR path[MAX_PATH]; - static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; - TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) ); if( !pdb ) @@ -298,28 +333,28 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) r = StgOpenStorage( szDBPath, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg); } - else if( szPersist == MSIDBOPEN_CREATE || szPersist == MSIDBOPEN_CREATEDIRECT ) + else if( szPersist == MSIDBOPEN_CREATE ) { - /* FIXME: MSIDBOPEN_CREATE should case STGM_TRANSACTED flag to be - * used here: */ r = StgCreateDocfile( szDBPath, - STGM_CREATE|STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg); - if( r == ERROR_SUCCESS ) - { - IStorage_SetClass( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase ); - /* create the _Tables stream */ - r = write_stream_data(stg, szTables, NULL, 0, TRUE); - if (SUCCEEDED(r)) - r = msi_init_string_table( stg ); - } + STGM_CREATE|STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg ); + + if( SUCCEEDED(r) ) + r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase ); + created = TRUE; + } + else if( szPersist == MSIDBOPEN_CREATEDIRECT ) + { + r = StgCreateDocfile( szDBPath, + STGM_CREATE|STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg ); + + if( SUCCEEDED(r) ) + r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase ); created = TRUE; } else if( szPersist == MSIDBOPEN_TRANSACT ) { - /* FIXME: MSIDBOPEN_TRANSACT should case STGM_TRANSACTED flag to be - * used here: */ r = StgOpenStorage( szDBPath, NULL, - STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg); + STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg); } else if( szPersist == MSIDBOPEN_DIRECT ) { diff --git a/dll/win32/msi/join.c b/dll/win32/msi/join.c index f787c309a41..7fe7f1c2677 100644 --- a/dll/win32/msi/join.c +++ b/dll/win32/msi/join.c @@ -60,8 +60,6 @@ static UINT JOIN_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *v UINT cols = 0; UINT prev_rows = 1; - TRACE("%d, %d\n", row, col); - if (col == 0 || col > jv->columns) return ERROR_FUNCTION_FAILED; @@ -225,10 +223,12 @@ static UINT JOIN_get_column_info( struct tagMSIVIEW *view, static UINT join_find_row( MSIJOINVIEW *jv, MSIRECORD *rec, UINT *row ) { LPCWSTR str; - UINT i, id, data; + UINT r, i, id, data; str = MSI_RecordGetString( rec, 1 ); - msi_string2idW( jv->db->strings, str, &id ); + r = msi_string2idW( jv->db->strings, str, &id ); + if (r != ERROR_SUCCESS) + return r; for (i = 0; i < jv->rows; i++) { diff --git a/dll/win32/msi/media.c b/dll/win32/msi/media.c index a2a90654186..788528e9b37 100644 --- a/dll/win32/msi/media.c +++ b/dll/win32/msi/media.c @@ -211,9 +211,6 @@ static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode ) UINT r; IStream *stm; - if (oflag) - WARN("ignoring open flags 0x%08x\n", oflag); - r = db_get_raw_stream( cab_stream.db, cab_stream.name, &stm ); if (r != ERROR_SUCCESS) { @@ -358,6 +355,40 @@ done: return res; } +static INT_PTR cabinet_next_cabinet_stream( FDINOTIFICATIONTYPE fdint, + PFDINOTIFICATION pfdin ) +{ + MSICABDATA *data = pfdin->pv; + MSIMEDIAINFO *mi = data->mi; + UINT rc; + + msi_free( mi->disk_prompt ); + msi_free( mi->cabinet ); + msi_free( mi->volume_label ); + mi->disk_prompt = NULL; + mi->cabinet = NULL; + mi->volume_label = NULL; + + mi->disk_id++; + mi->is_continuous = TRUE; + + rc = msi_media_get_disk_info( data->package, mi ); + if (rc != ERROR_SUCCESS) + { + ERR("Failed to get next cabinet information: %u\n", rc); + return -1; + } + + msi_free( cab_stream.name ); + cab_stream.name = encode_streamname( FALSE, mi->cabinet + 1 ); + if (!cab_stream.name) + return -1; + + TRACE("next cabinet is %s\n", debugstr_w(mi->cabinet)); + + return 0; +} + static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) { @@ -494,6 +525,12 @@ static INT_PTR CDECL cabinet_notify_stream( FDINOTIFICATIONTYPE fdint, PFDINOTIF { switch (fdint) { + case fdintPARTIAL_FILE: + return cabinet_partial_file( fdint, pfdin ); + + case fdintNEXT_CABINET: + return cabinet_next_cabinet_stream( fdint, pfdin ); + case fdintCOPY_FILE: return cabinet_copy_file( fdint, pfdin ); diff --git a/dll/win32/msi/msi.c b/dll/win32/msi/msi.c index fb7eba5f54e..fb90758a647 100644 --- a/dll/win32/msi/msi.c +++ b/dll/win32/msi/msi.c @@ -3779,3 +3779,45 @@ UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState); return ERROR_SUCCESS; } + +UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event ); +/*********************************************************************** + * MsiBeginTransactionA [MSI.@] + */ +UINT WINAPI MsiBeginTransactionA( LPCSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event ) +{ + WCHAR *nameW; + UINT r; + + FIXME("%s %u %p %p\n", debugstr_a(name), attrs, id, event); + + nameW = strdupAtoW( name ); + if (name && !nameW) + return ERROR_OUTOFMEMORY; + + r = MsiBeginTransactionW( nameW, attrs, id, event ); + msi_free( nameW ); + return r; +} + +/*********************************************************************** + * MsiBeginTransactionW [MSI.@] + */ +UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event ) +{ + FIXME("%s %u %p %p\n", debugstr_w(name), attrs, id, event); + + *id = (MSIHANDLE)0xdeadbeef; + *event = (HANDLE)0xdeadbeef; + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * MsiEndTransaction [MSI.@] + */ +UINT WINAPI MsiEndTransaction( DWORD state ) +{ + FIXME("%u\n", state); + return ERROR_SUCCESS; +} diff --git a/dll/win32/msi/msi.spec b/dll/win32/msi/msi.spec index 6fdebd86f10..fd047f8a652 100644 --- a/dll/win32/msi/msi.spec +++ b/dll/win32/msi/msi.spec @@ -174,7 +174,7 @@ 178 stdcall MsiGetPatchInfoA(str str ptr ptr) 179 stdcall MsiGetPatchInfoW(wstr wstr ptr ptr) 180 stdcall MsiEnumPatchesA(str long ptr ptr ptr) -181 stdcall MsiEnumPatchesW(str long ptr ptr ptr) +181 stdcall MsiEnumPatchesW(wstr long ptr ptr ptr) 182 stdcall -private DllGetVersion(ptr) 183 stub MsiGetProductCodeFromPackageCodeA 184 stub MsiGetProductCodeFromPackageCodeW @@ -214,7 +214,7 @@ 218 stdcall MsiGetFileHashA(str long ptr) 219 stdcall MsiGetFileHashW(wstr long ptr) 220 stub MsiEnumComponentCostsA -221 stdcall MsiEnumComponentCostsW(long str long long ptr ptr ptr ptr) +221 stdcall MsiEnumComponentCostsW(long wstr long long ptr ptr ptr ptr) 222 stdcall MsiCreateAndVerifyInstallerDirectory(long) 223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr) 224 stdcall MsiGetFileSignatureInformationW(wstr long ptr ptr ptr) @@ -277,9 +277,9 @@ 281 stdcall MsiSetExternalUIRecord(ptr long ptr ptr) 282 stub MsiGetPatchFileListA 283 stub MsiGetPatchFileListW -284 stub MsiBeginTransactionA -285 stub MsiBeginTransactionW -286 stub MsiEndTransaction +284 stdcall MsiBeginTransactionA(str long ptr ptr) +285 stdcall MsiBeginTransactionW(wstr long ptr ptr) +286 stdcall MsiEndTransaction(long) 287 stub MsiJoinTransaction 288 stub MsiSetOfflineContextW 289 stub MsiEnumComponentsExA diff --git a/dll/win32/msi/msi_Fi.rc b/dll/win32/msi/msi_Fi.rc index 7769a8afe76..89841729a73 100644 --- a/dll/win32/msi/msi_Fi.rc +++ b/dll/win32/msi/msi_Fi.rc @@ -24,39 +24,39 @@ LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT STRINGTABLE { - 4 "The specified installation package could not be opened. Please check the file path and try again." + 4 "Annettua asennuspakettia ei voitu avata. Tarkista tiedoston polku ja yritä uudelleen." 5 "Polkua %s ei löydy." 9 "Anna levy %s" 10 "Windows Installer %s\n\n" \ - "Usage:\n" \ - "msiexec command {required parameter} [optional parammeter]\n\n" \ - "Install a product:\n" \ - "\t/i {package|productcode} [property]\n" \ - "\t/package {package|productcode} [property]\n" \ - "\t/a package [property]\n" \ - "Repair an installation:\n" \ - "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \ - "Uninstall a product:\n" \ - "\t/uninstall {package|productcode} [property]\n" \ - "\t/x {package|productcode} [property]\n" \ - "Advertise a product:\n" \ - "\t/j[u|m] package [/t transform] [/g languageid]\n" \ - "Apply a patch:\n" \ - "\t/p patchpackage [property]\n" \ - "\t/p patchpackage /a package [property]\n" \ - "Log and UI Modifiers for above commands:\n" \ - "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \ + "Käyttö:\n" \ + "msiexec komento {pakollinen parametri} [valinnainen parametri]\n\n" \ + "Asenna tuote:\n" \ + "\t/i {paketti|tuotekoodi} [ominaisuus]\n" \ + "\t/package {paketti|tuotekoodi} [ominaisuus]\n" \ + "\t/a {paketti} [ominaisuus]\n" \ + "Korjaa asennus:\n" \ + "\t/f[p|o|e|d|c|a|u|m|s|v] {paketti|tuotekoodi}\n" \ + "Poista tuote:\n" \ + "\t/uninstall {paketti|tuotekoodi} [ominaisuus]\n" \ + "\t/x {paketti|tuotekoodi} [ominaisuus]\n" \ + "Mainosta (advertise) tuotetta:\n" \ + "\t/j[u|m] paketti [/t muunnos] [/g kielitunnus]\n" \ + "Asenna korjaus:\n" \ + "\t/p korjauspaketti [ominaisuus]\n" \ + "\t/p korjauspaketti /a paketti [ominaisuus]\n" \ + "Loki- ja käyttöliittymäasetukset edellisille komennoille:\n" \ + "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] lokitiedosto\n" \ "\t/q{|n|b|r|f|n+|b+|b-}\n" \ - "Register MSI Service:\n" \ + "Rekisteröi MSI-palvelu:\n" \ "\t/y\n" \ - "Unregister MSI Service:\n" \ + "Peru MSI-palvelun rekisteröinti:\n" \ "\t/z\n" \ - "Display this help:\n" \ + "Näytä tämä ohje:\n" \ "\t/help\n" \ "\t/?\n" - 11 "Anna kansio, joka sisältää %s" + 11 "Anna kansio, jossa on %s" 12 "Ominaisuuden asennuslähde puuttuu." 13 "Ominaisuuden verkkolevy puuttuu." 14 "Ominaisuus:" - 15 "Valitse kansio, joka sisältää %s" + 15 "Valitse kansio, jossa on %s" } diff --git a/dll/win32/msi/msipriv.h b/dll/win32/msi/msipriv.h index 344b1450e3a..0361ff42c6e 100644 --- a/dll/win32/msi/msipriv.h +++ b/dll/win32/msi/msipriv.h @@ -29,6 +29,7 @@ #include "fdi.h" #include "msi.h" #include "msiquery.h" +#include "msidefs.h" #include "objbase.h" #include "objidl.h" #include "winnls.h" @@ -36,6 +37,8 @@ #include "wine/list.h" #include "wine/debug.h" +static const BOOL is_64bit = sizeof(void *) > sizeof(int); + #define MSI_DATASIZEMASK 0x00ff #define MSITYPE_VALID 0x0100 #define MSITYPE_LOCALIZABLE 0x200 @@ -45,6 +48,7 @@ #define MSITYPE_TEMPORARY 0x4000 #define MAX_STREAM_NAME_LEN 62 +#define LONG_STR_BYTES 3 /* Install UI level mask for AND operation to exclude flags */ #define INSTALLUILEVEL_MASK 0x0007 @@ -103,6 +107,7 @@ typedef struct tagMSIFIELD union { INT iVal; + INT_PTR pVal; LPWSTR szwVal; IStream *stream; } u; @@ -303,10 +308,21 @@ struct tagMSIVIEW struct msi_dialog_tag; typedef struct msi_dialog_tag msi_dialog; +enum platform +{ + PLATFORM_INTEL, + PLATFORM_INTEL64, + PLATFORM_X64 +}; + typedef struct tagMSIPACKAGE { MSIOBJECTHDR hdr; MSIDATABASE *db; + INT version; + enum platform platform; + UINT num_langids; + LANGID *langids; struct list patches; struct list components; struct list features; @@ -388,7 +404,6 @@ typedef struct tagMSIFEATURE typedef struct tagMSICOMPONENT { struct list entry; - DWORD magic; LPWSTR Component; LPWSTR ComponentId; LPWSTR Directory; @@ -595,9 +610,9 @@ typedef struct tagMSISCRIPT #define MSIHANDLETYPE_PACKAGE 5 #define MSIHANDLETYPE_PREVIEW 6 -#define MSI_MAJORVERSION 3 -#define MSI_MINORVERSION 1 -#define MSI_BUILDNUMBER 4000 +#define MSI_MAJORVERSION 4 +#define MSI_MINORVERSION 5 +#define MSI_BUILDNUMBER 6001 #define GUID_SIZE 39 #define SQUISH_GUID_SIZE 33 @@ -672,7 +687,7 @@ extern VOID msi_destroy_stringtable( string_table *st ); extern const WCHAR *msi_string_lookup_id( const string_table *st, UINT id ); extern HRESULT msi_init_string_table( IStorage *stg ); extern string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref ); -extern UINT msi_save_string_table( const string_table *st, IStorage *storage ); +extern UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *bytes_per_strref ); extern BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name ); extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table ); @@ -709,11 +724,13 @@ extern UINT MSI_RecordGetIStream( MSIRECORD *, UINT, IStream **); extern const WCHAR *MSI_RecordGetString( const MSIRECORD *, UINT ); extern MSIRECORD *MSI_CreateRecord( UINT ); extern UINT MSI_RecordSetInteger( MSIRECORD *, UINT, int ); +extern UINT MSI_RecordSetIntPtr( MSIRECORD *, UINT, INT_PTR ); extern UINT MSI_RecordSetStringW( MSIRECORD *, UINT, LPCWSTR ); extern BOOL MSI_RecordIsNull( MSIRECORD *, UINT ); extern UINT MSI_RecordGetStringW( MSIRECORD * , UINT, LPWSTR, LPDWORD); extern UINT MSI_RecordGetStringA( MSIRECORD *, UINT, LPSTR, LPDWORD); extern int MSI_RecordGetInteger( MSIRECORD *, UINT ); +extern INT_PTR MSI_RecordGetIntPtr( MSIRECORD *, UINT ); extern UINT MSI_RecordReadStream( MSIRECORD *, UINT, char *, LPDWORD); extern UINT MSI_RecordSetStream(MSIRECORD *, UINT, IStream *); extern UINT MSI_RecordGetFieldCount( const MSIRECORD *rec ); @@ -765,7 +782,7 @@ extern UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR); extern UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR); extern UINT msi_clone_properties(MSIPACKAGE *); extern UINT msi_set_context(MSIPACKAGE *); -extern void msi_adjust_allusers_property(MSIPACKAGE *); +extern void msi_adjust_privilege_properties(MSIPACKAGE *); extern UINT MSI_GetFeatureCost(MSIPACKAGE *, MSIFEATURE *, MSICOSTTREE, INSTALLSTATE, LPINT); /* for deformating */ @@ -776,8 +793,8 @@ extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out); extern BOOL squash_guid(LPCWSTR in, LPWSTR out); extern BOOL encode_base85_guid(GUID *,LPWSTR); extern BOOL decode_base85_guid(LPCWSTR,GUID*); -extern UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create); -extern UINT MSIREG_DeleteUninstallKey(LPCWSTR szProduct); +extern UINT MSIREG_OpenUninstallKey(MSIPACKAGE *package, HKEY *key, BOOL create); +extern UINT MSIREG_DeleteUninstallKey(MSIPACKAGE *package); extern UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY* key, BOOL create); extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context, @@ -843,6 +860,7 @@ extern UINT msi_spawn_error_dialog( MSIPACKAGE*, LPWSTR, LPWSTR ); /* summary information */ extern MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount ); extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ); +extern INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ); extern LPWSTR msi_get_suminfo_product( IStorage *stg ); extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ); @@ -915,6 +933,10 @@ static inline void msi_feature_set_state(MSIPACKAGE *package, feature->ActionRequest = state; feature->Action = state; } + if (feature->Attributes & msidbFeatureAttributesUIDisallowAbsent) + { + feature->Action = INSTALLSTATE_UNKNOWN; + } } static inline void msi_component_set_state(MSIPACKAGE *package, @@ -1123,6 +1145,12 @@ static const WCHAR szMIMEDatabase[] = {'M','I','M','E','\\','D','a','t','a','b', static const WCHAR szLocalPackage[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0}; static const WCHAR szOriginalDatabase[] = {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0}; +static const WCHAR szAdminUser[] = {'A','d','m','i','n','U','s','e','r',0}; +static const WCHAR szIntel[] = {'I','n','t','e','l',0}; +static const WCHAR szIntel64[] = {'I','n','t','e','l','6','4',0}; +static const WCHAR szX64[] = {'x','6','4',0}; +static const WCHAR szWow6432NodeCLSID[] = {'W','o','w','6','4','3','2','N','o','d','e','\\','C','L','S','I','D',0}; +static const WCHAR szWow6432Node[] = {'W','o','w','6','4','3','2','N','o','d','e',0}; /* memory allocation macro functions */ static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1); diff --git a/dll/win32/msi/msiquery.c b/dll/win32/msi/msiquery.c index df81a748223..cf6959391d3 100644 --- a/dll/win32/msi/msiquery.c +++ b/dll/win32/msi/msiquery.c @@ -382,7 +382,7 @@ UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec) if (r == ERROR_SUCCESS) { query->row ++; - MSI_RecordSetInteger(*prec, 0, (int)query); + MSI_RecordSetIntPtr(*prec, 0, (INT_PTR)query); } return r; @@ -617,7 +617,7 @@ UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec ) if ( !view || !view->ops->modify) return ERROR_FUNCTION_FAILED; - if ( mode == MSIMODIFY_UPDATE && MSI_RecordGetInteger( rec, 0 ) != (int)query ) + if ( mode == MSIMODIFY_UPDATE && MSI_RecordGetIntPtr( rec, 0 ) != (INT_PTR)query ) return ERROR_FUNCTION_FAILED; r = view->ops->modify( view, mode, rec, query->row ); @@ -901,6 +901,9 @@ UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, MSIQUERY *query = NULL; UINT r; + if (!TABLE_Exists( db, table )) + return ERROR_INVALID_TABLE; + r = MSI_OpenQuery( db, &query, sql, table ); if( r != ERROR_SUCCESS ) return r; diff --git a/dll/win32/msi/package.c b/dll/win32/msi/package.c index d3321686964..32576a0362c 100644 --- a/dll/win32/msi/package.c +++ b/dll/win32/msi/package.c @@ -280,6 +280,7 @@ static void free_package_structures( MSIPACKAGE *package ) msi_free( package->ProductCode ); msi_free( package->ActionFormat ); msi_free( package->LastAction ); + msi_free( package->langids ); /* cleanup control event subscriptions */ ControlEvent_CleanupSubscriptions( package ); @@ -417,7 +418,7 @@ static UINT set_installed_prop( MSIPACKAGE *package ) HKEY hkey = 0; UINT r; - r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE ); + r = MSIREG_OpenUninstallKey( package, &hkey, FALSE ); if (r == ERROR_SUCCESS) { RegCloseKey( hkey ); @@ -618,72 +619,49 @@ static VOID set_installer_properties(MSIPACKAGE *package) SYSTEMTIME systemtime; LANGID langid; - static const WCHAR CFF[] = -{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0}; - static const WCHAR PFF[] = -{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0}; - static const WCHAR CADF[] = -{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; - static const WCHAR FaF[] = -{'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0}; - static const WCHAR FoF[] = -{'F','o','n','t','s','F','o','l','d','e','r',0}; - static const WCHAR SendTF[] = -{'S','e','n','d','T','o','F','o','l','d','e','r',0}; - static const WCHAR SMF[] = -{'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0}; - static const WCHAR StF[] = -{'S','t','a','r','t','u','p','F','o','l','d','e','r',0}; - static const WCHAR TemplF[] = -{'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0}; - static const WCHAR DF[] = -{'D','e','s','k','t','o','p','F','o','l','d','e','r',0}; - static const WCHAR PMF[] = -{'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0}; - static const WCHAR ATF[] = -{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0}; - static const WCHAR ADF[] = -{'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; - static const WCHAR SF[] = -{'S','y','s','t','e','m','F','o','l','d','e','r',0}; - static const WCHAR SF16[] = -{'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0}; - static const WCHAR LADF[] = -{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; - static const WCHAR MPF[] = -{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0}; - static const WCHAR PF[] = -{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0}; - static const WCHAR WF[] = -{'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; - static const WCHAR WV[] = -{'W','i','n','d','o','w','s','V','o','l','u','m','e',0}; - static const WCHAR TF[]= -{'T','e','m','p','F','o','l','d','e','r',0}; - static const WCHAR szAdminUser[] = -{'A','d','m','i','n','U','s','e','r',0}; - static const WCHAR szPriv[] = -{'P','r','i','v','i','l','e','g','e','d',0}; - static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 }; - static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 }; - static const WCHAR szMsiNTProductType[] = { 'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0 }; + static const WCHAR szCommonFilesFolder[] = {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0}; + static const WCHAR szProgramFilesFolder[] = {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0}; + static const WCHAR szCommonAppDataFolder[] = {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + static const WCHAR szFavoritesFolder[] = {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0}; + static const WCHAR szFontsFolder[] = {'F','o','n','t','s','F','o','l','d','e','r',0}; + static const WCHAR szSendToFolder[] = {'S','e','n','d','T','o','F','o','l','d','e','r',0}; + static const WCHAR szStartMenuFolder[] = {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0}; + static const WCHAR szStartupFolder[] = {'S','t','a','r','t','u','p','F','o','l','d','e','r',0}; + static const WCHAR szTemplateFolder[] = {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0}; + static const WCHAR szDesktopFolder[] = {'D','e','s','k','t','o','p','F','o','l','d','e','r',0}; + static const WCHAR szProgramMenuFolder[] = {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0}; + static const WCHAR szAdminToolsFolder[] = {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0}; + static const WCHAR szAppDataFolder[] = {'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + static const WCHAR szSystemFolder[] = {'S','y','s','t','e','m','F','o','l','d','e','r',0}; + static const WCHAR szSystem16Folder[] = {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0}; + static const WCHAR szLocalAppDataFolder[] = {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + static const WCHAR szMyPicturesFolder[] = {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0}; + static const WCHAR szPersonalFolder[] = {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0}; + static const WCHAR szWindowsFolder[] = {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + static const WCHAR szWindowsVolume[] = {'W','i','n','d','o','w','s','V','o','l','u','m','e',0}; + static const WCHAR szTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; + static const WCHAR szPrivileged[] = {'P','r','i','v','i','l','e','g','e','d',0}; + static const WCHAR szVersion9x[] = {'V','e','r','s','i','o','n','9','X',0}; + static const WCHAR szVersionNT[] = {'V','e','r','s','i','o','n','N','T',0}; + static const WCHAR szMsiNTProductType[] = {'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0}; static const WCHAR szFormat[] = {'%','l','i',0}; - static const WCHAR szWinBuild[] = -{'W','i','n','d','o','w','s','B','u','i','l','d', 0 }; - static const WCHAR szSPL[] = -{'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 }; + static const WCHAR szWindowsBuild[] = {'W','i','n','d','o','w','s','B','u','i','l','d',0}; + static const WCHAR szServicePackLevel[] = {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0}; static const WCHAR szSix[] = {'6',0 }; - static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 }; static const WCHAR szVersionDatabase[] = { 'V','e','r','s','i','o','n','D','a','t','a','b','a','s','e',0 }; static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 }; static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0}; -/* Screen properties */ static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0}; static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0}; static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0}; static const WCHAR szIntFormat[] = {'%','d',0}; - static const WCHAR szIntel[] = { 'I','n','t','e','l',0 }; + static const WCHAR szMsiAMD64[] = { 'M','s','i','A','M','D','6','4',0 }; + static const WCHAR szMsix64[] = { 'M','s','i','x','6','4',0 }; + static const WCHAR szSystem64Folder[] = { 'S','y','s','t','e','m','6','4','F','o','l','d','e','r',0 }; + static const WCHAR szCommonFiles64Folder[] = { 'C','o','m','m','o','n','F','i','l','e','s','6','4','F','o','l','d','e','r',0 }; + static const WCHAR szProgramFiles64Folder[] = { 'P','r','o','g','r','a','m','F','i','l','e','s','6','4','F','o','l','d','e','r',0 }; + static const WCHAR szVersionNT64[] = { 'V','e','r','s','i','o','n','N','T','6','4',0 }; static const WCHAR szUserInfo[] = { 'S','O','F','T','W','A','R','E','\\', 'M','i','c','r','o','s','o','f','t','\\', @@ -699,17 +677,20 @@ static VOID set_installer_properties(MSIPACKAGE *package) 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0 }; static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0}; - static const WCHAR szRegisteredOrg[] = { + static const WCHAR szRegisteredOrganization[] = { 'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0 }; static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0}; static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0}; static const WCHAR szDate[] = {'D','a','t','e',0}; static const WCHAR szTime[] = {'T','i','m','e',0}; - static const WCHAR szUserLangID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0}; + static const WCHAR szUserLanguageID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0}; static const WCHAR szSystemLangID[] = {'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0}; static const WCHAR szProductState[] = {'P','r','o','d','u','c','t','S','t','a','t','e',0}; static const WCHAR szLogonUser[] = {'L','o','g','o','n','U','s','e','r',0}; + static const WCHAR szNetHoodFolder[] = {'N','e','t','H','o','o','d','F','o','l','d','e','r',0}; + static const WCHAR szPrintHoodFolder[] = {'P','r','i','n','t','H','o','o','d','F','o','l','d','e','r',0}; + static const WCHAR szRecentFolder[] = {'R','e','c','e','n','t','F','o','l','d','e','r',0}; /* * Other things that probably should be set: @@ -720,130 +701,175 @@ static VOID set_installer_properties(MSIPACKAGE *package) * RedirectedDllSupport */ - SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, CFF, pth); + msi_set_property(package->db, szCommonAppDataFolder, pth); - SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, PFF, pth); + msi_set_property(package->db, szFavoritesFolder, pth); - SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, CADF, pth); + msi_set_property(package->db, szFontsFolder, pth); - SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_SENDTO, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, FaF, pth); + msi_set_property(package->db, szSendToFolder, pth); - SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, FoF, pth); + msi_set_property(package->db, szStartMenuFolder, pth); - SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_STARTUP, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, SendTF, pth); + msi_set_property(package->db, szStartupFolder, pth); - SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_TEMPLATES, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, SMF, pth); + msi_set_property(package->db, szTemplateFolder, pth); - SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, StF, pth); + msi_set_property(package->db, szDesktopFolder, pth); - SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth); + /* FIXME: set to AllUsers profile path if ALLUSERS is set */ + SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, TemplF, pth); + msi_set_property(package->db, szProgramMenuFolder, pth); - SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, DF, pth); + msi_set_property(package->db, szAdminToolsFolder, pth); - SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, PMF, pth); + msi_set_property(package->db, szAppDataFolder, pth); - SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, ATF, pth); + msi_set_property(package->db, szSystemFolder, pth); + msi_set_property(package->db, szSystem16Folder, pth); - SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, ADF, pth); + msi_set_property(package->db, szLocalAppDataFolder, pth); - SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, SF, pth); - msi_set_property(package->db, SF16, pth); + msi_set_property(package->db, szMyPicturesFolder, pth); - SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, LADF, pth); + msi_set_property(package->db, szPersonalFolder, pth); - SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth); + strcatW(pth, szBackSlash); + msi_set_property(package->db, szWindowsFolder, pth); + + SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, MPF, pth); + msi_set_property(package->db, szPrintHoodFolder, pth); - SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, PF, pth); + msi_set_property(package->db, szNetHoodFolder, pth); - SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, 0, pth); strcatW(pth, szBackSlash); - msi_set_property(package->db, WF, pth); - + msi_set_property(package->db, szRecentFolder, pth); + /* Physical Memory is specified in MB. Using total amount. */ msex.dwLength = sizeof(msex); GlobalMemoryStatusEx( &msex ); - sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys/1024/1024)); + sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys / 1024 / 1024) ); msi_set_property(package->db, szPhysicalMemory, bufstr); - SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); + SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth); ptr = strchrW(pth,'\\'); - if (ptr) - *(ptr+1) = 0; - msi_set_property(package->db, WV, pth); + if (ptr) *(ptr + 1) = 0; + msi_set_property(package->db, szWindowsVolume, pth); GetTempPathW(MAX_PATH,pth); - msi_set_property(package->db, TF, pth); - + msi_set_property(package->db, szTempFolder, pth); /* in a wine environment the user is always admin and privileged */ msi_set_property(package->db, szAdminUser, szOne); - msi_set_property(package->db, szPriv, szOne); + msi_set_property(package->db, szPrivileged, szOne); /* set the os things */ OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); GetVersionExW((OSVERSIONINFOW *)&OSVersion); - verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100; - sprintfW(verstr,szFormat,verval); + verval = OSVersion.dwMinorVersion + OSVersion.dwMajorVersion * 100; + sprintfW(verstr, szFormat, verval); switch (OSVersion.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: - msi_set_property(package->db, v9x, verstr); + msi_set_property(package->db, szVersion9x, verstr); break; case VER_PLATFORM_WIN32_NT: - msi_set_property(package->db, vNT, verstr); - sprintfW(verstr,szFormat,OSVersion.wProductType); + msi_set_property(package->db, szVersionNT, verstr); + sprintfW(verstr, szFormat,OSVersion.wProductType); msi_set_property(package->db, szMsiNTProductType, verstr); break; } - sprintfW(verstr,szFormat,OSVersion.dwBuildNumber); - msi_set_property(package->db, szWinBuild, verstr); + sprintfW(verstr, szFormat, OSVersion.dwBuildNumber); + msi_set_property(package->db, szWindowsBuild, verstr); /* just fudge this */ - msi_set_property(package->db, szSPL, szSix); + msi_set_property(package->db, szServicePackLevel, szSix); sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION); msi_set_property( package->db, szVersionMsi, bufstr ); sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100); msi_set_property( package->db, szVersionDatabase, bufstr ); - GetSystemInfo( &sys_info ); + GetNativeSystemInfo( &sys_info ); + sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel ); if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { - sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel ); msi_set_property( package->db, szIntel, bufstr ); + + GetSystemDirectoryW( pth, MAX_PATH ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szSystemFolder, pth ); + + SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szProgramFilesFolder, pth ); + + SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szCommonFilesFolder, pth ); + } + else if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + { + msi_set_property( package->db, szMsiAMD64, bufstr ); + msi_set_property( package->db, szMsix64, bufstr ); + msi_set_property( package->db, szVersionNT64, verstr ); + + GetSystemDirectoryW( pth, MAX_PATH ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szSystem64Folder, pth ); + + GetSystemWow64DirectoryW( pth, MAX_PATH ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szSystemFolder, pth ); + + SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szProgramFiles64Folder, pth ); + + SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, pth ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szProgramFilesFolder, pth ); + + SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szCommonFiles64Folder, pth ); + + SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMONX86, NULL, 0, pth ); + PathAddBackslashW( pth ); + msi_set_property( package->db, szCommonFilesFolder, pth ); } /* Screen properties. */ @@ -878,7 +904,7 @@ static VOID set_installer_properties(MSIPACKAGE *package) (username = msi_reg_get_val_str( hkey, szRegisteredUser ))) msi_set_property( package->db, szUSERNAME, username ); if (!companyname && - (companyname = msi_reg_get_val_str( hkey, szRegisteredOrg ))) + (companyname = msi_reg_get_val_str( hkey, szRegisteredOrganization ))) msi_set_property( package->db, szCOMPANYNAME, companyname ); CloseHandle( hkey ); } @@ -908,7 +934,7 @@ static VOID set_installer_properties(MSIPACKAGE *package) langid = GetUserDefaultLangID(); sprintfW(bufstr, szIntFormat, langid); - msi_set_property( package->db, szUserLangID, bufstr ); + msi_set_property( package->db, szUserLanguageID, bufstr ); langid = GetSystemDefaultLangID(); sprintfW(bufstr, szIntFormat, langid); @@ -1042,7 +1068,7 @@ static UINT msi_load_admin_properties(MSIPACKAGE *package) return r; } -void msi_adjust_allusers_property( MSIPACKAGE *package ) +void msi_adjust_privilege_properties( MSIPACKAGE *package ) { /* FIXME: this should depend on the user's privileges */ if (msi_get_property_int( package->db, szAllUsers, 0 ) == 2) @@ -1050,6 +1076,7 @@ void msi_adjust_allusers_property( MSIPACKAGE *package ) TRACE("resetting ALLUSERS property from 2 to 1\n"); msi_set_property( package->db, szAllUsers, szOne ); } + msi_set_property( package->db, szAdminUser, szOne ); } MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url ) @@ -1074,7 +1101,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url ) create_temp_property_table( package ); msi_clone_properties( package ); - msi_adjust_allusers_property( package ); + msi_adjust_privilege_properties( package ); package->ProductCode = msi_dup_property( package->db, szProductCode ); package->script = msi_alloc_zero( sizeof(MSISCRIPT) ); @@ -1119,7 +1146,10 @@ static UINT copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename ) if( !CopyFileW( szPackage, filename, FALSE ) ) { UINT error = GetLastError(); - ERR("failed to copy package %s to %s (%u)\n", debugstr_w(szPackage), debugstr_w(filename), error); + if ( error == ERROR_FILE_NOT_FOUND ) + ERR("can't find %s\n", debugstr_w(szPackage)); + else + ERR("failed to copy package %s to %s (%u)\n", debugstr_w(szPackage), debugstr_w(filename), error); DeleteFileW( filename ); return error; } @@ -1257,6 +1287,92 @@ static UINT apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code ) return r; } +static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package ) +{ + WCHAR *template, *p, *q; + DWORD i, count; + + package->version = msi_suminfo_get_int32( si, PID_PAGECOUNT ); + TRACE("version: %d\n", package->version); + + template = msi_suminfo_dup_string( si, PID_TEMPLATE ); + if (!template) + return ERROR_SUCCESS; /* native accepts missing template property */ + + TRACE("template: %s\n", debugstr_w(template)); + + p = strchrW( template, ';' ); + if (!p) + { + WARN("invalid template string %s\n", debugstr_w(template)); + msi_free( template ); + return ERROR_PATCH_PACKAGE_INVALID; + } + *p = 0; + if (!template[0] || !strcmpW( template, szIntel )) + package->platform = PLATFORM_INTEL; + else if (!strcmpW( template, szIntel64 )) + package->platform = PLATFORM_INTEL64; + else if (!strcmpW( template, szX64 )) + package->platform = PLATFORM_X64; + else + { + WARN("unknown platform %s\n", debugstr_w(template)); + msi_free( template ); + return ERROR_INSTALL_PLATFORM_UNSUPPORTED; + } + + count = 1; + for (q = ++p; (q = strchrW( q, ',' )); q++) count++; + + package->langids = msi_alloc( count * sizeof(LANGID) ); + if (!package->langids) + { + msi_free( template ); + return ERROR_OUTOFMEMORY; + } + + i = 0; + while (*p) + { + q = strchrW( p, ',' ); + if (q) *q = 0; + package->langids[i] = atoiW( p ); + if (!q) break; + p = q + 1; + i++; + } + package->num_langids = i + 1; + + msi_free( template ); + return ERROR_SUCCESS; +} + +static UINT validate_package( MSIPACKAGE *package ) +{ + BOOL is_wow64; + UINT i; + + IsWow64Process( GetCurrentProcess(), &is_wow64 ); + if (package->platform == PLATFORM_X64) + { + if (!is_64bit && !is_wow64) + return ERROR_INSTALL_PLATFORM_UNSUPPORTED; + if (package->version < 200) + return ERROR_INSTALL_PACKAGE_INVALID; + } + if (!package->num_langids) + { + return ERROR_SUCCESS; + } + for (i = 0; i < package->num_langids; i++) + { + if (!package->langids[i] || IsValidLocale( package->langids[i], LCID_INSTALLED )) + return ERROR_SUCCESS; + } + return ERROR_INSTALL_LANGUAGE_UNSUPPORTED; +} + UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) { static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0}; @@ -1269,6 +1385,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) WCHAR temppath[MAX_PATH], localfile[MAX_PATH], cachefile[MAX_PATH]; LPCWSTR file = szPackage; DWORD index = 0; + MSISUMMARYINFO *si; TRACE("%s %p\n", debugstr_w(szPackage), pPackage); @@ -1339,7 +1456,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) * read/write, which is safe because we always create a copy that is thrown * away when we're done. */ - r = MSI_OpenDatabaseW( file, MSIDBOPEN_DIRECT, &db ); + r = MSI_OpenDatabaseW( file, MSIDBOPEN_TRANSACT, &db ); if( r != ERROR_SUCCESS ) { if (file != szPackage) @@ -1368,6 +1485,29 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) if( file != szPackage ) track_tempfile( package, file ); + si = MSI_GetSummaryInformationW( db->storage, 0 ); + if (!si) + { + WARN("failed to load summary info %u\n", r); + msiobj_release( &package->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; + } + + r = msi_parse_summary( si, package ); + msiobj_release( &si->hdr ); + if (r != ERROR_SUCCESS) + { + WARN("failed to parse summary info %u\n", r); + msiobj_release( &package->hdr ); + return r; + } + + r = validate_package( package ); + if (r != ERROR_SUCCESS) + { + msiobj_release( &package->hdr ); + return r; + } msi_set_property( package->db, Database, db->path ); if( UrlIsW( szPackage, URLIS_URL ) ) @@ -1398,7 +1538,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) if (r != ERROR_SUCCESS) { ERR("registered patch failed to apply %u\n", r); - MSI_FreePackage( (MSIOBJECTHDR *)package ); + msiobj_release( &package->hdr ); return r; } @@ -1408,7 +1548,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) if (index) { msi_clone_properties( package ); - msi_adjust_allusers_property( package ); + msi_adjust_privilege_properties( package ); } *pPackage = package; diff --git a/dll/win32/msi/record.c b/dll/win32/msi/record.c index 45adbac8471..7bc82814b2e 100644 --- a/dll/win32/msi/record.c +++ b/dll/win32/msi/record.c @@ -45,6 +45,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb); #define MSIFIELD_INT 1 #define MSIFIELD_WSTR 3 #define MSIFIELD_STREAM 4 +#define MSIFIELD_INTPTR 5 static void MSI_FreeField( MSIFIELD *field ) { @@ -52,6 +53,7 @@ static void MSI_FreeField( MSIFIELD *field ) { case MSIFIELD_NULL: case MSIFIELD_INT: + case MSIFIELD_INTPTR: break; case MSIFIELD_WSTR: msi_free( field->u.szwVal); @@ -177,6 +179,9 @@ UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n, case MSIFIELD_INT: out->u.iVal = in->u.iVal; break; + case MSIFIELD_INTPTR: + out->u.pVal = in->u.pVal; + break; case MSIFIELD_WSTR: str = strdupW( in->u.szwVal ); if ( !str ) @@ -200,6 +205,32 @@ UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n, return r; } +INT_PTR MSI_RecordGetIntPtr( MSIRECORD *rec, UINT iField ) +{ + int ret; + + TRACE( "%p %d\n", rec, iField ); + + if( iField > rec->count ) + return MININT_PTR; + + switch( rec->fields[iField].type ) + { + case MSIFIELD_INT: + return rec->fields[iField].u.iVal; + case MSIFIELD_INTPTR: + return rec->fields[iField].u.pVal; + case MSIFIELD_WSTR: + if( string2intW( rec->fields[iField].u.szwVal, &ret ) ) + return ret; + return MININT_PTR; + default: + break; + } + + return MININT_PTR; +} + int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField) { int ret = 0; @@ -213,6 +244,8 @@ int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField) { case MSIFIELD_INT: return rec->fields[iField].u.iVal; + case MSIFIELD_INTPTR: + return rec->fields[iField].u.pVal; case MSIFIELD_WSTR: if( string2intW( rec->fields[iField].u.szwVal, &ret ) ) return ret; @@ -267,6 +300,20 @@ UINT WINAPI MsiRecordClearData( MSIHANDLE handle ) return ERROR_SUCCESS; } +UINT MSI_RecordSetIntPtr( MSIRECORD *rec, UINT iField, INT_PTR pVal ) +{ + TRACE("%p %u %ld\n", rec, iField, pVal); + + if( iField > rec->count ) + return ERROR_INVALID_PARAMETER; + + MSI_FreeField( &rec->fields[iField] ); + rec->fields[iField].type = MSIFIELD_INTPTR; + rec->fields[iField].u.pVal = pVal; + + return ERROR_SUCCESS; +} + UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal ) { TRACE("%p %u %d\n", rec, iField, iVal); diff --git a/dll/win32/msi/registry.c b/dll/win32/msi/registry.c index 2a84e11be61..e83490f5e36 100644 --- a/dll/win32/msi/registry.c +++ b/dll/win32/msi/registry.c @@ -40,7 +40,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); - /* * This module will be all the helper functions for registry access by the * installer bits. @@ -103,6 +102,15 @@ static const WCHAR szUninstall_fmt[] = { 'U','n','i','n','s','t','a','l','l','\\', '%','s',0 }; +static const WCHAR szUninstall_32node_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'W','o','w','6','4','3','2','N','o','d','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','\\', +'U','n','i','n','s','t','a','l','l','\\', +'%','s',0 }; + static const WCHAR szUserProduct[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', @@ -509,28 +517,36 @@ static UINT get_user_sid(LPWSTR *usersid) return ERROR_SUCCESS; } -UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create) +UINT MSIREG_OpenUninstallKey(MSIPACKAGE *package, HKEY *key, BOOL create) { UINT rc; WCHAR keypath[0x200]; - TRACE("%s\n",debugstr_w(szProduct)); - sprintfW(keypath,szUninstall_fmt,szProduct); + TRACE("%s\n", debugstr_w(package->ProductCode)); + + if (is_64bit && package->platform == PLATFORM_INTEL) + sprintfW(keypath, szUninstall_32node_fmt, package->ProductCode); + else + sprintfW(keypath, szUninstall_fmt, package->ProductCode); if (create) - rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key); + rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, KEY_ALL_ACCESS, NULL, key, NULL); else - rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key); + rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, KEY_ALL_ACCESS, key); return rc; } -UINT MSIREG_DeleteUninstallKey(LPCWSTR szProduct) +UINT MSIREG_DeleteUninstallKey(MSIPACKAGE *package) { WCHAR keypath[0x200]; - TRACE("%s\n",debugstr_w(szProduct)); - sprintfW(keypath,szUninstall_fmt,szProduct); + TRACE("%s\n", debugstr_w(package->ProductCode)); + + if (is_64bit && package->platform == PLATFORM_INTEL) + sprintfW(keypath, szUninstall_32node_fmt, package->ProductCode); + else + sprintfW(keypath, szUninstall_fmt, package->ProductCode); return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath); } diff --git a/dll/win32/msi/storages.c b/dll/win32/msi/storages.c index 3e8887437a7..56f252fa37f 100644 --- a/dll/win32/msi/storages.c +++ b/dll/win32/msi/storages.c @@ -334,10 +334,12 @@ static UINT STORAGES_get_column_info(struct tagMSIVIEW *view, UINT n, static UINT storages_find_row(MSISTORAGESVIEW *sv, MSIRECORD *rec, UINT *row) { LPCWSTR str; - UINT i, id, data; + UINT r, i, id, data; str = MSI_RecordGetString(rec, 1); - msi_string2idW(sv->db->strings, str, &id); + r = msi_string2idW(sv->db->strings, str, &id); + if (r != ERROR_SUCCESS) + return r; for (i = 0; i < sv->num_rows; i++) { diff --git a/dll/win32/msi/string.c b/dll/win32/msi/string.c index 21b1db2a405..5644749392f 100644 --- a/dll/win32/msi/string.c +++ b/dll/win32/msi/string.c @@ -3,6 +3,7 @@ * * Copyright 2002-2004, Mike McCormack for CodeWeavers * Copyright 2007 Robert Shearman for CodeWeavers + * Copyright 2010 Hans Leidekker for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -40,8 +41,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb); -#define LONG_STR_BYTES 3 - typedef struct _msistring { USHORT persistent_refcount; @@ -564,7 +563,7 @@ end: return st; } -UINT msi_save_string_table( const string_table *st, IStorage *storage ) +UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *bytes_per_strref ) { UINT i, datasize = 0, poolsize = 0, sz, used, r, codepage, n; UINT ret = ERROR_FUNCTION_FAILED; @@ -593,8 +592,16 @@ UINT msi_save_string_table( const string_table *st, IStorage *storage ) used = 0; codepage = st->codepage; - pool[0]=codepage&0xffff; - pool[1]=(codepage>>16); + pool[0] = codepage & 0xffff; + pool[1] = codepage >> 16; + if (st->maxcount > 0xffff) + { + pool[1] |= 0x8000; + *bytes_per_strref = LONG_STR_BYTES; + } + else + *bytes_per_strref = sizeof(USHORT); + n = 1; for( i=1; imaxcount; i++ ) { diff --git a/dll/win32/msi/suminfo.c b/dll/win32/msi/suminfo.c index 902a61f6544..2a9cd713001 100644 --- a/dll/win32/msi/suminfo.c +++ b/dll/win32/msi/suminfo.c @@ -469,7 +469,7 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, if( !pHandle ) return ERROR_INVALID_PARAMETER; - if( szDatabase ) + if( szDatabase && szDatabase[0] ) { LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY; @@ -644,6 +644,18 @@ LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) return strdupAtoW( prop->u.pszVal ); } +INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) +{ + PROPVARIANT *prop; + + if ( uiProperty >= MSI_MAX_PROPS ) + return -1; + prop = &si->property[uiProperty]; + if( prop->vt != VT_I4 ) + return -1; + return prop->u.lVal; +} + LPWSTR msi_get_suminfo_product( IStorage *stg ) { MSISUMMARYINFO *si; diff --git a/dll/win32/msi/table.c b/dll/win32/msi/table.c index 72d1f2103a5..3e456ed56c4 100644 --- a/dll/win32/msi/table.c +++ b/dll/win32/msi/table.c @@ -42,7 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb); #define MSITABLE_HASH_TABLE_SIZE 37 -#define LONG_STR_BYTES 3 typedef struct tagMSICOLUMNHASHENTRY { @@ -117,13 +116,13 @@ static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz); static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count ); -static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col ) +static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col, UINT bytes_per_strref ) { if( MSITYPE_IS_BINARY(col->type) ) return 2; if( col->type & MSITYPE_STRING ) - return db->bytes_per_strref; + return bytes_per_strref; if( (col->type & 0xff) <= 2) return 2; @@ -399,24 +398,33 @@ static void free_table( MSITABLE *table ) msi_free( table ); } -static UINT msi_table_get_row_size( MSIDATABASE *db,const MSICOLUMNINFO *cols, - UINT count ) +static UINT msi_table_get_row_size( MSIDATABASE *db, const MSICOLUMNINFO *cols, UINT count, UINT bytes_per_strref ) { - const MSICOLUMNINFO *last_col = &cols[count-1]; + const MSICOLUMNINFO *last_col; + if (!count) return 0; - return last_col->offset + bytes_per_column( db, last_col ); + + if (bytes_per_strref != LONG_STR_BYTES) + { + UINT i, size = 0; + for (i = 0; i < count; i++) size += bytes_per_column( db, &cols[i], bytes_per_strref ); + return size; + } + last_col = &cols[count - 1]; + return last_col->offset + bytes_per_column( db, last_col, bytes_per_strref ); } /* add this table to the list of cached tables in the database */ static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg ) { BYTE *rawdata = NULL; - UINT rawsize = 0, i, j, row_size = 0; + UINT rawsize = 0, i, j, row_size, row_size_mem; TRACE("%s\n",debugstr_w(t->name)); - row_size = msi_table_get_row_size( db, t->colinfo, t->col_count ); + row_size = msi_table_get_row_size( db, t->colinfo, t->col_count, db->bytes_per_strref ); + row_size_mem = msi_table_get_row_size( db, t->colinfo, t->col_count, LONG_STR_BYTES ); /* if we can't read the table, just assume that it's empty */ read_stream_data( stg, t->name, TRUE, &rawdata, &rawsize ); @@ -441,17 +449,19 @@ static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg /* transpose all the data */ TRACE("Transposing data from %d rows\n", t->row_count ); - for( i=0; irow_count; i++ ) + for (i = 0; i < t->row_count; i++) { - t->data[i] = msi_alloc( row_size ); + UINT ofs = 0, ofs_mem = 0; + + t->data[i] = msi_alloc( row_size_mem ); if( !t->data[i] ) goto err; t->data_persistent[i] = TRUE; - for( j=0; jcol_count; j++ ) + for (j = 0; j < t->col_count; j++) { - UINT ofs = t->colinfo[j].offset; - UINT n = bytes_per_column( db, &t->colinfo[j] ); + UINT m = bytes_per_column( db, &t->colinfo[j], LONG_STR_BYTES ); + UINT n = bytes_per_column( db, &t->colinfo[j], db->bytes_per_strref ); UINT k; if ( n != 2 && n != 3 && n != 4 ) @@ -459,9 +469,23 @@ static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg ERR("oops - unknown column width %d\n", n); goto err; } - - for ( k = 0; k < n; k++ ) - t->data[i][ofs + k] = rawdata[ofs*t->row_count + i * n + k]; + if (t->colinfo[j].type & MSITYPE_STRING && n < m) + { + for (k = 0; k < m; k++) + { + if (k < n) + t->data[i][ofs_mem + k] = rawdata[ofs * t->row_count + i * n + k]; + else + t->data[i][ofs_mem + k] = 0; + } + } + else + { + for (k = 0; k < n; k++) + t->data[i][ofs_mem + k] = rawdata[ofs * t->row_count + i * n + k]; + } + ofs_mem += m; + ofs += n; } } @@ -729,10 +753,20 @@ static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret ) return ERROR_SUCCESS; } -static UINT save_table( MSIDATABASE *db, const MSITABLE *t ) +static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes) +{ + UINT ret = 0, i; + + for (i = 0; i < bytes; i++) + ret += data[row][col + i] << i * 8; + + return ret; +} + +static UINT save_table( MSIDATABASE *db, const MSITABLE *t, UINT bytes_per_strref ) { - BYTE *rawdata = NULL, *p; - UINT rawsize, r, i, j, row_size; + BYTE *rawdata = NULL; + UINT rawsize, r, i, j, row_size, row_count; /* Nothing to do for non-persistent tables */ if( t->persistent == MSICONDITION_FALSE ) @@ -740,9 +774,17 @@ static UINT save_table( MSIDATABASE *db, const MSITABLE *t ) TRACE("Saving %s\n", debugstr_w( t->name ) ); - row_size = msi_table_get_row_size( db, t->colinfo, t->col_count ); - - rawsize = t->row_count * row_size; + row_size = msi_table_get_row_size( db, t->colinfo, t->col_count, bytes_per_strref ); + row_count = t->row_count; + for (i = 0; i < t->row_count; i++) + { + if (!t->data_persistent[i]) + { + row_count = 1; /* yes, this is bizarre */ + break; + } + } + rawsize = row_count * row_size; rawdata = msi_alloc_zero( rawsize ); if( !rawdata ) { @@ -751,25 +793,41 @@ static UINT save_table( MSIDATABASE *db, const MSITABLE *t ) } rawsize = 0; - p = rawdata; - for( i=0; icol_count; i++ ) + for (i = 0; i < t->row_count; i++) { - for( j=0; jrow_count; j++ ) - { - UINT offset = t->colinfo[i].offset; + UINT ofs = 0, ofs_mem = 0; + + if (!t->data_persistent[i]) break; - if (!t->data_persistent[j]) continue; - if (i == 0) - rawsize += row_size; + for (j = 0; j < t->col_count; j++) + { + UINT m = bytes_per_column( db, &t->colinfo[j], LONG_STR_BYTES ); + UINT n = bytes_per_column( db, &t->colinfo[j], bytes_per_strref ); + UINT k; - *p++ = t->data[j][offset]; - *p++ = t->data[j][offset + 1]; - if( 4 == bytes_per_column( db, &t->colinfo[i] ) ) + if (n != 2 && n != 3 && n != 4) + { + ERR("oops - unknown column width %d\n", n); + goto err; + } + if (t->colinfo[j].type & MSITYPE_STRING && n < m) + { + UINT id = read_table_int( t->data, i, ofs_mem, LONG_STR_BYTES ); + if (id > 1 << bytes_per_strref * 8) + { + ERR("string id %u out of range\n", id); + r = ERROR_FUNCTION_FAILED; + goto err; + } + } + for (k = 0; k < n; k++) { - *p++ = t->data[j][offset + 2]; - *p++ = t->data[j][offset + 3]; + rawdata[ofs * row_count + i * n + k] = t->data[i][ofs_mem + k]; } + ofs_mem += m; + ofs += n; } + rawsize += row_size; } TRACE("writing %d bytes\n", rawsize); @@ -777,12 +835,10 @@ static UINT save_table( MSIDATABASE *db, const MSITABLE *t ) err: msi_free( rawdata ); - return r; } -static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo, - DWORD count ) +static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo, DWORD count ) { DWORD i; @@ -791,7 +847,7 @@ static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo, assert( (i+1) == colinfo[ i ].number ); if (i) colinfo[i].offset = colinfo[ i - 1 ].offset - + bytes_per_column( db, &colinfo[ i - 1 ] ); + + bytes_per_column( db, &colinfo[ i - 1 ], LONG_STR_BYTES ); else colinfo[i].offset = 0; TRACE("column %d is [%s] with type %08x ofs %d\n", @@ -855,16 +911,6 @@ static LPWSTR msi_makestring( const MSIDATABASE *db, UINT stringid) return strdupW(msi_string_lookup_id( db->strings, stringid )); } -static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes) -{ - UINT ret = 0, i; - - for (i = 0; i < bytes; i++) - ret += (data[row][col + i] << i * 8); - - return ret; -} - static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz) { @@ -902,11 +948,11 @@ static UINT get_tablecolumns( MSIDATABASE *db, count = table->row_count; for( i=0; idata, i, 0, db->bytes_per_strref) != table_id ) + if( read_table_int(table->data, i, 0, LONG_STR_BYTES) != table_id ) continue; if( colinfo ) { - UINT id = read_table_int(table->data, i, table->colinfo[2].offset, db->bytes_per_strref); + UINT id = read_table_int(table->data, i, table->colinfo[2].offset, LONG_STR_BYTES); UINT col = read_table_int(table->data, i, table->colinfo[1].offset, sizeof(USHORT)) - (1<<15); /* check the column number is in range */ @@ -971,7 +1017,7 @@ static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name ) if (!table->col_count) goto done; - size = msi_table_get_row_size( db, table->colinfo, table->col_count ); + size = msi_table_get_row_size( db, table->colinfo, table->col_count, LONG_STR_BYTES ); offset = table->colinfo[table->col_count - 1].offset; for ( n = 0; n < table->row_count; n++ ) @@ -988,8 +1034,8 @@ done: /* try to find the table name in the _Tables table */ BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name ) { - UINT r, table_id = 0, i, count; - MSITABLE *table = NULL; + UINT r, table_id, i; + MSITABLE *table; static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0}; static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0}; @@ -1012,10 +1058,11 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name ) return FALSE; } - count = table->row_count; - for( i=0; idata[ i ][ 0 ] == table_id ) + for( i = 0; i < table->row_count; i++ ) + { + if( read_table_int( table->data, i, 0, LONG_STR_BYTES ) == table_id ) return TRUE; + } return FALSE; } @@ -1059,7 +1106,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT * if (tv->order) row = tv->order->reorder[row]; - n = bytes_per_column( tv->db, &tv->columns[col-1] ); + n = bytes_per_column( tv->db, &tv->columns[col - 1], LONG_STR_BYTES ); if (n != 2 && n != 3 && n != 4) { ERR("oops! what is %d bytes per column?\n", n ); @@ -1116,7 +1163,7 @@ static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname ) { static const WCHAR fmt[] = { '%','d',0 }; WCHAR number[0x20]; - UINT n = bytes_per_column( tv->db, &tv->columns[i] ); + UINT n = bytes_per_column( tv->db, &tv->columns[i], LONG_STR_BYTES ); switch( n ) { @@ -1213,7 +1260,7 @@ static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val ) msi_free( tv->columns[col-1].hash_table ); tv->columns[col-1].hash_table = NULL; - n = bytes_per_column( tv->db, &tv->columns[col-1] ); + n = bytes_per_column( tv->db, &tv->columns[col - 1], LONG_STR_BYTES ); if ( n != 2 && n != 3 && n != 4 ) { ERR("oops! what is %d bytes per column?\n", n ); @@ -1304,7 +1351,7 @@ static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT if (r != ERROR_SUCCESS) return ERROR_NOT_FOUND; } - else if ( 2 == bytes_per_column( tv->db, &columninfo ) ) + else if ( bytes_per_column( tv->db, &columninfo, LONG_STR_BYTES ) == 2 ) { *pvalue = 0x8000 + MSI_RecordGetInteger( rec, iField ); if ( *pvalue & 0xffff0000 ) @@ -1577,39 +1624,60 @@ static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec ) return ERROR_SUCCESS; } -static UINT find_insert_index( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *pidx ) +static int compare_record( MSITABLEVIEW *tv, UINT row, MSIRECORD *rec ) { - UINT r, idx, j, ivalue, x; - - TRACE("%p %p %p\n", tv, rec, pidx); + UINT r, i, ivalue, x; - for (idx = 0; idx < tv->table->row_count; idx++) + for (i = 0; i < tv->num_cols; i++ ) { - for (j = 0; j < tv->num_cols; j++ ) + r = get_table_value_from_record( tv, rec, i + 1, &ivalue ); + if (r != ERROR_SUCCESS) + return 1; + + r = TABLE_fetch_int( &tv->view, row, i + 1, &x ); + if (r != ERROR_SUCCESS) { - r = get_table_value_from_record (tv, rec, j+1, &ivalue); - if (r != ERROR_SUCCESS) - break; + WARN("TABLE_fetch_int should not fail here %u\n", r); + return -1; + } + if (ivalue > x) + { + return 1; + } + else if (ivalue == x) + { + if (i < tv->num_cols - 1) continue; + return 0; + } + else + return -1; + } + return 1; +} - r = TABLE_fetch_int(&tv->view, idx, j + 1, &x); - if (r != ERROR_SUCCESS) - return r; +static int find_insert_index( MSITABLEVIEW *tv, MSIRECORD *rec ) +{ + int idx, c, low = 0, high = tv->table->row_count - 1; - if (ivalue > x) - break; - else if (ivalue == x) - continue; - else { - TRACE("Found %d.\n", idx); - *pidx = idx; - return ERROR_SUCCESS; - } + TRACE("%p %p\n", tv, rec); + + while (low <= high) + { + idx = (low + high) / 2; + c = compare_record( tv, idx, rec ); + + if (c < 0) + high = idx - 1; + else if (c > 0) + low = idx + 1; + else + { + TRACE("found %u\n", idx); + return idx; } } - - TRACE("Found %d.\n", idx); - *pidx = idx; - return ERROR_SUCCESS; + TRACE("found %u\n", high + 1); + return high + 1; } static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary ) @@ -1625,11 +1693,7 @@ static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, return ERROR_FUNCTION_FAILED; if (row == -1) - { - r = find_insert_index(tv, rec, &row); - if( r != ERROR_SUCCESS ) - return ERROR_FUNCTION_FAILED; - } + row = find_insert_index( tv, rec ); r = table_create_new_row( view, &row, temporary ); TRACE("insert_row returned %08x\n", r); @@ -2306,7 +2370,7 @@ UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) tv->db = db; tv->columns = tv->table->colinfo; tv->num_cols = tv->table->col_count; - tv->row_size = msi_table_get_row_size( db, tv->table->colinfo, tv->table->col_count ); + tv->row_size = msi_table_get_row_size( db, tv->table->colinfo, tv->table->col_count, LONG_STR_BYTES ); TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size ); @@ -2318,12 +2382,13 @@ UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) UINT MSI_CommitTables( MSIDATABASE *db ) { - UINT r; + UINT r, bytes_per_strref; + HRESULT hr; MSITABLE *table = NULL; TRACE("%p\n",db); - r = msi_save_string_table( db->strings, db->storage ); + r = msi_save_string_table( db->strings, db->storage, &bytes_per_strref ); if( r != ERROR_SUCCESS ) { WARN("failed to save string table r=%08x\n",r); @@ -2332,7 +2397,7 @@ UINT MSI_CommitTables( MSIDATABASE *db ) LIST_FOR_EACH_ENTRY( table, &db->tables, MSITABLE, entry ) { - r = save_table( db, table ); + r = save_table( db, table, bytes_per_strref ); if( r != ERROR_SUCCESS ) { WARN("failed to save table %s (r=%08x)\n", @@ -2344,7 +2409,13 @@ UINT MSI_CommitTables( MSIDATABASE *db ) /* force everything to reload next time */ free_cached_tables( db ); - return ERROR_SUCCESS; + hr = IStorage_Commit( db->storage, 0 ); + if (FAILED( hr )) + { + WARN("failed to commit changes 0x%08x\n", hr); + r = ERROR_FUNCTION_FAILED; + } + return r; } MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table ) @@ -2463,7 +2534,7 @@ static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string IStream *stm = NULL; UINT r; - ofs += bytes_per_column( tv->db, &columns[i] ); + ofs += bytes_per_column( tv->db, &columns[i], bytes_per_strref ); r = msi_record_encoded_stream_name( tv, rec, &encname ); if ( r != ERROR_SUCCESS ) @@ -2490,7 +2561,7 @@ static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string } else { - UINT n = bytes_per_column( tv->db, &columns[i] ); + UINT n = bytes_per_column( tv->db, &columns[i], bytes_per_strref ); switch( n ) { case 2: @@ -2704,7 +2775,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, ! MSITYPE_IS_BINARY(tv->columns[i].type) ) sz += bytes_per_strref; else - sz += bytes_per_column( tv->db, &tv->columns[i] ); + sz += bytes_per_column( tv->db, &tv->columns[i], bytes_per_strref ); } } else @@ -2726,7 +2797,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, ! MSITYPE_IS_BINARY(tv->columns[i].type) ) sz += bytes_per_strref; else - sz += bytes_per_column( tv->db, &tv->columns[i] ); + sz += bytes_per_column( tv->db, &tv->columns[i], bytes_per_strref ); } } } diff --git a/dll/win32/msi/version.rc b/dll/win32/msi/version.rc index 4fe3d9173e9..ab027f409a2 100644 --- a/dll/win32/msi/version.rc +++ b/dll/win32/msi/version.rc @@ -18,9 +18,9 @@ #define WINE_FILEDESCRIPTION_STR "Wine MSI dll" #define WINE_FILENAME_STR "msi.dll" -#define WINE_FILEVERSION 3,1,4000,2435 -#define WINE_FILEVERSION_STR "3.1.4000.2435" -#define WINE_PRODUCTVERSION 3,1,4000,2435 -#define WINE_PRODUCTVERSION_STR "3.1.4000.2435" +#define WINE_FILEVERSION 4,5,6001,22159 +#define WINE_FILEVERSION_STR "4.5.6001.22159" +#define WINE_PRODUCTVERSION 4,5,6001,22159 +#define WINE_PRODUCTVERSION_STR "4.5.6001.22159" #include "wine/wine_common_ver.rc" -- 2.17.1