[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)
-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
index c1baa82..ea66a4d 100644 (file)
@@ -239,8 +239,7 @@ static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
                 len++;
                 break;
             default:
-                if (!count) in_quotes = FALSE;
-                else in_quotes = TRUE;
+                if (count) in_quotes = TRUE;
                 len++;
                 break;
             }
@@ -261,8 +260,7 @@ static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
                 break;
             default:
                 state = state_token;
-                if (!count) in_quotes = FALSE;
-                else in_quotes = TRUE;
+                if (count) in_quotes = TRUE;
                 len++;
                 break;
             }
@@ -271,6 +269,7 @@ static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
         default: break;
         }
         if (!ignore) *out++ = *p;
+        if (!count) in_quotes = FALSE;
     }
 
 done:
@@ -313,7 +312,7 @@ UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
 
         ptr2 = strchrW( ptr, '=' );
         if (!ptr2) 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));
 }
 
+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[] =
@@ -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 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;
@@ -2426,6 +2443,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     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 )))
@@ -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] == ':')
             {
+                static const WCHAR fmtW[] = {'%','l','u',0};
                 ULARGE_INTEGER free;
+                ULONGLONG required;
+                WCHAR buf[21];
 
                 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 );
                 }
+                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 );
@@ -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 );
 
-    return MSI_SetFeatureStates(package);
+    return ERROR_SUCCESS;
 }
 
 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;
 }
 
-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;
@@ -2641,7 +2665,7 @@ static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BO
     }
     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;
@@ -2866,7 +2890,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     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);
@@ -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;
-    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 );
+            RegCloseKey( hkey );
+        }
         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;
         }
-        if (p && p[1]) RegCloseKey( hkey );
-        else break;
-    }
+    } while (p);
     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;
 
-    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);
@@ -3004,8 +3030,8 @@ static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path
     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 );
@@ -3537,7 +3563,9 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                 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);
@@ -5857,8 +5885,8 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
 
     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);
@@ -6032,8 +6060,8 @@ done:
     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);
@@ -6142,8 +6170,8 @@ static UINT stop_service( LPCWSTR name )
         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;
 }
@@ -6280,8 +6308,8 @@ done:
     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 );
 
@@ -6903,13 +6931,13 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
 {
     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;
-    int action = 0;
+    int action = 0, found = 0;
 
     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;
     }
 
-    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)
@@ -6963,10 +7004,6 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             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)
@@ -6986,15 +7023,14 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             goto done;
         }
 
-        data = msi_alloc(size);
-        if (!data)
+        if (!(p = q = data = msi_alloc( size )))
         {
             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;
 
@@ -7007,20 +7043,28 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             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;
@@ -7028,21 +7072,24 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
 
         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;
         }
 
-        lstrcpyW(ptr, data);
+        strcpyW( p, data );
 
         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));
-    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);
@@ -7084,8 +7131,8 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
 {
     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;
@@ -7122,7 +7169,20 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
     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)
@@ -7134,13 +7194,48 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
     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)
+        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:
@@ -7153,6 +7248,7 @@ done:
 
     if (env) RegCloseKey( env );
     msi_free( deformatted );
+    msi_free( new_value );
     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;
-                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;
@@ -1816,12 +1816,36 @@ static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
                                                 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;
 
-    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;
 }
 
@@ -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;
-            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. */
index 4636eba..1b138eb 100644 (file)
@@ -953,7 +953,7 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
 
         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);
 
@@ -975,7 +975,7 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
             {
                 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)
@@ -1148,7 +1148,7 @@ UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
         }
         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);
 
@@ -1392,7 +1392,7 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
         {
             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);
@@ -1414,7 +1414,7 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
             {
                 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);
index b815b72..281dac2 100644 (file)
@@ -36,6 +36,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 #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 ) )
@@ -763,6 +770,8 @@ static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
     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 );
@@ -901,50 +910,131 @@ end:
     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;
+    BOOL bret;
     DWORD sz;
+    UINT r;
 
-    len = 0x100;
-    buffer = msi_alloc( len );
-    if ( !buffer )
+    sz = 0x100;
+    buffer = msi_alloc( sz );
+    if (!buffer)
         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)
-            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 ))
-        {
-            r = ERROR_FUNCTION_FAILED;
-            break;
-        }
+            return ERROR_FUNCTION_FAILED;
     }
-    msi_free( buffer );
     return r;
 }
 
@@ -968,9 +1058,25 @@ static UINT msi_export_forcecodepage( HANDLE handle, UINT codepage )
     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 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[] = {
@@ -1009,14 +1115,22 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
         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)
     {
+        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)
         {
-            msi_export_record( handle, rec, 1 );
+            msi_export_record( &row_export_info, rec, 1 );
             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)
         {
-            msi_export_record( handle, rec, 1 );
+            msi_export_record( &row_export_info, rec, 1 );
             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 );
-            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 */
-        r = MSI_IterateRecords( view, 0, msi_export_row, handle );
+        r = MSI_IterateRecords( view, 0, msi_export_row, &row_export_info );
         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;
-    style |= WS_GROUP | WS_VSCROLL;
+    style |= WS_GROUP | WS_VSCROLL | WS_TABSTOP;
     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);
-        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 );
index c7124de..d29ffaf 100644 (file)
@@ -4291,6 +4291,17 @@ UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HAND
     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.@]
  */
index 0ea9a27..d48f08b 100644 (file)
 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)
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 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;
 
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
-                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;
 
+    TRACE("%p %s %p %p\n", db, debugstr_w(szName), szValueBuf, pchValueBuf);
+
     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};
 
+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};
@@ -466,7 +470,7 @@ UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
         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)
@@ -517,7 +521,7 @@ UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
 
     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)
@@ -582,7 +586,7 @@ UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
 
     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)
@@ -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 ret;
 
     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);
-    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)
@@ -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;
-    r = SHDeleteKeyW(hkey, comp);
+    r = RegDeleteTreeW(hkey, comp);
     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;
-    r = SHDeleteKeyW(hkey, squished_patch);
+    r = RegDeleteTreeW(hkey, squished_patch);
     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;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     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;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     RegCloseKey(hkey);
     return r;
 }
@@ -927,7 +937,7 @@ UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
 
     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)
@@ -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;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     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;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     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;
-    r = SHDeleteKeyW(hkey, squished_pc);
+    r = RegDeleteTreeW(hkey, squished_pc);
     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)
 {
-    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;
 }
 
@@ -293,12 +314,15 @@ static UINT STREAMS_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRE
         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_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 <stdio.h>
 #include <propvarutil.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
@@ -999,6 +1000,117 @@ end:
     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;
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 )
-            return r;
+            goto err;
 
         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,
-                                            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;
@@ -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 )
+            {
+                msiobj_release( &rec->hdr );
                 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 )
             {
+                msiobj_release( &rec->hdr );
                 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/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