[MSI] Sync with Wine Staging 1.7.55. CORE-10536

svn path=/trunk/; revision=69995
This commit is contained in:
Amine Khaldi 2015-11-21 16:44:38 +00:00
parent 02ab2bf42c
commit 9c595b7465
16 changed files with 536 additions and 138 deletions

View 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

View 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;
res = RegDeleteValueW( env, name );
if (!(new_value = msi_alloc( size ))) goto done;
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;
}

View 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. */

View 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);

View 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 = msi_realloc( buffer, sz + 1 );
if (!p)
break;
len = sz + 1;
buffer = p;
}
sz = len;
r = MSI_RecordGetStringA( row, i, buffer, &sz );
if (r != ERROR_SUCCESS)
break;
char *p;
if (!WriteFile( handle, buffer, sz, &sz, NULL ))
sz++; /* leave room for NULL terminator */
p = msi_realloc( buffer, sz );
if (!p)
{
r = ERROR_FUNCTION_FAILED;
break;
msi_free( buffer );
return ERROR_OUTOFMEMORY;
}
buffer = p;
r = MSI_RecordGetStringA( row, field, buffer, &sz );
if (r != ERROR_SUCCESS)
{
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;
}
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 = 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 );
}

View 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 );

View 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.@]
*/

View file

@ -280,7 +280,7 @@
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)

View 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;

View 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));
}
}

View 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)

View 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;
}

View 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:

View 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;

View 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;
}

View 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