[MSI] Sync with Wine Staging 1.7.55. CORE-10536
authorAmine Khaldi <amine.khaldi@reactos.org>
Sat, 21 Nov 2015 16:44:38 +0000 (16:44 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sat, 21 Nov 2015 16:44:38 +0000 (16:44 +0000)
svn path=/trunk/; revision=69995

16 files changed:
reactos/dll/win32/msi/CMakeLists.txt
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/automation.c
reactos/dll/win32/msi/classes.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/dialog.c
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msi.spec
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/msiquery.c
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/registry.c
reactos/dll/win32/msi/streams.c
reactos/dll/win32/msi/suminfo.c
reactos/dll/win32/msi/table.c
reactos/media/doc/README.WINE

index daca0f3..7b84e01 100644 (file)
@@ -65,7 +65,7 @@ set_module_type(msi win32dll)
 target_link_libraries(msi uuid ${PSEH_LIB} wine)
 add_dependencies(msi msi_idlheader)
 add_delay_importlibs(msi odbccp32 crypt32 wintrust)
 target_link_libraries(msi uuid ${PSEH_LIB} wine)
 add_dependencies(msi msi_idlheader)
 add_delay_importlibs(msi odbccp32 crypt32 wintrust)
-add_importlibs(msi advapi32 cabinet comctl32 gdi32 ole32 oleaut32 shell32 shlwapi urlmon user32 version wininet mspatcha
+add_importlibs(msi advapi32 advapi32_vista cabinet comctl32 gdi32 ole32 oleaut32 shell32 shlwapi urlmon user32 version wininet mspatcha
     #FIXME : should be in delayed imports
     imagehlp
     msvcrt
     #FIXME : should be in delayed imports
     imagehlp
     msvcrt
index c1baa82..ea66a4d 100644 (file)
@@ -239,8 +239,7 @@ static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
                 len++;
                 break;
             default:
                 len++;
                 break;
             default:
-                if (!count) in_quotes = FALSE;
-                else in_quotes = TRUE;
+                if (count) in_quotes = TRUE;
                 len++;
                 break;
             }
                 len++;
                 break;
             }
@@ -261,8 +260,7 @@ static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
                 break;
             default:
                 state = state_token;
                 break;
             default:
                 state = state_token;
-                if (!count) in_quotes = FALSE;
-                else in_quotes = TRUE;
+                if (count) in_quotes = TRUE;
                 len++;
                 break;
             }
                 len++;
                 break;
             }
@@ -271,6 +269,7 @@ static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
         default: break;
         }
         if (!ignore) *out++ = *p;
         default: break;
         }
         if (!ignore) *out++ = *p;
+        if (!count) in_quotes = FALSE;
     }
 
 done:
     }
 
 done:
@@ -313,7 +312,7 @@ UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
 
         ptr2 = strchrW( ptr, '=' );
         if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
 
         ptr2 = strchrW( ptr, '=' );
         if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
+
         len = ptr2 - ptr;
         if (!len) return ERROR_INVALID_COMMAND_LINE;
 
         len = ptr2 - ptr;
         if (!len) return ERROR_INVALID_COMMAND_LINE;
 
@@ -2362,6 +2361,18 @@ void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL loa
     TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
 }
 
     TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
 }
 
+static ULONGLONG get_volume_space_required( MSIPACKAGE *package )
+{
+    MSICOMPONENT *comp;
+    ULONGLONG ret = 0;
+
+    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    {
+        if (comp->Action == INSTALLSTATE_LOCAL) ret += comp->Cost;
+    }
+    return ret;
+}
+
 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
 {
     static const WCHAR query[] =
 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
 {
     static const WCHAR query[] =
@@ -2376,6 +2387,12 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     static const WCHAR szPrimaryVolumeSpaceAvailable[] =
         {'P','r','i','m','a','r','y','V','o','l','u','m','e','S','p','a','c','e',
          'A','v','a','i','l','a','b','l','e',0};
     static const WCHAR szPrimaryVolumeSpaceAvailable[] =
         {'P','r','i','m','a','r','y','V','o','l','u','m','e','S','p','a','c','e',
          'A','v','a','i','l','a','b','l','e',0};
+    static const WCHAR szPrimaryVolumeSpaceRequired[] =
+        {'P','r','i','m','a','r','y','V','o','l','u','m','e','S','p','a','c','e',
+         'R','e','q','u','i','r','e','d',0};
+    static const WCHAR szPrimaryVolumeSpaceRemaining[] =
+        {'P','r','i','m','a','r','y','V','o','l','u','m','e','S','p','a','c','e',
+         'R','e','m','a','i','n','i','n','g',0};
     static const WCHAR szOutOfNoRbDiskSpace[] =
         {'O','u','t','O','f','N','o','R','b','D','i','s','k','S','p','a','c','e',0};
     MSICOMPONENT *comp;
     static const WCHAR szOutOfNoRbDiskSpace[] =
         {'O','u','t','O','f','N','o','R','b','D','i','s','k','S','p','a','c','e',0};
     MSICOMPONENT *comp;
@@ -2426,6 +2443,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     if (!level) msi_set_property( package->db, szInstallLevel, szOne, -1 );
     msi_free(level);
 
     if (!level) msi_set_property( package->db, szInstallLevel, szOne, -1 );
     msi_free(level);
 
+    if ((rc = MSI_SetFeatureStates( package ))) return rc;
+
     if ((primary_key = msi_dup_property( package->db, szPrimaryFolder )))
     {
         if ((primary_folder = msi_dup_property( package->db, primary_key )))
     if ((primary_key = msi_dup_property( package->db, szPrimaryFolder )))
     {
         if ((primary_folder = msi_dup_property( package->db, primary_key )))
@@ -2433,17 +2452,23 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             if (((primary_folder[0] >= 'A' && primary_folder[0] <= 'Z') ||
                  (primary_folder[0] >= 'a' && primary_folder[0] <= 'z')) && primary_folder[1] == ':')
             {
             if (((primary_folder[0] >= 'A' && primary_folder[0] <= 'Z') ||
                  (primary_folder[0] >= 'a' && primary_folder[0] <= 'z')) && primary_folder[1] == ':')
             {
+                static const WCHAR fmtW[] = {'%','l','u',0};
                 ULARGE_INTEGER free;
                 ULARGE_INTEGER free;
+                ULONGLONG required;
+                WCHAR buf[21];
 
                 primary_folder[2] = 0;
                 if (GetDiskFreeSpaceExW( primary_folder, &free, NULL, NULL ))
                 {
 
                 primary_folder[2] = 0;
                 if (GetDiskFreeSpaceExW( primary_folder, &free, NULL, NULL ))
                 {
-                    static const WCHAR fmtW[] = {'%','l','u',0};
-                    WCHAR buf[21];
-
                     sprintfW( buf, fmtW, free.QuadPart / 512 );
                     msi_set_property( package->db, szPrimaryVolumeSpaceAvailable, buf, -1 );
                 }
                     sprintfW( buf, fmtW, free.QuadPart / 512 );
                     msi_set_property( package->db, szPrimaryVolumeSpaceAvailable, buf, -1 );
                 }
+                required = get_volume_space_required( package );
+                sprintfW( buf, fmtW, required / 512 );
+                msi_set_property( package->db, szPrimaryVolumeSpaceRequired, buf, -1 );
+
+                sprintfW( buf, fmtW, (free.QuadPart - required) / 512 );
+                msi_set_property( package->db, szPrimaryVolumeSpaceRemaining, buf, -1 );
                 msi_set_property( package->db, szPrimaryVolumePath, primary_folder, 2 );
             }
             msi_free( primary_folder );
                 msi_set_property( package->db, szPrimaryVolumePath, primary_folder, 2 );
             }
             msi_free( primary_folder );
@@ -2455,7 +2480,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
     msi_set_property( package->db, szOutOfNoRbDiskSpace, szZero, -1 );
 
     msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
     msi_set_property( package->db, szOutOfNoRbDiskSpace, szZero, -1 );
 
-    return MSI_SetFeatureStates(package);
+    return ERROR_SUCCESS;
 }
 
 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size )
 }
 
 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size )
@@ -2617,9 +2642,8 @@ static inline REGSAM get_registry_view( const MSICOMPONENT *comp )
     return view;
 }
 
     return view;
 }
 
-static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create )
+static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create, REGSAM access )
 {
 {
-    REGSAM access = KEY_ALL_ACCESS;
     WCHAR *subkey, *p, *q;
     HKEY hkey, ret = NULL;
     LONG res;
     WCHAR *subkey, *p, *q;
     HKEY hkey, ret = NULL;
     LONG res;
@@ -2641,7 +2665,7 @@ static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BO
     }
     if (q && q[1])
     {
     }
     if (q && q[1])
     {
-        ret = open_key( comp, hkey, q + 1, create );
+        ret = open_key( comp, hkey, q + 1, create, access );
         RegCloseKey( hkey );
     }
     else ret = hkey;
         RegCloseKey( hkey );
     }
     else ret = hkey;
@@ -2866,7 +2890,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     strcpyW(uikey,szRoot);
     strcatW(uikey,deformated);
 
     strcpyW(uikey,szRoot);
     strcatW(uikey,deformated);
 
-    if (!(hkey = open_key( comp, root_key, deformated, TRUE )))
+    if (!(hkey = open_key( comp, root_key, deformated, TRUE, KEY_QUERY_VALUE | KEY_SET_VALUE )))
     {
         ERR("Could not create key %s\n", debugstr_w(deformated));
         msi_free(uikey);
     {
         ERR("Could not create key %s\n", debugstr_w(deformated));
         msi_free(uikey);
@@ -2957,13 +2981,17 @@ static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
     access |= get_registry_view( comp );
 
     if (!(subkey = strdupW( path ))) return;
     access |= get_registry_view( comp );
 
     if (!(subkey = strdupW( path ))) return;
-    for (;;)
+    do
     {
     {
-        if ((p = strrchrW( subkey, '\\' ))) *p = 0;
-        hkey = open_key( comp, root, subkey, FALSE );
-        if (!hkey) break;
-        if (p && p[1])
+        if ((p = strrchrW( subkey, '\\' )))
+        {
+            *p = 0;
+            if (!p[1]) continue; /* trailing backslash */
+            hkey = open_key( comp, root, subkey, FALSE, access );
+            if (!hkey) break;
             res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
             res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
+            RegCloseKey( hkey );
+        }
         else
             res = RegDeleteKeyExW( root, subkey, access, 0 );
         if (res)
         else
             res = RegDeleteKeyExW( root, subkey, access, 0 );
         if (res)
@@ -2971,9 +2999,7 @@ static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
             TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
             break;
         }
             TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
             break;
         }
-        if (p && p[1]) RegCloseKey( hkey );
-        else break;
-    }
+    } while (p);
     msi_free( subkey );
 }
 
     msi_free( subkey );
 }
 
@@ -2983,7 +3009,7 @@ static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path
     HKEY hkey;
     DWORD num_subkeys, num_values;
 
     HKEY hkey;
     DWORD num_subkeys, num_values;
 
-    if ((hkey = open_key( comp, root, path, FALSE )))
+    if ((hkey = open_key( comp, root, path, FALSE, KEY_SET_VALUE | KEY_QUERY_VALUE )))
     {
         if ((res = RegDeleteValueW( hkey, value )))
             TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
     {
         if ((res = RegDeleteValueW( hkey, value )))
             TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
@@ -3004,8 +3030,8 @@ static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path
     LONG res;
     HKEY hkey;
 
     LONG res;
     HKEY hkey;
 
-    if (!(hkey = open_key( comp, root, path, FALSE ))) return;
-    res = SHDeleteKeyW( hkey, NULL );
+    if (!(hkey = open_key( comp, root, path, FALSE, KEY_ALL_ACCESS ))) return;
+    res = RegDeleteTreeW( hkey, NULL );
     if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
     delete_key( comp, root, path );
     RegCloseKey( hkey );
     if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
     delete_key( comp, root, path );
     RegCloseKey( hkey );
@@ -3537,7 +3563,9 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
                     continue;
 
                 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
                     continue;
 
-                row = MSI_QueryGetRecord(package->db, query, file->Sequence);
+                if (!(row = MSI_QueryGetRecord(package->db, query, file->Sequence)))
+                    return ERROR_FUNCTION_FAILED;
+
                 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
                 ptr2 = strrchrW(source, '\\') + 1;
                 msiobj_release(&row->hdr);
                 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
                 ptr2 = strrchrW(source, '\\') + 1;
                 msiobj_release(&row->hdr);
@@ -5857,8 +5885,8 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
 
     if (image_path != file->TargetPath) msi_free(image_path);
 done:
 
     if (image_path != file->TargetPath) msi_free(image_path);
 done:
-    CloseServiceHandle(service);
-    CloseServiceHandle(hscm);
+    if (service) CloseServiceHandle(service);
+    if (hscm) CloseServiceHandle(hscm);
     msi_free(name);
     msi_free(disp);
     msi_free(sd.lpDescription);
     msi_free(name);
     msi_free(disp);
     msi_free(sd.lpDescription);
@@ -6032,8 +6060,8 @@ done:
     msi_ui_actiondata( package, szStartServices, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_ui_actiondata( package, szStartServices, uirow );
     msiobj_release( &uirow->hdr );
 
-    CloseServiceHandle(service);
-    CloseServiceHandle(scm);
+    if (service) CloseServiceHandle(service);
+    if (scm) CloseServiceHandle(scm);
 
     msi_free(name);
     msi_free(args);
 
     msi_free(name);
     msi_free(args);
@@ -6142,8 +6170,8 @@ static UINT stop_service( LPCWSTR name )
         WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
 
 done:
         WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
 
 done:
-    CloseServiceHandle(service);
-    CloseServiceHandle(scm);
+    if (service) CloseServiceHandle(service);
+    if (scm) CloseServiceHandle(scm);
 
     return ERROR_SUCCESS;
 }
 
     return ERROR_SUCCESS;
 }
@@ -6280,8 +6308,8 @@ done:
     msi_ui_actiondata( package, szDeleteServices, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_ui_actiondata( package, szDeleteServices, uirow );
     msiobj_release( &uirow->hdr );
 
-    CloseServiceHandle( service );
-    CloseServiceHandle( scm );
+    if (service) CloseServiceHandle( service );
+    if (scm) CloseServiceHandle( scm );
     msi_free( name );
     msi_free( display_name );
 
     msi_free( name );
     msi_free( display_name );
 
@@ -6903,13 +6931,13 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
     LPCWSTR name, value, component;
 {
     MSIPACKAGE *package = param;
     LPCWSTR name, value, component;
-    LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
-    DWORD flags, type, size;
+    WCHAR *data = NULL, *newval = NULL, *deformatted = NULL, *p, *q;
+    DWORD flags, type, size, len, len_value = 0;
     UINT res;
     HKEY env = NULL;
     MSICOMPONENT *comp;
     MSIRECORD *uirow;
     UINT res;
     HKEY env = NULL;
     MSICOMPONENT *comp;
     MSIRECORD *uirow;
-    int action = 0;
+    int action = 0, found = 0;
 
     component = MSI_RecordGetString(rec, 4);
     comp = msi_get_loaded_component(package, component);
 
     component = MSI_RecordGetString(rec, 4);
     comp = msi_get_loaded_component(package, component);
@@ -6937,7 +6965,20 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
         goto done;
     }
 
         goto done;
     }
 
-    value = deformatted;
+    if ((value = deformatted))
+    {
+        if (flags & ENV_MOD_PREFIX)
+        {
+            p = strrchrW( value, ';' );
+            len_value = p - value;
+        }
+        else if (flags & ENV_MOD_APPEND)
+        {
+            value = strchrW( value, ';' ) + 1;
+            len_value = strlenW( value );
+        }
+        else len_value = strlenW( value );
+    }
 
     res = open_env_key( flags, &env );
     if (res != ERROR_SUCCESS)
 
     res = open_env_key( flags, &env );
     if (res != ERROR_SUCCESS)
@@ -6963,10 +7004,6 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             res = ERROR_SUCCESS;
             goto done;
         }
             res = ERROR_SUCCESS;
             goto done;
         }
-
-        /* If we are appending but the string was empty, strip ; */
-        if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
-
         size = (lstrlenW(value) + 1) * sizeof(WCHAR);
         newval = strdupW(value);
         if (!newval)
         size = (lstrlenW(value) + 1) * sizeof(WCHAR);
         newval = strdupW(value);
         if (!newval)
@@ -6986,15 +7023,14 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             goto done;
         }
 
             goto done;
         }
 
-        data = msi_alloc(size);
-        if (!data)
+        if (!(p = q = data = msi_alloc( size )))
         {
             msi_free(deformatted);
             RegCloseKey(env);
             return ERROR_OUTOFMEMORY;
         }
 
         {
             msi_free(deformatted);
             RegCloseKey(env);
             return ERROR_OUTOFMEMORY;
         }
 
-        res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
+        res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)data, &size );
         if (res != ERROR_SUCCESS)
             goto done;
 
         if (res != ERROR_SUCCESS)
             goto done;
 
@@ -7007,20 +7043,28 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             goto done;
         }
 
             goto done;
         }
 
-        size = (lstrlenW(data) + 1) * sizeof(WCHAR);
-        if (flags & ENV_MOD_MASK)
+        for (;;)
         {
         {
-            DWORD mod_size;
-            int multiplier = 0;
-            if (flags & ENV_MOD_APPEND) multiplier++;
-            if (flags & ENV_MOD_PREFIX) multiplier++;
-            mod_size = lstrlenW(value) * multiplier;
-            size += mod_size * sizeof(WCHAR);
+            while (*q && *q != ';') q++;
+            len = q - p;
+            if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ) &&
+                (!p[len] || p[len] == ';'))
+            {
+                found = 1;
+                break;
+            }
+            if (!*q) break;
+            p = ++q;
         }
 
         }
 
-        newval = msi_alloc(size);
-        ptr = newval;
-        if (!newval)
+        if (found)
+        {
+            TRACE("string already set\n");
+            goto done;
+        }
+
+        size = (len_value + 1 + strlenW( data ) + 1) * sizeof(WCHAR);
+        if (!(p = newval = msi_alloc( size )))
         {
             res = ERROR_OUTOFMEMORY;
             goto done;
         {
             res = ERROR_OUTOFMEMORY;
             goto done;
@@ -7028,21 +7072,24 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
 
         if (flags & ENV_MOD_PREFIX)
         {
 
         if (flags & ENV_MOD_PREFIX)
         {
-            lstrcpyW(newval, value);
-            ptr = newval + lstrlenW(value);
+            memcpy( newval, value, len_value * sizeof(WCHAR) );
+            newval[len_value] = ';';
+            p = newval + len_value + 1;
             action |= 0x80000000;
         }
 
             action |= 0x80000000;
         }
 
-        lstrcpyW(ptr, data);
+        strcpyW( p, data );
 
         if (flags & ENV_MOD_APPEND)
         {
 
         if (flags & ENV_MOD_APPEND)
         {
-            lstrcatW(newval, value);
+            p += strlenW( data );
+            *p++ = ';';
+            memcpy( p, value, (len_value + 1) * sizeof(WCHAR) );
             action |= 0x40000000;
         }
     }
     TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
             action |= 0x40000000;
         }
     }
     TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
-    res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
+    res = RegSetValueExW( env, name, 0, type, (BYTE *)newval, size );
     if (res)
     {
         WARN("Failed to set %s to %s (%d)\n",  debugstr_w(name), debugstr_w(newval), res);
     if (res)
     {
         WARN("Failed to set %s to %s (%d)\n",  debugstr_w(name), debugstr_w(newval), res);
@@ -7084,8 +7131,8 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
     LPCWSTR name, value, component;
 {
     MSIPACKAGE *package = param;
     LPCWSTR name, value, component;
-    LPWSTR deformatted = NULL;
-    DWORD flags;
+    WCHAR *p, *q, *deformatted = NULL, *new_value = NULL;
+    DWORD flags, type, size, len, len_value = 0, len_new_value;
     HKEY env;
     MSICOMPONENT *comp;
     MSIRECORD *uirow;
     HKEY env;
     MSICOMPONENT *comp;
     MSIRECORD *uirow;
@@ -7122,7 +7169,20 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
     if (value && !deformat_string( package, value, &deformatted ))
         return ERROR_OUTOFMEMORY;
 
     if (value && !deformat_string( package, value, &deformatted ))
         return ERROR_OUTOFMEMORY;
 
-    value = deformatted;
+    if ((value = deformatted))
+    {
+        if (flags & ENV_MOD_PREFIX)
+        {
+            p = strchrW( value, ';' );
+            len_value = p - value;
+        }
+        else if (flags & ENV_MOD_APPEND)
+        {
+            value = strchrW( value, ';' ) + 1;
+            len_value = strlenW( value );
+        }
+        else len_value = strlenW( value );
+    }
 
     r = open_env_key( flags, &env );
     if (r != ERROR_SUCCESS)
 
     r = open_env_key( flags, &env );
     if (r != ERROR_SUCCESS)
@@ -7134,13 +7194,48 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
     if (flags & ENV_MOD_MACHINE)
         action |= 0x20000000;
 
     if (flags & ENV_MOD_MACHINE)
         action |= 0x20000000;
 
-    TRACE("Removing %s\n", debugstr_w(name));
+    size = 0;
+    type = REG_SZ;
+    res = RegQueryValueExW( env, name, NULL, &type, NULL, &size );
+    if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ))
+        goto done;
+
+    if (!(new_value = msi_alloc( size ))) goto done;
 
 
-    res = RegDeleteValueW( env, name );
+    res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)new_value, &size );
     if (res != ERROR_SUCCESS)
     if (res != ERROR_SUCCESS)
+        goto done;
+
+    len_new_value = size / sizeof(WCHAR) - 1;
+    p = q = new_value;
+    for (;;)
     {
     {
-        WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
-        r = ERROR_SUCCESS;
+        while (*q && *q != ';') q++;
+        len = q - p;
+        if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ))
+        {
+            if (*q == ';') q++;
+            memmove( p, q, (len_new_value - (q - new_value) + 1) * sizeof(WCHAR) );
+            break;
+        }
+        if (!*q) break;
+        p = ++q;
+    }
+
+    if (!new_value[0] || !value)
+    {
+        TRACE("removing %s\n", debugstr_w(name));
+        res = RegDeleteValueW( env, name );
+        if (res != ERROR_SUCCESS)
+            WARN("failed to delete value %s (%d)\n", debugstr_w(name), res);
+    }
+    else
+    {
+        TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(new_value));
+        size = (strlenW( new_value ) + 1) * sizeof(WCHAR);
+        res = RegSetValueExW( env, name, 0, type, (BYTE *)new_value, size );
+        if (res != ERROR_SUCCESS)
+            WARN("failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(new_value), res);
     }
 
 done:
     }
 
 done:
@@ -7153,6 +7248,7 @@ done:
 
     if (env) RegCloseKey( env );
     msi_free( deformatted );
 
     if (env) RegCloseKey( env );
     msi_free( deformatted );
+    msi_free( new_value );
     return r;
 }
 
     return r;
 }
 
index 01a1ac8..c46e178 100644 (file)
@@ -1421,7 +1421,7 @@ static HRESULT session_invoke(
                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
                 if (FAILED(hr)) return hr;
                 V_VT(pVarResult) = VT_BOOL;
                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
                 if (FAILED(hr)) return hr;
                 V_VT(pVarResult) = VT_BOOL;
-                V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
+                V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE;
             } else if (wFlags & DISPATCH_PROPERTYPUT) {
                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
                 if (FAILED(hr)) return hr;
             } else if (wFlags & DISPATCH_PROPERTYPUT) {
                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
                 if (FAILED(hr)) return hr;
@@ -1816,12 +1816,36 @@ static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
                                                 EXCEPINFO* pExcepInfo,
                                                 UINT* puArgErr)
 {
                                                 EXCEPINFO* pExcepInfo,
                                                 UINT* puArgErr)
 {
-    if (!(wFlags & DISPATCH_METHOD))
+    UINT ret;
+    HRESULT hr;
+    MSIHANDLE hsuminfo;
+    IDispatch *dispatch;
+    VARIANTARG varg0, varg1;
+
+    if (!(wFlags & DISPATCH_PROPERTYGET))
         return DISP_E_MEMBERNOTFOUND;
 
         return DISP_E_MEMBERNOTFOUND;
 
-    FIXME("\n");
+    VariantInit(&varg1);
+    hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
+    if (FAILED(hr))
+        return hr;
 
 
-    VariantInit(pVarResult);
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo);
+    VariantClear(&varg0);
+    if (ret != ERROR_SUCCESS)
+        return DISP_E_EXCEPTION;
+
+    hr = create_summaryinfo(hsuminfo, &dispatch);
+    if (FAILED(hr))
+        return hr;
+
+    V_VT(pVarResult) = VT_DISPATCH;
+    V_DISPATCH(pVarResult) = dispatch;
     return S_OK;
 }
 
     return S_OK;
 }
 
@@ -2013,7 +2037,7 @@ static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
         /* Return VT_BOOL clarifying whether registry key exists or not. */
         case VT_EMPTY:
             V_VT(pVarResult) = VT_BOOL;
         /* Return VT_BOOL clarifying whether registry key exists or not. */
         case VT_EMPTY:
             V_VT(pVarResult) = VT_BOOL;
-            V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
+            V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE;
             break;
 
         /* Return the value of specified key if it exists. */
             break;
 
         /* Return the value of specified key if it exists. */
index 4636eba..1b138eb 100644 (file)
@@ -953,7 +953,7 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
 
         cls->action = INSTALLSTATE_ABSENT;
 
 
         cls->action = INSTALLSTATE_ABSENT;
 
-        res = SHDeleteKeyW( hkey, cls->clsid );
+        res = RegDeleteTreeW( hkey, cls->clsid );
         if (res != ERROR_SUCCESS)
             WARN("Failed to delete class key %d\n", res);
 
         if (res != ERROR_SUCCESS)
             WARN("Failed to delete class key %d\n", res);
 
@@ -975,7 +975,7 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
             {
                 strcpyW( filetype, szFileType );
                 strcatW( filetype, cls->clsid );
             {
                 strcpyW( filetype, szFileType );
                 strcatW( filetype, cls->clsid );
-                res = SHDeleteKeyW( HKEY_CLASSES_ROOT, filetype );
+                res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype );
                 msi_free( filetype );
 
                 if (res != ERROR_SUCCESS)
                 msi_free( filetype );
 
                 if (res != ERROR_SUCCESS)
@@ -1148,7 +1148,7 @@ UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
         }
         TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
 
         }
         TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
 
-        res = SHDeleteKeyW( HKEY_CLASSES_ROOT, progid->ProgID );
+        res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
         if (res != ERROR_SUCCESS)
             TRACE("Failed to delete progid key %d\n", res);
 
         if (res != ERROR_SUCCESS)
             TRACE("Failed to delete progid key %d\n", res);
 
@@ -1392,7 +1392,7 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
         {
             extension[0] = '.';
             strcpyW( extension + 1, ext->Extension );
         {
             extension[0] = '.';
             strcpyW( extension + 1, ext->Extension );
-            res = SHDeleteKeyW( HKEY_CLASSES_ROOT, extension );
+            res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension );
             msi_free( extension );
             if (res != ERROR_SUCCESS)
                 WARN("Failed to delete extension key %d\n", res);
             msi_free( extension );
             if (res != ERROR_SUCCESS)
                 WARN("Failed to delete extension key %d\n", res);
@@ -1414,7 +1414,7 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
             {
                 strcpyW( progid_shell, progid );
                 strcatW( progid_shell, shellW );
             {
                 strcpyW( progid_shell, progid );
                 strcatW( progid_shell, shellW );
-                res = SHDeleteKeyW( HKEY_CLASSES_ROOT, progid_shell );
+                res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell );
                 msi_free( progid_shell );
                 if (res != ERROR_SUCCESS)
                     WARN("Failed to delete shell key %d\n", res);
                 msi_free( progid_shell );
                 if (res != ERROR_SUCCESS)
                     WARN("Failed to delete shell key %d\n", res);
index b815b72..281dac2 100644 (file)
@@ -36,6 +36,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 #define IS_INTMSIDBOPEN(x)      (((ULONG_PTR)(x) >> 16) == 0)
 
 
 #define IS_INTMSIDBOPEN(x)      (((ULONG_PTR)(x) >> 16) == 0)
 
+struct row_export_info
+{
+    HANDLE handle;
+    LPCWSTR folder;
+    LPCWSTR table;
+};
+
 static void free_transforms( MSIDATABASE *db )
 {
     while( !list_empty( &db->transforms ) )
 static void free_transforms( MSIDATABASE *db )
 {
     while( !list_empty( &db->transforms ) )
@@ -763,6 +770,8 @@ static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
     lstrcatW( path, file );
 
     data = msi_read_text_archive( path, &len );
     lstrcatW( path, file );
 
     data = msi_read_text_archive( path, &len );
+    if (data == NULL)
+        return ERROR_BAD_PATHNAME;
 
     ptr = data;
     msi_parse_line( &ptr, &columns, &num_columns, &len );
 
     ptr = data;
     msi_parse_line( &ptr, &columns, &num_columns, &len );
@@ -901,50 +910,131 @@ end:
     return r;
 }
 
     return r;
 }
 
-static UINT msi_export_record( HANDLE handle, MSIRECORD *row, UINT start )
+static UINT msi_export_field( HANDLE handle, MSIRECORD *row, UINT field )
 {
 {
-    UINT i, count, len, r = ERROR_SUCCESS;
-    const char *sep;
     char *buffer;
     char *buffer;
+    BOOL bret;
     DWORD sz;
     DWORD sz;
+    UINT r;
 
 
-    len = 0x100;
-    buffer = msi_alloc( len );
-    if ( !buffer )
+    sz = 0x100;
+    buffer = msi_alloc( sz );
+    if (!buffer)
         return ERROR_OUTOFMEMORY;
 
         return ERROR_OUTOFMEMORY;
 
-    count = MSI_RecordGetFieldCount( row );
-    for ( i=start; i<=count; i++ )
+    r = MSI_RecordGetStringA( row, field, buffer, &sz );
+    if (r == ERROR_MORE_DATA)
     {
     {
-        sz = len;
-        r = MSI_RecordGetStringA( row, i, buffer, &sz );
-        if (r == ERROR_MORE_DATA)
+        char *p;
+
+        sz++; /* leave room for NULL terminator */
+        p = msi_realloc( buffer, sz );
+        if (!p)
         {
         {
-            char *p = msi_realloc( buffer, sz + 1 );
-            if (!p)
-                break;
-            len = sz + 1;
-            buffer = p;
+            msi_free( buffer );
+            return ERROR_OUTOFMEMORY;
         }
         }
-        sz = len;
-        r = MSI_RecordGetStringA( row, i, buffer, &sz );
+        buffer = p;
+
+        r = MSI_RecordGetStringA( row, field, buffer, &sz );
         if (r != ERROR_SUCCESS)
         if (r != ERROR_SUCCESS)
-            break;
+        {
+            msi_free( buffer );
+            return r;
+        }
+    }
+    else if (r != ERROR_SUCCESS)
+        return r;
+
+    bret = WriteFile( handle, buffer, sz, &sz, NULL );
+    msi_free( buffer );
+    if (!bret)
+        return ERROR_FUNCTION_FAILED;
+
+    return r;
+}
+
+static UINT msi_export_stream( LPCWSTR folder, LPCWSTR table, MSIRECORD *row, UINT field,
+                               UINT start )
+{
+    static const WCHAR fmt_file[] = { '%','s','/','%','s','/','%','s',0 };
+    static const WCHAR fmt_folder[] = { '%','s','/','%','s',0 };
+    WCHAR stream_name[256], stream_filename[MAX_PATH];
+    DWORD sz, read_size, write_size;
+    char buffer[1024];
+    HANDLE file;
+    UINT r;
+
+    /* get the name of the file */
+    sz = sizeof(stream_name)/sizeof(WCHAR);
+    r = MSI_RecordGetStringW( row, start, stream_name, &sz );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    /* if the destination folder does not exist then create it (folder name = table name) */
+    snprintfW( stream_filename, sizeof(stream_filename), fmt_folder, folder, table );
+    if (GetFileAttributesW( stream_filename ) == INVALID_FILE_ATTRIBUTES)
+    {
+        if (!CreateDirectoryW( stream_filename, NULL ))
+            return ERROR_PATH_NOT_FOUND;
+    }
+
+    /* actually create the file */
+    snprintfW( stream_filename, sizeof(stream_filename), fmt_file, folder, table, stream_name );
+    file = CreateFileW( stream_filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+    if (file == INVALID_HANDLE_VALUE)
+        return ERROR_FILE_NOT_FOUND;
+
+    /* copy the stream to the file */
+    read_size = sizeof(buffer);
+    while (read_size == sizeof(buffer))
+    {
+        r = MSI_RecordReadStream( row, field, buffer, &read_size );
+        if (r != ERROR_SUCCESS)
+        {
+            CloseHandle( file );
+            return r;
+        }
+        if (!WriteFile( file, buffer, read_size, &write_size, NULL ) || read_size != write_size)
+        {
+            CloseHandle( file );
+            return ERROR_WRITE_FAULT;
+        }
+    }
+    CloseHandle( file );
+    return r;
+}
 
 
-        if (!WriteFile( handle, buffer, sz, &sz, NULL ))
+static UINT msi_export_record( struct row_export_info *row_export_info, MSIRECORD *row, UINT start )
+{
+    HANDLE handle = row_export_info->handle;
+    UINT i, count, r = ERROR_SUCCESS;
+    const char *sep;
+    DWORD sz;
+
+    count = MSI_RecordGetFieldCount( row );
+    for (i = start; i <= count; i++)
+    {
+        r = msi_export_field( handle, row, i );
+        if (r == ERROR_INVALID_PARAMETER)
         {
         {
-            r = ERROR_FUNCTION_FAILED;
-            break;
+            r = msi_export_stream( row_export_info->folder, row_export_info->table, row, i, start );
+            if (r != ERROR_SUCCESS)
+                return r;
+
+            /* exporting a binary stream, repeat the "Name" field */
+            r = msi_export_field( handle, row, start );
+            if (r != ERROR_SUCCESS)
+                return r;
         }
         }
+        else if (r != ERROR_SUCCESS)
+            return r;
 
         sep = (i < count) ? "\t" : "\r\n";
         if (!WriteFile( handle, sep, strlen(sep), &sz, NULL ))
 
         sep = (i < count) ? "\t" : "\r\n";
         if (!WriteFile( handle, sep, strlen(sep), &sz, NULL ))
-        {
-            r = ERROR_FUNCTION_FAILED;
-            break;
-        }
+            return ERROR_FUNCTION_FAILED;
     }
     }
-    msi_free( buffer );
     return r;
 }
 
     return r;
 }
 
@@ -968,9 +1058,25 @@ static UINT msi_export_forcecodepage( HANDLE handle, UINT codepage )
     return ERROR_SUCCESS;
 }
 
     return ERROR_SUCCESS;
 }
 
+static UINT msi_export_summaryinformation( MSIDATABASE *db, HANDLE handle )
+{
+    static const char header[] = "PropertyId\tValue\r\n"
+                                 "i2\tl255\r\n"
+                                 "_SummaryInformation\tPropertyId\r\n";
+    DWORD sz;
+
+    sz = lstrlenA(header);
+    if (!WriteFile(handle, header, sz, &sz, NULL))
+        return ERROR_WRITE_FAULT;
+
+    return msi_export_suminfo( db, handle );
+}
+
 static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
                LPCWSTR folder, LPCWSTR file )
 {
 static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
                LPCWSTR folder, LPCWSTR file )
 {
+    static const WCHAR summaryinformation[] = {
+        '_','S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0 };
     static const WCHAR query[] = {
         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','%','s',0 };
     static const WCHAR forcecodepage[] = {
     static const WCHAR query[] = {
         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','%','s',0 };
     static const WCHAR forcecodepage[] = {
@@ -1009,14 +1115,22 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
         goto done;
     }
 
         goto done;
     }
 
+    if (!strcmpW( table, summaryinformation ))
+    {
+        r = msi_export_summaryinformation( db, handle );
+        goto done;
+    }
+
     r = MSI_OpenQuery( db, &view, query, table );
     if (r == ERROR_SUCCESS)
     {
     r = MSI_OpenQuery( db, &view, query, table );
     if (r == ERROR_SUCCESS)
     {
+        struct row_export_info row_export_info = { handle, folder, table };
+
         /* write out row 1, the column names */
         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
         if (r == ERROR_SUCCESS)
         {
         /* write out row 1, the column names */
         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
         if (r == ERROR_SUCCESS)
         {
-            msi_export_record( handle, rec, 1 );
+            msi_export_record( &row_export_info, rec, 1 );
             msiobj_release( &rec->hdr );
         }
 
             msiobj_release( &rec->hdr );
         }
 
@@ -1024,7 +1138,7 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
         if (r == ERROR_SUCCESS)
         {
         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
         if (r == ERROR_SUCCESS)
         {
-            msi_export_record( handle, rec, 1 );
+            msi_export_record( &row_export_info, rec, 1 );
             msiobj_release( &rec->hdr );
         }
 
             msiobj_release( &rec->hdr );
         }
 
@@ -1033,12 +1147,12 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
         if (r == ERROR_SUCCESS)
         {
             MSI_RecordSetStringW( rec, 0, table );
         if (r == ERROR_SUCCESS)
         {
             MSI_RecordSetStringW( rec, 0, table );
-            msi_export_record( handle, rec, 0 );
+            msi_export_record( &row_export_info, rec, 0 );
             msiobj_release( &rec->hdr );
         }
 
         /* write out row 4 onwards, the data */
             msiobj_release( &rec->hdr );
         }
 
         /* write out row 4 onwards, the data */
-        r = MSI_IterateRecords( view, 0, msi_export_row, handle );
+        r = MSI_IterateRecords( view, 0, msi_export_row, &row_export_info );
         msiobj_release( &view->hdr );
     }
 
         msiobj_release( &view->hdr );
     }
 
index 3f5c7c5..77ebc5b 100644 (file)
@@ -2672,7 +2672,7 @@ static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec )
 
     /* create the treeview control */
     style = TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT;
 
     /* create the treeview control */
     style = TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT;
-    style |= WS_GROUP | WS_VSCROLL;
+    style |= WS_GROUP | WS_VSCROLL | WS_TABSTOP;
     control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW, style );
     if (!control)
     {
     control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW, style );
     if (!control)
     {
@@ -3645,8 +3645,11 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
     if (!dialog->default_font)
     {
         dialog->default_font = strdupW(dfv);
     if (!dialog->default_font)
     {
         dialog->default_font = strdupW(dfv);
-        msiobj_release( &rec->hdr );
-        if (!dialog->default_font) return -1;
+        if (!dialog->default_font)
+        {
+            msiobj_release( &rec->hdr );
+            return -1;
+        }
     }
 
     title = msi_get_deformatted_field( dialog->package, rec, 7 );
     }
 
     title = msi_get_deformatted_field( dialog->package, rec, 7 );
index c7124de..d29ffaf 100644 (file)
@@ -4291,6 +4291,17 @@ UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HAND
     return ERROR_SUCCESS;
 }
 
     return ERROR_SUCCESS;
 }
 
+/***********************************************************************
+ * MsiJoinTransaction     [MSI.@]
+ */
+UINT WINAPI MsiJoinTransaction( MSIHANDLE handle, DWORD attrs, HANDLE *event )
+{
+    FIXME("%u %08x %p\n", handle, attrs, event);
+
+    *event = (HANDLE)0xdeadbeef;
+    return ERROR_SUCCESS;
+}
+
 /***********************************************************************
  * MsiEndTransaction     [MSI.@]
  */
 /***********************************************************************
  * MsiEndTransaction     [MSI.@]
  */
index 0ea9a27..d48f08b 100644 (file)
 284 stdcall MsiBeginTransactionA(str long ptr ptr)
 285 stdcall MsiBeginTransactionW(wstr long ptr ptr)
 286 stdcall MsiEndTransaction(long)
 284 stdcall MsiBeginTransactionA(str long ptr ptr)
 285 stdcall MsiBeginTransactionW(wstr long ptr ptr)
 286 stdcall MsiEndTransaction(long)
-287 stub MsiJoinTransaction
+287 stdcall MsiJoinTransaction(long long ptr)
 288 stub MsiSetOfflineContextW
 289 stdcall MsiEnumComponentsExA(str long long ptr ptr ptr ptr)
 290 stdcall MsiEnumComponentsExW(wstr long long ptr ptr ptr ptr)
 288 stub MsiSetOfflineContextW
 289 stdcall MsiEnumComponentsExA(str long long ptr ptr ptr ptr)
 290 stdcall MsiEnumComponentsExW(wstr long long ptr ptr ptr ptr)
index 3dea486..4d1aa3a 100644 (file)
@@ -968,6 +968,7 @@ extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) DECL
 extern INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN;
 extern LPWSTR msi_get_suminfo_product( IStorage *stg ) DECLSPEC_HIDDEN;
 extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) DECLSPEC_HIDDEN;
 extern INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN;
 extern LPWSTR msi_get_suminfo_product( IStorage *stg ) DECLSPEC_HIDDEN;
 extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) DECLSPEC_HIDDEN;
+extern UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle ) DECLSPEC_HIDDEN;
 extern enum platform parse_platform( const WCHAR *str ) DECLSPEC_HIDDEN;
 extern UINT msi_load_suminfo_properties( MSIPACKAGE *package ) DECLSPEC_HIDDEN;
 
 extern enum platform parse_platform( const WCHAR *str ) DECLSPEC_HIDDEN;
 extern UINT msi_load_suminfo_properties( MSIPACKAGE *package ) DECLSPEC_HIDDEN;
 
index 9dc33be..4dcc971 100644 (file)
@@ -335,7 +335,7 @@ UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
             if ((type & MSI_DATASIZEMASK) == 2)
                 MSI_RecordSetInteger(*rec, i, ival - (1<<15));
             else
             if ((type & MSI_DATASIZEMASK) == 2)
                 MSI_RecordSetInteger(*rec, i, ival - (1<<15));
             else
-                MSI_RecordSetInteger(*rec, i, ival - (1<<31));
+                MSI_RecordSetInteger(*rec, i, ival - (1u<<31));
         }
     }
 
         }
     }
 
index 37afba8..5f35ec2 100644 (file)
@@ -2100,6 +2100,8 @@ UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
     MSIRECORD *row;
     UINT rc = ERROR_FUNCTION_FAILED;
 
     MSIRECORD *row;
     UINT rc = ERROR_FUNCTION_FAILED;
 
+    TRACE("%p %s %p %p\n", db, debugstr_w(szName), szValueBuf, pchValueBuf);
+
     row = msi_get_property_row( db, szName );
 
     if (*pchValueBuf > 0)
     row = msi_get_property_row( db, szName );
 
     if (*pchValueBuf > 0)
index 31995a8..3bb22cd 100644 (file)
@@ -157,6 +157,10 @@ static const WCHAR szUserComponents[] = {
     'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
     'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
 
     'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
     'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
 
+static const WCHAR szInstaller_Components[] = {
+    'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
+    'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
+
 static const WCHAR szUserFeatures[] = {
     'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
     'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
 static const WCHAR szUserFeatures[] = {
     'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
     'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
@@ -466,7 +470,7 @@ UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
         strcpyW(keypath, szUninstall);
         strcatW(keypath, product);
     }
         strcpyW(keypath, szUninstall);
         strcatW(keypath, product);
     }
-    return SHDeleteKeyW(HKEY_LOCAL_MACHINE, keypath);
+    return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
 }
 
 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
 }
 
 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
@@ -517,7 +521,7 @@ UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
 
     strcpyW(keypath, szUserProducts);
     strcatW(keypath, squished_pc);
 
     strcpyW(keypath, szUserProducts);
     strcatW(keypath, squished_pc);
-    return SHDeleteKeyW(HKEY_CURRENT_USER, keypath);
+    return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
 }
 
 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
 }
 
 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
@@ -582,7 +586,7 @@ UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
 
     strcpyW(keypath, szUserFeatures);
     strcatW(keypath, squished_pc);
 
     strcpyW(keypath, szUserFeatures);
     strcatW(keypath, squished_pc);
-    return SHDeleteKeyW(HKEY_CURRENT_USER, keypath);
+    return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
 }
 
 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
 }
 
 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
@@ -634,6 +638,7 @@ UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINS
 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
 {
     WCHAR squished_cc[GUID_SIZE], keypath[0x200];
 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
 {
     WCHAR squished_cc[GUID_SIZE], keypath[0x200];
+    UINT ret;
 
     if (!squash_guid(szComponent, squished_cc)) return ERROR_FUNCTION_FAILED;
     TRACE("%s squished %s\n", debugstr_w(szComponent), debugstr_w(squished_cc));
 
     if (!squash_guid(szComponent, squished_cc)) return ERROR_FUNCTION_FAILED;
     TRACE("%s squished %s\n", debugstr_w(szComponent), debugstr_w(squished_cc));
@@ -642,7 +647,12 @@ UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
     strcatW(keypath, squished_cc);
 
     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
     strcatW(keypath, squished_cc);
 
     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
-    return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
+    ret = RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
+    if (ret != ERROR_FILE_NOT_FOUND) return ret;
+
+    strcpyW(keypath, szInstaller_Components);
+    strcatW(keypath, squished_cc);
+    return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
 }
 
 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
 }
 
 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
@@ -696,7 +706,7 @@ UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
         sprintfW(keypath, szUserDataComponents_fmt, szUserSid);
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
         sprintfW(keypath, szUserDataComponents_fmt, szUserSid);
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
-    r = SHDeleteKeyW(hkey, comp);
+    r = RegDeleteTreeW(hkey, comp);
     RegCloseKey(hkey);
     return r;
 }
     RegCloseKey(hkey);
     return r;
 }
@@ -777,7 +787,7 @@ UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
         LocalFree(usersid);
     }
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
         LocalFree(usersid);
     }
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
-    r = SHDeleteKeyW(hkey, squished_patch);
+    r = RegDeleteTreeW(hkey, squished_patch);
     RegCloseKey(hkey);
     return r;
 }
     RegCloseKey(hkey);
     return r;
 }
@@ -854,7 +864,7 @@ UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
     LocalFree(usersid);
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
     LocalFree(usersid);
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     RegCloseKey(hkey);
     return r;
 }
     RegCloseKey(hkey);
     return r;
 }
@@ -870,7 +880,7 @@ UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
     TRACE("%s squished %s\n", debugstr_w(szProduct), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_Products, 0, access, &hkey)) return ERROR_SUCCESS;
     TRACE("%s squished %s\n", debugstr_w(szProduct), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_Products, 0, access, &hkey)) return ERROR_SUCCESS;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     RegCloseKey(hkey);
     return r;
 }
     RegCloseKey(hkey);
     return r;
 }
@@ -927,7 +937,7 @@ UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
 
     strcpyW(keypath, szInstaller_UserUpgradeCodes);
     strcatW(keypath, squished_pc);
 
     strcpyW(keypath, szInstaller_UserUpgradeCodes);
     strcatW(keypath, squished_pc);
-    return SHDeleteKeyW(HKEY_CURRENT_USER, keypath);
+    return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
 }
 
 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
 }
 
 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
@@ -941,7 +951,7 @@ UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
     TRACE("%s squished %s\n", debugstr_w(szProductCode), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesProducts, 0, access, &hkey)) return ERROR_SUCCESS;
     TRACE("%s squished %s\n", debugstr_w(szProductCode), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesProducts, 0, access, &hkey)) return ERROR_SUCCESS;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     RegCloseKey(hkey);
     return r;
 }
     RegCloseKey(hkey);
     return r;
 }
@@ -957,7 +967,7 @@ UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
     TRACE("%s squished %s\n", debugstr_w(szProductCode), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesFeatures, 0, access, &hkey)) return ERROR_SUCCESS;
     TRACE("%s squished %s\n", debugstr_w(szProductCode), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesFeatures, 0, access, &hkey)) return ERROR_SUCCESS;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     RegCloseKey(hkey);
     return r;
 }
     RegCloseKey(hkey);
     return r;
 }
@@ -988,7 +998,7 @@ UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
     TRACE("%s squished %s\n", debugstr_w(szUpgradeCode), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_ClassesUpgradeCodes, 0, access, &hkey)) return ERROR_SUCCESS;
     TRACE("%s squished %s\n", debugstr_w(szUpgradeCode), debugstr_w(squished_pc));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_ClassesUpgradeCodes, 0, access, &hkey)) return ERROR_SUCCESS;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     RegCloseKey(hkey);
     return r;
 }
     RegCloseKey(hkey);
     return r;
 }
index 642093e..596fa13 100644 (file)
@@ -194,7 +194,28 @@ static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row
 
 static UINT STREAMS_delete_row(struct tagMSIVIEW *view, UINT row)
 {
 
 static UINT STREAMS_delete_row(struct tagMSIVIEW *view, UINT row)
 {
-    FIXME("(%p %d): stub!\n", view, row);
+    MSIDATABASE *db = ((MSISTREAMSVIEW *)view)->db;
+    UINT i, num_rows = db->num_streams - 1;
+    const WCHAR *name;
+    WCHAR *encname;
+    HRESULT hr;
+
+    TRACE("(%p %d)!\n", view, row);
+
+    name = msi_string_lookup( db->strings, db->streams[row].str_index, NULL );
+    if (!(encname = encode_streamname( FALSE, name ))) return ERROR_OUTOFMEMORY;
+    hr = IStorage_DestroyElement( db->storage, encname );
+    msi_free( encname );
+    if (FAILED( hr ))
+        return ERROR_FUNCTION_FAILED;
+    hr = IStream_Release( db->streams[row].stream );
+    if (FAILED( hr ))
+        return ERROR_FUNCTION_FAILED;
+
+    for (i = row; i < num_rows; i++)
+        db->streams[i] = db->streams[i + 1];
+    db->num_streams = num_rows;
+
     return ERROR_SUCCESS;
 }
 
     return ERROR_SUCCESS;
 }
 
@@ -293,12 +314,15 @@ static UINT STREAMS_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRE
         r = streams_modify_update(view, rec);
         break;
 
         r = streams_modify_update(view, rec);
         break;
 
+    case MSIMODIFY_DELETE:
+        r = STREAMS_delete_row(view, row - 1);
+        break;
+
     case MSIMODIFY_VALIDATE_NEW:
     case MSIMODIFY_INSERT_TEMPORARY:
     case MSIMODIFY_REFRESH:
     case MSIMODIFY_REPLACE:
     case MSIMODIFY_MERGE:
     case MSIMODIFY_VALIDATE_NEW:
     case MSIMODIFY_INSERT_TEMPORARY:
     case MSIMODIFY_REFRESH:
     case MSIMODIFY_REPLACE:
     case MSIMODIFY_MERGE:
-    case MSIMODIFY_DELETE:
     case MSIMODIFY_VALIDATE:
     case MSIMODIFY_VALIDATE_FIELD:
     case MSIMODIFY_VALIDATE_DELETE:
     case MSIMODIFY_VALIDATE:
     case MSIMODIFY_VALIDATE_FIELD:
     case MSIMODIFY_VALIDATE_DELETE:
index f4ded7f..99bc431 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "msipriv.h"
 
 
 #include "msipriv.h"
 
+#include <stdio.h>
 #include <propvarutil.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 #include <propvarutil.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
@@ -999,6 +1000,117 @@ end:
     return r;
 }
 
     return r;
 }
 
+static UINT save_prop( MSISUMMARYINFO *si, HANDLE handle, UINT row )
+{
+    static const char fmt_systemtime[] = "%d/%02d/%02d %02d:%02d:%02d";
+    char data[20]; /* largest string: YYYY/MM/DD hh:mm:ss */
+    static const char fmt_begin[] = "%u\t";
+    static const char data_end[] = "\r\n";
+    static const char fmt_int[] = "%u";
+    UINT r, data_type, len;
+    SYSTEMTIME system_time;
+    FILETIME file_time;
+    INT int_value;
+    awstring str;
+    DWORD sz;
+
+    str.unicode = FALSE;
+    str.str.a = NULL;
+    len = 0;
+    r = get_prop( si, row, &data_type, &int_value, &file_time, &str, &len );
+    if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
+        return r;
+    if (data_type == VT_EMPTY)
+        return ERROR_SUCCESS; /* property not set */
+    snprintf( data, sizeof(data), fmt_begin, row );
+    sz = lstrlenA( data );
+    if (!WriteFile( handle, data, sz, &sz, NULL ))
+        return ERROR_WRITE_FAULT;
+
+    switch (data_type)
+    {
+    case VT_I2:
+    case VT_I4:
+        snprintf( data, sizeof(data), fmt_int, int_value );
+        sz = lstrlenA( data );
+        if (!WriteFile( handle, data, sz, &sz, NULL ))
+            return ERROR_WRITE_FAULT;
+        break;
+    case VT_LPSTR:
+        len++;
+        if (!(str.str.a = msi_alloc( len )))
+            return ERROR_OUTOFMEMORY;
+        r = get_prop( si, row, NULL, NULL, NULL, &str, &len );
+        if (r != ERROR_SUCCESS)
+        {
+            msi_free( str.str.a );
+            return r;
+        }
+        sz = lstrlenA( str.str.a );
+        if (!WriteFile( handle, str.str.a, sz, &sz, NULL ))
+        {
+            msi_free( str.str.a );
+            return ERROR_WRITE_FAULT;
+        }
+        msi_free( str.str.a );
+        break;
+    case VT_FILETIME:
+        if (!FileTimeToSystemTime( &file_time, &system_time ))
+            return ERROR_FUNCTION_FAILED;
+        snprintf( data, sizeof(data), fmt_systemtime, system_time.wYear, system_time.wMonth,
+                  system_time.wDay, system_time.wHour, system_time.wMinute,
+                  system_time.wSecond );
+        sz = lstrlenA( data );
+        if (!WriteFile( handle, data, sz, &sz, NULL ))
+            return ERROR_WRITE_FAULT;
+        break;
+    case VT_EMPTY:
+        /* cannot reach here, property not set */
+        break;
+    default:
+        FIXME( "Unknown property variant type\n" );
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    sz = lstrlenA( data_end );
+    if (!WriteFile( handle, data_end, sz, &sz, NULL ))
+        return ERROR_WRITE_FAULT;
+
+    return ERROR_SUCCESS;
+}
+
+UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle )
+{
+    UINT i, r, num_rows;
+    MSISUMMARYINFO *si;
+
+    r = msi_get_suminfo( db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
+        r = msi_get_db_suminfo( db, 0, &si );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    num_rows = get_property_count( si->property );
+    if (!num_rows)
+    {
+        msiobj_release( &si->hdr );
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    for (i = 0; i < num_rows; i++)
+    {
+        r = save_prop( si, handle, i );
+        if (r != ERROR_SUCCESS)
+        {
+            msiobj_release( &si->hdr );
+            return r;
+        }
+    }
+
+    msiobj_release( &si->hdr );
+    return ERROR_SUCCESS;
+}
+
 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
 {
     MSISUMMARYINFO *si;
 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
 {
     MSISUMMARYINFO *si;
index 8c440d5..0b05142 100644 (file)
@@ -792,7 +792,7 @@ UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info,
         /* add each column to the _Columns table */
         r = TABLE_CreateView( db, szColumns, &tv );
         if( r )
         /* add each column to the _Columns table */
         r = TABLE_CreateView( db, szColumns, &tv );
         if( r )
-            return r;
+            goto err;
 
         r = tv->ops->execute( tv, 0 );
         TRACE("tv execute returned %x\n", r);
 
         r = tv->ops->execute( tv, 0 );
         TRACE("tv execute returned %x\n", r);
@@ -2308,8 +2308,7 @@ err:
 }
 
 static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st,
 }
 
 static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st,
-                                            IStorage *stg,
-                                            const BYTE *rawdata, UINT bytes_per_strref )
+                                            IStorage *stg, const BYTE *rawdata, UINT bytes_per_strref )
 {
     UINT i, val, ofs = 0;
     USHORT mask;
 {
     UINT i, val, ofs = 0;
     USHORT mask;
@@ -2342,12 +2341,14 @@ static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string
 
             r = msi_record_encoded_stream_name( tv, rec, &encname );
             if ( r != ERROR_SUCCESS )
 
             r = msi_record_encoded_stream_name( tv, rec, &encname );
             if ( r != ERROR_SUCCESS )
+            {
+                msiobj_release( &rec->hdr );
                 return NULL;
                 return NULL;
-
-            r = IStorage_OpenStream( stg, encname, NULL,
-                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
+            }
+            r = IStorage_OpenStream( stg, encname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
             if ( r != ERROR_SUCCESS )
             {
             if ( r != ERROR_SUCCESS )
             {
+                msiobj_release( &rec->hdr );
                 msi_free( encname );
                 return NULL;
             }
                 msi_free( encname );
                 return NULL;
             }
index df1a961..6cfc0fd 100644 (file)
@@ -115,7 +115,7 @@ reactos/dll/win32/msg711.acm          # Synced to WineStaging-1.7.47
 reactos/dll/win32/msgsm32.acm         # Synced to WineStaging-1.7.47
 reactos/dll/win32/mshtml              # Synced to WineStaging-1.7.37
 reactos/dll/win32/mshtml.tlb          # Synced to WineStaging-1.7.47
 reactos/dll/win32/msgsm32.acm         # Synced to WineStaging-1.7.47
 reactos/dll/win32/mshtml              # Synced to WineStaging-1.7.37
 reactos/dll/win32/mshtml.tlb          # Synced to WineStaging-1.7.47
-reactos/dll/win32/msi                 # Synced to WineStaging-1.7.47
+reactos/dll/win32/msi                 # Synced to WineStaging-1.7.55
 reactos/dll/win32/msimg32             # Synced to WineStaging-1.7.47
 reactos/dll/win32/msimtf              # Synced to WineStaging-1.7.47
 reactos/dll/win32/msisip              # Synced to WineStaging-1.7.47
 reactos/dll/win32/msimg32             # Synced to WineStaging-1.7.47
 reactos/dll/win32/msimtf              # Synced to WineStaging-1.7.47
 reactos/dll/win32/msisip              # Synced to WineStaging-1.7.47