[MSI]
authorAleksey Bragin <aleksey@reactos.org>
Fri, 22 Oct 2010 13:18:11 +0000 (13:18 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Fri, 22 Oct 2010 13:18:11 +0000 (13:18 +0000)
- Sync to Wine-1.3.5.

svn path=/trunk/; revision=49219

23 files changed:
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/appsearch.c
reactos/dll/win32/msi/classes.c
reactos/dll/win32/msi/cond.tab.c
reactos/dll/win32/msi/cond.y
reactos/dll/win32/msi/custom.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/join.c
reactos/dll/win32/msi/media.c
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msi.spec
reactos/dll/win32/msi/msi_Fi.rc
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/msiquery.c
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/record.c
reactos/dll/win32/msi/registry.c
reactos/dll/win32/msi/storages.c
reactos/dll/win32/msi/string.c
reactos/dll/win32/msi/suminfo.c
reactos/dll/win32/msi/table.c
reactos/dll/win32/msi/version.rc
reactos/include/psdk/msi.h

index bb559c0..34c0ce4 100644 (file)
@@ -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;
@@ -2371,17 +2371,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 +2458,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 +2580,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 +2636,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 +2657,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 +2710,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 +3921,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 +4789,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 +4869,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 +7528,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))
index a516bda..dfab396 100644 (file)
@@ -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)
     {
index 30ee36b..beaf1f0 100644 (file)
@@ -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 );
index 2b10d20..e68723d 100644 (file)
@@ -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;
index 9a7a16d..03ea493 100644 (file)
@@ -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;
index 5a1787f..b56139f 100644 (file)
@@ -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);
index 01c3249..3007d48 100644 (file)
@@ -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 )
     {
index f787c30..7fe7f1c 100644 (file)
@@ -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++)
     {
index a2a9065..788528e 100644 (file)
@@ -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 );
 
index fb7eba5..7d1b9a5 100644 (file)
@@ -3779,3 +3779,44 @@ UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent,
     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
     return ERROR_SUCCESS;
 }
+
+/***********************************************************************
+ * 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;
+}
index 6fdebd8..fd047f8 100644 (file)
 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
index 7769a8a..8984172 100644 (file)
@@ -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"
 }
index 344b145..0361ff4 100644 (file)
@@ -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);
index df81a74..cf69593 100644 (file)
@@ -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;
index d332168..32576a0 100644 (file)
@@ -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;
index 45adbac..7bc8281 100644 (file)
@@ -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);
index 2a84e11..e83490f 100644 (file)
@@ -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);
 }
index 3e88874..56f252f 100644 (file)
@@ -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++)
     {
index 21b1db2..5644749 100644 (file)
@@ -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; i<st->maxcount; i++ )
     {
index 902a61f..2a9cd71 100644 (file)
@@ -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;
index 72d1f21..3e456ed 100644 (file)
@@ -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; 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 )
@@ -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; 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);
@@ -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; 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 */
@@ -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; 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;
 }
@@ -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 );
                 }
             }
         }
index 4fe3d91..ab027f4 100644 (file)
@@ -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"
index b331057..550ce95 100644 (file)
 #ifndef __WINE_MSI_H
 #define __WINE_MSI_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #ifndef _MSI_NO_CRYPTO
 #include <wincrypt.h>
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef ULONG MSIHANDLE;
 
 typedef enum tagINSTALLSTATE
@@ -663,6 +663,12 @@ UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR, LPCSTR, LPCSTR);
 UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR, LPCWSTR, LPCWSTR);
 #define     MsiApplyMultiplePatches WINELIB_NAME_AW(MsiApplyMultiplePatches)
 
+UINT WINAPI MsiBeginTransactionA(LPCSTR, DWORD, MSIHANDLE *, HANDLE *);
+UINT WINAPI MsiBeginTransactionW(LPCWSTR, DWORD, MSIHANDLE *, HANDLE *);
+#define     MsiBeginTransaction WINELIB_NAME_AW(MsiBeginTransaction)
+
+UINT WINAPI MsiEndTransaction(DWORD);
+
 /* Non Unicode */
 UINT WINAPI MsiCloseHandle(MSIHANDLE);
 UINT WINAPI MsiCloseAllHandles(void);