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);
{
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);
}
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;
{
component = cl->component;
- switch (feature->Action)
+ switch (feature->ActionRequest)
{
case INSTALLSTATE_ABSENT:
component->anyAbsent = 1;
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;
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;
}
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;
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)
{
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;
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 );
{
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;
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 );
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;
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;
MSIREG_DeleteProductKey(package->ProductCode);
MSIREG_DeleteUserDataProductKey(package->ProductCode);
- MSIREG_DeleteUninstallKey(package->ProductCode);
+ MSIREG_DeleteUninstallKey(package);
if (package->Context == MSIINSTALLCONTEXT_MACHINE)
{
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))
'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;
/* 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)
{
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 )
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 )
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 );
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;
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;
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);
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);
}
{
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);
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)
{
}
}
+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;
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 )
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 )
{
UINT cols = 0;
UINT prev_rows = 1;
- TRACE("%d, %d\n", row, col);
-
if (col == 0 || col > jv->columns)
return ERROR_FUNCTION_FAILED;
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++)
{
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)
{
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)
{
{
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 );
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;
+}
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
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)
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
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"
}
#include "fdi.h"
#include "msi.h"
#include "msiquery.h"
+#include "msidefs.h"
#include "objbase.h"
#include "objidl.h"
#include "winnls.h"
#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
#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
union
{
INT iVal;
+ INT_PTR pVal;
LPWSTR szwVal;
IStream *stream;
} u;
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;
typedef struct tagMSICOMPONENT
{
struct list entry;
- DWORD magic;
LPWSTR Component;
LPWSTR ComponentId;
LPWSTR Directory;
#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
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 );
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 );
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 */
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,
/* 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 );
feature->ActionRequest = state;
feature->Action = state;
}
+ if (feature->Attributes & msidbFeatureAttributesUIDisallowAbsent)
+ {
+ feature->Action = INSTALLSTATE_UNKNOWN;
+ }
}
static inline void msi_component_set_state(MSIPACKAGE *package,
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);
if (r == ERROR_SUCCESS)
{
query->row ++;
- MSI_RecordSetInteger(*prec, 0, (int)query);
+ MSI_RecordSetIntPtr(*prec, 0, (INT_PTR)query);
}
return r;
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 );
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;
msi_free( package->ProductCode );
msi_free( package->ActionFormat );
msi_free( package->LastAction );
+ msi_free( package->langids );
/* cleanup control event subscriptions */
ControlEvent_CleanupSubscriptions( 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 );
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','\\',
'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:
* 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. */
(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 );
}
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);
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)
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 )
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) );
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;
}
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};
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);
* 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)
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 ) )
if (r != ERROR_SUCCESS)
{
ERR("registered patch failed to apply %u\n", r);
- MSI_FreePackage( (MSIOBJECTHDR *)package );
+ msiobj_release( &package->hdr );
return r;
}
if (index)
{
msi_clone_properties( package );
- msi_adjust_allusers_property( package );
+ msi_adjust_privilege_properties( package );
}
*pPackage = package;
#define MSIFIELD_INT 1
#define MSIFIELD_WSTR 3
#define MSIFIELD_STREAM 4
+#define MSIFIELD_INTPTR 5
static void MSI_FreeField( MSIFIELD *field )
{
{
case MSIFIELD_NULL:
case MSIFIELD_INT:
+ case MSIFIELD_INTPTR:
break;
case MSIFIELD_WSTR:
msi_free( field->u.szwVal);
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 )
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;
{
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 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);
WINE_DEFAULT_DEBUG_CHANNEL(msi);
-
/*
* This module will be all the helper functions for registry access by the
* installer bits.
'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','\\',
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);
}
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++)
{
*
* 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
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
-#define LONG_STR_BYTES 3
-
typedef struct _msistring
{
USHORT persistent_refcount;
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;
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; i<st->maxcount; i++ )
{
if( !pHandle )
return ERROR_INVALID_PARAMETER;
- if( szDatabase )
+ if( szDatabase && szDatabase[0] )
{
LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY;
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;
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
#define MSITABLE_HASH_TABLE_SIZE 37
-#define LONG_STR_BYTES 3
typedef struct tagMSICOLUMNHASHENTRY
{
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;
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 );
/* transpose all the data */
TRACE("Transposing data from %d rows\n", t->row_count );
- for( i=0; i<t->row_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; j<t->col_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 )
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;
}
}
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 )
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 )
{
}
rawsize = 0;
- p = rawdata;
- for( i=0; i<t->col_count; i++ )
+ for (i = 0; i < t->row_count; i++)
{
- for( j=0; j<t->row_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);
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;
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",
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)
{
count = table->row_count;
for( i=0; i<count; i++ )
{
- if( read_table_int(table->data, 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 */
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++ )
/* 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};
return FALSE;
}
- count = table->row_count;
- for( i=0; i<count; i++ )
- if( table->data[ 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;
}
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 );
{
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 )
{
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 );
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 )
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 )
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);
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 );
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);
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",
/* 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 )
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 )
}
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:
! 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
! 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 );
}
}
}
#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"