mirror of
https://github.com/reactos/reactos.git
synced 2025-05-07 02:41:22 +00:00
[MSI] Sync with Wine Staging 1.7.37. CORE-9246
svn path=/trunk/; revision=66632
This commit is contained in:
parent
3bce081d61
commit
102b741c7e
19 changed files with 803 additions and 622 deletions
|
@ -2407,7 +2407,6 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
|
|||
sprintfW( buf, fmtW, free.QuadPart / 512 );
|
||||
msi_set_property( package->db, szPrimaryVolumeSpaceAvailable, buf, -1 );
|
||||
}
|
||||
toupperW( primary_folder[0] );
|
||||
msi_set_property( package->db, szPrimaryVolumePath, primary_folder, 2 );
|
||||
}
|
||||
msi_free( primary_folder );
|
||||
|
@ -2422,9 +2421,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
|
|||
return MSI_SetFeatureStates(package);
|
||||
}
|
||||
|
||||
static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type, DWORD *size )
|
||||
static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size )
|
||||
{
|
||||
BYTE *data = NULL;
|
||||
BYTE *data;
|
||||
|
||||
if (!value)
|
||||
{
|
||||
|
@ -2513,19 +2512,18 @@ static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type,
|
|||
else
|
||||
{
|
||||
const WCHAR *ptr = value;
|
||||
DWORD len;
|
||||
|
||||
*type = REG_SZ;
|
||||
if (value[0] == '#')
|
||||
{
|
||||
ptr++;
|
||||
ptr++; len--;
|
||||
if (value[1] == '%')
|
||||
{
|
||||
ptr++;
|
||||
ptr++; len--;
|
||||
*type = REG_EXPAND_SZ;
|
||||
}
|
||||
}
|
||||
len = deformat_string( package, ptr, (WCHAR **)&data );
|
||||
data = (BYTE *)msi_strdupW( ptr, len );
|
||||
if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
|
||||
*size = (len + 1) * sizeof(WCHAR);
|
||||
}
|
||||
|
@ -2574,38 +2572,22 @@ static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key
|
|||
return ret;
|
||||
}
|
||||
|
||||
static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
|
||||
static inline REGSAM get_registry_view( const MSICOMPONENT *comp )
|
||||
{
|
||||
static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
|
||||
static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
|
||||
|
||||
if ((is_64bit || is_wow64) &&
|
||||
!(comp->Attributes & msidbComponentAttributes64bit) &&
|
||||
root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
|
||||
{
|
||||
UINT size;
|
||||
WCHAR *path_32node;
|
||||
|
||||
size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
|
||||
if (!(path_32node = msi_alloc( size ))) return NULL;
|
||||
|
||||
memcpy( path_32node, path, len * sizeof(WCHAR) );
|
||||
strcpyW( path_32node + len, szWow6432Node );
|
||||
strcatW( path_32node, szBackSlash );
|
||||
strcatW( path_32node, path + len );
|
||||
return path_32node;
|
||||
}
|
||||
return strdupW( path );
|
||||
REGSAM view = 0;
|
||||
if (is_wow64 || is_64bit)
|
||||
view |= (comp->Attributes & msidbComponentAttributes64bit) ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
|
||||
return view;
|
||||
}
|
||||
|
||||
static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
|
||||
static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create )
|
||||
{
|
||||
REGSAM access = KEY_ALL_ACCESS;
|
||||
WCHAR *subkey, *p, *q;
|
||||
HKEY hkey, ret = NULL;
|
||||
LONG res;
|
||||
|
||||
if (is_wow64) access |= KEY_WOW64_64KEY;
|
||||
access |= get_registry_view( comp );
|
||||
|
||||
if (!(subkey = strdupW( path ))) return NULL;
|
||||
p = subkey;
|
||||
|
@ -2622,7 +2604,7 @@ static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
|
|||
}
|
||||
if (q && q[1])
|
||||
{
|
||||
ret = open_key( hkey, q + 1, create );
|
||||
ret = open_key( comp, hkey, q + 1, create );
|
||||
RegCloseKey( hkey );
|
||||
}
|
||||
else ret = hkey;
|
||||
|
@ -2803,7 +2785,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
|
|||
BYTE *new_value, *old_value = NULL;
|
||||
HKEY root_key, hkey;
|
||||
DWORD type, old_type, new_size, old_size = 0;
|
||||
LPWSTR deformated, uikey, keypath;
|
||||
LPWSTR deformated, uikey;
|
||||
const WCHAR *szRoot, *component, *name, *key, *str;
|
||||
MSICOMPONENT *comp;
|
||||
MSIRECORD * uirow;
|
||||
|
@ -2847,23 +2829,19 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
|
|||
strcpyW(uikey,szRoot);
|
||||
strcatW(uikey,deformated);
|
||||
|
||||
keypath = get_keypath( comp, root_key, deformated );
|
||||
msi_free( deformated );
|
||||
if (!(hkey = open_key( root_key, keypath, TRUE )))
|
||||
if (!(hkey = open_key( comp, root_key, deformated, TRUE )))
|
||||
{
|
||||
ERR("Could not create key %s\n", debugstr_w(keypath));
|
||||
ERR("Could not create key %s\n", debugstr_w(deformated));
|
||||
msi_free(uikey);
|
||||
msi_free(keypath);
|
||||
msi_free(deformated);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
str = msi_record_get_string( row, 5, &len );
|
||||
if (str && len > strlenW( str ))
|
||||
{
|
||||
type = REG_MULTI_SZ;
|
||||
new_size = (len + 1) * sizeof(WCHAR);
|
||||
new_value = (BYTE *)msi_strdupW( str, len );
|
||||
}
|
||||
else new_value = parse_value( package, str, &type, &new_size );
|
||||
msi_free( deformated );
|
||||
str = msi_record_get_string( row, 5, NULL );
|
||||
len = deformat_string( package, str, &deformated );
|
||||
new_value = parse_value( package, deformated, len, &type, &new_size );
|
||||
|
||||
msi_free( deformated );
|
||||
deformat_string(package, name, &deformated);
|
||||
|
||||
if (!is_special_entry( name ))
|
||||
|
@ -2911,7 +2889,6 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
|
|||
msi_free(old_value);
|
||||
msi_free(deformated);
|
||||
msi_free(uikey);
|
||||
msi_free(keypath);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -2933,20 +2910,20 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void delete_key( HKEY root, const WCHAR *path )
|
||||
static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
|
||||
{
|
||||
REGSAM access = 0;
|
||||
WCHAR *subkey, *p;
|
||||
HKEY hkey;
|
||||
LONG res;
|
||||
|
||||
if (is_wow64) access |= KEY_WOW64_64KEY;
|
||||
access |= get_registry_view( comp );
|
||||
|
||||
if (!(subkey = strdupW( path ))) return;
|
||||
for (;;)
|
||||
{
|
||||
if ((p = strrchrW( subkey, '\\' ))) *p = 0;
|
||||
hkey = open_key( root, subkey, FALSE );
|
||||
hkey = open_key( comp, root, subkey, FALSE );
|
||||
if (!hkey) break;
|
||||
if (p && p[1])
|
||||
res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
|
||||
|
@ -2963,13 +2940,13 @@ static void delete_key( HKEY root, const WCHAR *path )
|
|||
msi_free( subkey );
|
||||
}
|
||||
|
||||
static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
|
||||
static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, const WCHAR *value )
|
||||
{
|
||||
LONG res;
|
||||
HKEY hkey;
|
||||
DWORD num_subkeys, num_values;
|
||||
|
||||
if ((hkey = open_key( root, path, FALSE )))
|
||||
if ((hkey = open_key( comp, root, path, FALSE )))
|
||||
{
|
||||
if ((res = RegDeleteValueW( hkey, value )))
|
||||
TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
|
||||
|
@ -2980,20 +2957,20 @@ static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
|
|||
if (!res && !num_subkeys && !num_values)
|
||||
{
|
||||
TRACE("removing empty key %s\n", debugstr_w(path));
|
||||
delete_key( root, path );
|
||||
delete_key( comp, root, path );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void delete_tree( HKEY root, const WCHAR *path )
|
||||
static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
|
||||
{
|
||||
LONG res;
|
||||
HKEY hkey;
|
||||
|
||||
if (!(hkey = open_key( root, path, FALSE ))) return;
|
||||
if (!(hkey = open_key( comp, root, path, FALSE ))) return;
|
||||
res = SHDeleteKeyW( hkey, NULL );
|
||||
if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
|
||||
delete_key( root, path );
|
||||
delete_key( comp, root, path );
|
||||
RegCloseKey( hkey );
|
||||
}
|
||||
|
||||
|
@ -3001,7 +2978,7 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para
|
|||
{
|
||||
MSIPACKAGE *package = param;
|
||||
LPCWSTR component, name, key_str, root_key_str;
|
||||
LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
|
||||
LPWSTR deformated_key, deformated_name, ui_key_str;
|
||||
MSICOMPONENT *comp;
|
||||
MSIRECORD *uirow;
|
||||
BOOL delete_key = FALSE;
|
||||
|
@ -3050,11 +3027,9 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para
|
|||
|
||||
deformat_string( package, name, &deformated_name );
|
||||
|
||||
keypath = get_keypath( comp, hkey_root, deformated_key );
|
||||
if (delete_key) delete_tree( comp, hkey_root, deformated_key );
|
||||
else delete_value( comp, hkey_root, deformated_key, deformated_name );
|
||||
msi_free( deformated_key );
|
||||
if (delete_key) delete_tree( hkey_root, keypath );
|
||||
else delete_value( hkey_root, keypath, deformated_name );
|
||||
msi_free( keypath );
|
||||
|
||||
uirow = MSI_CreateRecord( 2 );
|
||||
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
||||
|
@ -3071,7 +3046,7 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param
|
|||
{
|
||||
MSIPACKAGE *package = param;
|
||||
LPCWSTR component, name, key_str, root_key_str;
|
||||
LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
|
||||
LPWSTR deformated_key, deformated_name, ui_key_str;
|
||||
MSICOMPONENT *comp;
|
||||
MSIRECORD *uirow;
|
||||
BOOL delete_key = FALSE;
|
||||
|
@ -3115,11 +3090,9 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param
|
|||
|
||||
deformat_string( package, name, &deformated_name );
|
||||
|
||||
keypath = get_keypath( comp, hkey_root, deformated_key );
|
||||
if (delete_key) delete_tree( comp, hkey_root, deformated_key );
|
||||
else delete_value( comp, hkey_root, deformated_key, deformated_name );
|
||||
msi_free( deformated_key );
|
||||
if (delete_key) delete_tree( hkey_root, keypath );
|
||||
else delete_value( hkey_root, keypath, deformated_name );
|
||||
msi_free( keypath );
|
||||
|
||||
uirow = MSI_CreateRecord( 2 );
|
||||
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
||||
|
@ -5300,7 +5273,7 @@ static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
|
|||
WCHAR *remove;
|
||||
|
||||
/* first do the same as an InstallExecute */
|
||||
rc = ACTION_InstallExecute(package);
|
||||
rc = execute_script(package, SCRIPT_INSTALL);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
|
@ -5940,24 +5913,21 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
|
|||
if (!comp)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
event = MSI_RecordGetInteger( rec, 3 );
|
||||
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
||||
|
||||
comp->Action = msi_get_component_action( package, comp );
|
||||
if (comp->Action != INSTALLSTATE_LOCAL)
|
||||
if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStart)) &&
|
||||
!(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStart)))
|
||||
{
|
||||
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
||||
TRACE("not starting %s\n", debugstr_w(name));
|
||||
msi_free( name );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
deformat_string(package, MSI_RecordGetString(rec, 2), &name);
|
||||
deformat_string(package, MSI_RecordGetString(rec, 4), &args);
|
||||
event = MSI_RecordGetInteger(rec, 3);
|
||||
wait = MSI_RecordGetInteger(rec, 5);
|
||||
|
||||
if (!(event & msidbServiceControlEventStart))
|
||||
{
|
||||
r = ERROR_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
|
||||
if (!scm)
|
||||
{
|
||||
|
@ -6147,23 +6117,24 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
|
|||
MSICOMPONENT *comp;
|
||||
MSIRECORD *uirow;
|
||||
LPCWSTR component;
|
||||
LPWSTR name = NULL, display_name = NULL;
|
||||
WCHAR *name, *display_name = NULL;
|
||||
DWORD event, len;
|
||||
SC_HANDLE scm;
|
||||
|
||||
event = MSI_RecordGetInteger( rec, 3 );
|
||||
if (!(event & msidbServiceControlEventStop))
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
component = MSI_RecordGetString( rec, 6 );
|
||||
comp = msi_get_loaded_component( package, component );
|
||||
if (!comp)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
event = MSI_RecordGetInteger( rec, 3 );
|
||||
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
||||
|
||||
comp->Action = msi_get_component_action( package, comp );
|
||||
if (comp->Action != INSTALLSTATE_ABSENT)
|
||||
if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStop)) &&
|
||||
!(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStop)))
|
||||
{
|
||||
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
||||
TRACE("not stopping %s\n", debugstr_w(name));
|
||||
msi_free( name );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -6183,7 +6154,6 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
|
|||
}
|
||||
CloseServiceHandle( scm );
|
||||
|
||||
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
||||
stop_service( name );
|
||||
|
||||
done:
|
||||
|
@ -6982,6 +6952,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
|
|||
data = msi_alloc(size);
|
||||
if (!data)
|
||||
{
|
||||
msi_free(deformatted);
|
||||
RegCloseKey(env);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
@ -7801,10 +7772,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
|
|||
package->full_reinstall = 1;
|
||||
}
|
||||
|
||||
/* properties may have been added by a transform */
|
||||
msi_clone_properties( package );
|
||||
msi_set_original_database_property( package->db, szPackagePath );
|
||||
|
||||
msi_parse_command_line( package, szCommandLine, FALSE );
|
||||
msi_adjust_privilege_properties( package );
|
||||
msi_set_context( package );
|
||||
|
|
|
@ -242,7 +242,7 @@ static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_n
|
|||
memset( &info, 0, sizeof(info) );
|
||||
info.cbAssemblyInfo = sizeof(info);
|
||||
hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &info );
|
||||
if (hr == S_OK /* sxs version */ || hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ))
|
||||
if (hr == S_OK /* sxs version */ || hr == E_NOT_SUFFICIENT_BUFFER)
|
||||
{
|
||||
return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ static enum clr_version get_clr_version( const WCHAR *filename )
|
|||
if (!pGetFileVersion) return CLR_VERSION_V10;
|
||||
|
||||
hr = pGetFileVersion( filename, NULL, 0, &len );
|
||||
if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) return CLR_VERSION_V11;
|
||||
if (hr != E_NOT_SUFFICIENT_BUFFER) return CLR_VERSION_V11;
|
||||
if ((strW = msi_alloc( len * sizeof(WCHAR) )))
|
||||
{
|
||||
hr = pGetFileVersion( filename, strW, len, &len );
|
||||
|
|
|
@ -36,179 +36,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|||
|
||||
#define IS_INTMSIDBOPEN(x) (((ULONG_PTR)(x) >> 16) == 0)
|
||||
|
||||
typedef struct tagMSITRANSFORM {
|
||||
struct list entry;
|
||||
IStorage *stg;
|
||||
} MSITRANSFORM;
|
||||
|
||||
typedef struct tagMSISTREAM {
|
||||
struct list entry;
|
||||
IStorage *stg;
|
||||
IStream *stm;
|
||||
} MSISTREAM;
|
||||
|
||||
static UINT find_open_stream( MSIDATABASE *db, IStorage *stg, LPCWSTR name, IStream **stm )
|
||||
{
|
||||
MSISTREAM *stream;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( stream, &db->streams, MSISTREAM, entry )
|
||||
{
|
||||
HRESULT r;
|
||||
STATSTG stat;
|
||||
|
||||
if (stream->stg != stg) continue;
|
||||
|
||||
r = IStream_Stat( stream->stm, &stat, 0 );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
WARN("failed to stat stream r = %08x!\n", r);
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !strcmpW( name, stat.pwcsName ) )
|
||||
{
|
||||
TRACE("found %s\n", debugstr_w(name));
|
||||
*stm = stream->stm;
|
||||
CoTaskMemFree( stat.pwcsName );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
CoTaskMemFree( stat.pwcsName );
|
||||
}
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
UINT msi_clone_open_stream( MSIDATABASE *db, IStorage *stg, LPCWSTR name, IStream **stm )
|
||||
{
|
||||
IStream *stream;
|
||||
|
||||
if (find_open_stream( db, stg, name, &stream ) == ERROR_SUCCESS)
|
||||
{
|
||||
HRESULT r;
|
||||
LARGE_INTEGER pos;
|
||||
|
||||
r = IStream_Clone( stream, stm );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
WARN("failed to clone stream r = %08x!\n", r);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
pos.QuadPart = 0;
|
||||
r = IStream_Seek( *stm, pos, STREAM_SEEK_SET, NULL );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
IStream_Release( *stm );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
UINT msi_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
|
||||
{
|
||||
HRESULT r;
|
||||
IStorage *stg;
|
||||
WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
|
||||
|
||||
decode_streamname( stname, decoded );
|
||||
TRACE("%s -> %s\n", debugstr_w(stname), debugstr_w(decoded));
|
||||
|
||||
if (msi_clone_open_stream( db, db->storage, stname, stm ) == ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
r = IStorage_OpenStream( db->storage, stname, NULL,
|
||||
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
MSITRANSFORM *transform;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
|
||||
{
|
||||
r = IStorage_OpenStream( transform->stg, stname, NULL,
|
||||
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
|
||||
if (SUCCEEDED(r))
|
||||
{
|
||||
stg = transform->stg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else stg = db->storage;
|
||||
|
||||
if( SUCCEEDED(r) )
|
||||
{
|
||||
MSISTREAM *stream;
|
||||
|
||||
if (!(stream = msi_alloc( sizeof(MSISTREAM) ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
stream->stg = stg;
|
||||
IStorage_AddRef( stg );
|
||||
stream->stm = *stm;
|
||||
IStream_AddRef( *stm );
|
||||
list_add_tail( &db->streams, &stream->entry );
|
||||
}
|
||||
|
||||
return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static void free_transforms( MSIDATABASE *db )
|
||||
{
|
||||
while( !list_empty( &db->transforms ) )
|
||||
{
|
||||
MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
|
||||
MSITRANSFORM, entry );
|
||||
MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ), MSITRANSFORM, entry );
|
||||
list_remove( &t->entry );
|
||||
IStorage_Release( t->stg );
|
||||
msi_free( t );
|
||||
}
|
||||
}
|
||||
|
||||
void msi_destroy_stream( MSIDATABASE *db, const WCHAR *stname )
|
||||
{
|
||||
MSISTREAM *stream, *stream2;
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE( stream, stream2, &db->streams, MSISTREAM, entry )
|
||||
{
|
||||
HRESULT r;
|
||||
STATSTG stat;
|
||||
|
||||
r = IStream_Stat( stream->stm, &stat, 0 );
|
||||
if (FAILED(r))
|
||||
{
|
||||
WARN("failed to stat stream r = %08x\n", r);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmpW( stname, stat.pwcsName ))
|
||||
{
|
||||
TRACE("destroying %s\n", debugstr_w(stname));
|
||||
|
||||
list_remove( &stream->entry );
|
||||
IStream_Release( stream->stm );
|
||||
IStorage_Release( stream->stg );
|
||||
IStorage_DestroyElement( stream->stg, stname );
|
||||
msi_free( stream );
|
||||
CoTaskMemFree( stat.pwcsName );
|
||||
break;
|
||||
}
|
||||
CoTaskMemFree( stat.pwcsName );
|
||||
}
|
||||
}
|
||||
|
||||
static void free_streams( MSIDATABASE *db )
|
||||
{
|
||||
while( !list_empty( &db->streams ) )
|
||||
UINT i;
|
||||
for (i = 0; i < db->num_streams; i++)
|
||||
{
|
||||
MSISTREAM *s = LIST_ENTRY(list_head( &db->streams ), MSISTREAM, entry);
|
||||
list_remove( &s->entry );
|
||||
IStream_Release( s->stm );
|
||||
IStorage_Release( s->stg );
|
||||
msi_free( s );
|
||||
if (db->streams[i].stream) IStream_Release( db->streams[i].stream );
|
||||
}
|
||||
msi_free( db->streams );
|
||||
}
|
||||
|
||||
void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
|
||||
|
@ -219,9 +65,6 @@ void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
|
|||
t->stg = stg;
|
||||
IStorage_AddRef( stg );
|
||||
list_add_head( &db->transforms, &t->entry );
|
||||
|
||||
/* the transform may add or replace streams */
|
||||
free_streams( db );
|
||||
}
|
||||
|
||||
static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
||||
|
@ -229,8 +72,8 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
|||
MSIDATABASE *db = (MSIDATABASE *) arg;
|
||||
|
||||
msi_free(db->path);
|
||||
free_cached_tables( db );
|
||||
free_streams( db );
|
||||
free_cached_tables( db );
|
||||
free_transforms( db );
|
||||
if (db->strings) msi_destroy_stringtable( db->strings );
|
||||
IStorage_Release( db->storage );
|
||||
|
@ -413,7 +256,6 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
|||
db->deletefile = strdupW( szDBPath );
|
||||
list_init( &db->tables );
|
||||
list_init( &db->transforms );
|
||||
list_init( &db->streams );
|
||||
|
||||
db->strings = msi_load_string_table( stg, &db->bytes_per_strref );
|
||||
if( !db->strings )
|
||||
|
|
|
@ -135,7 +135,6 @@ static const WCHAR szVolumeCostList[] = { 'V','o','l','u','m','e','C','o','s','t
|
|||
static const WCHAR szVolumeSelectCombo[] = { 'V','o','l','u','m','e','S','e','l','e','c','t','C','o','m','b','o',0 };
|
||||
static const WCHAR szSelectionDescription[] = {'S','e','l','e','c','t','i','o','n','D','e','s','c','r','i','p','t','i','o','n',0};
|
||||
static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0};
|
||||
static const WCHAR szProperty[] = {'P','r','o','p','e','r','t','y',0};
|
||||
static const WCHAR szHyperLink[] = {'H','y','p','e','r','L','i','n','k',0};
|
||||
|
||||
/* dialog sequencing */
|
||||
|
@ -2152,7 +2151,7 @@ static void msi_dialog_update_pathedit( msi_dialog *dialog, msi_control *control
|
|||
/* FIXME: test when this should fail */
|
||||
static BOOL msi_dialog_verify_path( LPWSTR path )
|
||||
{
|
||||
if ( !lstrlenW( path ) )
|
||||
if ( !path[0] )
|
||||
return FALSE;
|
||||
|
||||
if ( PathIsRelativeW( path ) )
|
||||
|
|
|
@ -216,15 +216,12 @@ static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
|
|||
WARN("failed to encode stream name\n");
|
||||
return -1;
|
||||
}
|
||||
if (msi_clone_open_stream( package_disk.package->db, cab->storage, encoded, &stream ) != ERROR_SUCCESS)
|
||||
hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
|
||||
if (FAILED(hr))
|
||||
{
|
||||
hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("failed to open stream 0x%08x\n", hr);
|
||||
msi_free( encoded );
|
||||
return -1;
|
||||
}
|
||||
WARN("failed to open stream 0x%08x\n", hr);
|
||||
msi_free( encoded );
|
||||
return -1;
|
||||
}
|
||||
msi_free( encoded );
|
||||
return (INT_PTR)stream;
|
||||
|
@ -287,9 +284,6 @@ static UINT CDECL msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi)
|
|||
mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
|
||||
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||
|
||||
if (!mi->first_volume)
|
||||
mi->first_volume = strdupW(mi->volume_label);
|
||||
|
||||
msiobj_release(&row->hdr);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -662,7 +656,6 @@ void msi_free_media_info(MSIMEDIAINFO *mi)
|
|||
msi_free(mi->disk_prompt);
|
||||
msi_free(mi->cabinet);
|
||||
msi_free(mi->volume_label);
|
||||
msi_free(mi->first_volume);
|
||||
msi_free(mi);
|
||||
}
|
||||
|
||||
|
@ -708,9 +701,6 @@ UINT msi_load_media_info(MSIPACKAGE *package, UINT Sequence, MSIMEDIAINFO *mi)
|
|||
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
if (!mi->first_volume)
|
||||
mi->first_volume = strdupW(mi->volume_label);
|
||||
|
||||
msi_set_sourcedir_props(package, FALSE);
|
||||
source_dir = msi_dup_property(package->db, szSourceDir);
|
||||
lstrcpyW(mi->sourcedir, source_dir);
|
||||
|
@ -880,7 +870,7 @@ UINT ready_media( MSIPACKAGE *package, BOOL compressed, MSIMEDIAINFO *mi )
|
|||
}
|
||||
}
|
||||
/* check volume matches, change media if not */
|
||||
if (mi->volume_label && mi->disk_id > 1 && strcmpW( mi->first_volume, mi->volume_label ))
|
||||
if (mi->volume_label && mi->disk_id > 1)
|
||||
{
|
||||
WCHAR *source = msi_dup_property( package->db, szSourceDir );
|
||||
BOOL match = source_matches_volume( mi, source );
|
||||
|
|
|
@ -1738,10 +1738,6 @@ UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
|
|||
datakey = patch;
|
||||
szProperty = szInstalled;
|
||||
}
|
||||
else if (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
|
||||
{
|
||||
datakey = udpatch;
|
||||
}
|
||||
else if (!strcmpW( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
|
||||
!strcmpW( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
|
||||
!strcmpW( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
|
||||
|
@ -4178,6 +4174,92 @@ UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent,
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiProvideComponentA( LPCSTR product, LPCSTR feature, LPCSTR component, DWORD mode, LPSTR buf, LPDWORD buflen )
|
||||
{
|
||||
WCHAR *productW = NULL, *componentW = NULL, *featureW = NULL, *bufW = NULL;
|
||||
UINT r = ERROR_OUTOFMEMORY;
|
||||
DWORD lenW;
|
||||
int len;
|
||||
|
||||
TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_a(product), debugstr_a(component), debugstr_a(feature), mode, buf, buflen);
|
||||
|
||||
if (product && !(productW = strdupAtoW( product ))) goto done;
|
||||
if (feature && !(featureW = strdupAtoW( feature ))) goto done;
|
||||
if (component && !(componentW = strdupAtoW( component ))) goto done;
|
||||
|
||||
r = MsiProvideComponentW( productW, featureW, componentW, mode, NULL, &lenW );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
if (!(bufW = msi_alloc( ++lenW * sizeof(WCHAR) )))
|
||||
{
|
||||
r = ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = MsiProvideComponentW( productW, featureW, componentW, mode, bufW, &lenW );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
len = WideCharToMultiByte( CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
|
||||
if (buf)
|
||||
{
|
||||
if (len > *buflen)
|
||||
r = ERROR_MORE_DATA;
|
||||
else
|
||||
WideCharToMultiByte( CP_ACP, 0, bufW, -1, buf, *buflen, NULL, NULL );
|
||||
}
|
||||
|
||||
*buflen = len - 1;
|
||||
|
||||
done:
|
||||
msi_free( productW );
|
||||
msi_free( featureW );
|
||||
msi_free( componentW );
|
||||
msi_free( bufW );
|
||||
return r;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiProvideComponentW( LPCWSTR product, LPCWSTR feature, LPCWSTR component, DWORD mode, LPWSTR buf, LPDWORD buflen )
|
||||
{
|
||||
INSTALLSTATE state;
|
||||
|
||||
TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_w(product), debugstr_w(component), debugstr_w(feature), mode, buf, buflen);
|
||||
|
||||
state = MsiQueryFeatureStateW( product, feature );
|
||||
TRACE("feature state: %d\n", state);
|
||||
switch (mode)
|
||||
{
|
||||
case INSTALLMODE_NODETECTION:
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("mode %x not implemented\n", mode);
|
||||
return ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
|
||||
state = MsiGetComponentPathW( product, component, buf, buflen );
|
||||
TRACE("component state: %d\n", state);
|
||||
switch (state)
|
||||
{
|
||||
case INSTALLSTATE_INVALIDARG:
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
case INSTALLSTATE_MOREDATA:
|
||||
return ERROR_MORE_DATA;
|
||||
|
||||
case INSTALLSTATE_ADVERTISED:
|
||||
case INSTALLSTATE_LOCAL:
|
||||
case INSTALLSTATE_SOURCE:
|
||||
MsiUseFeatureW( product, feature );
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
default:
|
||||
TRACE("MsiGetComponentPathW returned %d\n", state);
|
||||
return ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiBeginTransactionA [MSI.@]
|
||||
*/
|
||||
|
@ -4224,3 +4306,21 @@ UINT WINAPI Migrate10CachedPackagesW(void* a, void* b, void* c, DWORD d)
|
|||
FIXME("%p,%p,%p,%08x\n", a, b, c, d);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiRemovePatchesA [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiRemovePatchesA(LPCSTR patchlist, LPCSTR product, INSTALLTYPE type, LPCSTR propertylist)
|
||||
{
|
||||
FIXME("(%s %s %d %s\n", debugstr_a(patchlist), debugstr_a(product), type, debugstr_a(propertylist));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiRemovePatchesW [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiRemovePatchesW(LPCWSTR patchlist, LPCWSTR product, INSTALLTYPE type, LPCWSTR propertylist)
|
||||
{
|
||||
FIXME("(%s %s %d %s\n", debugstr_w(patchlist), debugstr_w(product), type, debugstr_w(propertylist));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -84,9 +84,9 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
|
||||
#define WINE_FILEDESCRIPTION_STR "Wine MSI dll"
|
||||
#define WINE_FILENAME_STR "msi.dll"
|
||||
#define WINE_FILEVERSION 4,5,6001,22299
|
||||
#define WINE_FILEVERSION_STR "4.5.6001.22299"
|
||||
#define WINE_PRODUCTVERSION 4,5,6001,22299
|
||||
#define WINE_PRODUCTVERSION_STR "4.5.6001.22299"
|
||||
#define WINE_FILEVERSION 4,5,6001,22308
|
||||
#define WINE_FILEVERSION_STR "4.5.6001.22308"
|
||||
#define WINE_PRODUCTVERSION 4,5,6001,22308
|
||||
#define WINE_PRODUCTVERSION_STR "4.5.6001.22308"
|
||||
|
||||
#include <wine/wine_common_ver.rc>
|
||||
|
|
|
@ -97,10 +97,10 @@
|
|||
101 stub MsiProcessAdvertiseScriptA
|
||||
102 stub MsiProcessAdvertiseScriptW
|
||||
103 stdcall MsiProcessMessage(long long long)
|
||||
104 stub MsiProvideComponentA
|
||||
104 stdcall MsiProvideComponentA(str str str long ptr ptr)
|
||||
105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr)
|
||||
106 stdcall MsiProvideComponentFromDescriptorW(wstr ptr ptr ptr)
|
||||
107 stub MsiProvideComponentW
|
||||
107 stdcall MsiProvideComponentW(wstr wstr wstr long ptr ptr)
|
||||
108 stdcall MsiProvideQualifiedComponentA(str str long ptr ptr)
|
||||
109 stdcall MsiProvideQualifiedComponentW(wstr wstr long ptr ptr)
|
||||
110 stdcall MsiQueryFeatureStateA(str str)
|
||||
|
@ -230,8 +230,8 @@
|
|||
234 stub MsiDeleteUserDataW
|
||||
235 stub Migrate10CachedPackagesA
|
||||
236 stdcall Migrate10CachedPackagesW(ptr ptr ptr long)
|
||||
237 stub MsiRemovePatchesA
|
||||
238 stub MsiRemovePatchesW
|
||||
237 stdcall MsiRemovePatchesA(str str long str)
|
||||
238 stdcall MsiRemovePatchesW(wstr wstr long wstr)
|
||||
239 stdcall MsiApplyMultiplePatchesA(str str str)
|
||||
240 stdcall MsiApplyMultiplePatchesW(wstr wstr wstr)
|
||||
241 stub MsiExtractPatchXMLDataA
|
||||
|
@ -281,9 +281,16 @@
|
|||
285 stdcall MsiBeginTransactionW(wstr long ptr ptr)
|
||||
286 stdcall MsiEndTransaction(long)
|
||||
287 stub MsiJoinTransaction
|
||||
288 stub QueryInstanceCount
|
||||
288 stub MsiSetOfflineContextW
|
||||
289 stdcall MsiEnumComponentsExA(str long long ptr ptr ptr ptr)
|
||||
290 stdcall MsiEnumComponentsExW(wstr long long ptr ptr ptr ptr)
|
||||
291 stdcall MsiEnumClientsExA(str str long long ptr ptr ptr ptr)
|
||||
292 stdcall MsiEnumClientsExW(wstr wstr long long ptr ptr ptr ptr)
|
||||
293 stub MsiGetComponentPathExA
|
||||
294 stub MsiGetComponentPathExW
|
||||
295 stub QueryInstanceCount
|
||||
|
||||
@ stdcall -private DllCanUnloadNow()
|
||||
@ stdcall -private DllGetClassObject(ptr ptr ptr)
|
||||
@ stdcall -private DllRegisterServer()
|
||||
@ stdcall -private DllUnregisterServer()
|
||||
|
||||
|
|
|
@ -94,6 +94,18 @@ struct tagMSIOBJECTHDR
|
|||
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
|
||||
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID 30000
|
||||
|
||||
typedef struct tagMSISTREAM
|
||||
{
|
||||
UINT str_index;
|
||||
IStream *stream;
|
||||
} MSISTREAM;
|
||||
|
||||
typedef struct tagMSITRANSFORM
|
||||
{
|
||||
struct list entry;
|
||||
IStorage *stg;
|
||||
} MSITRANSFORM;
|
||||
|
||||
typedef struct tagMSIDATABASE
|
||||
{
|
||||
MSIOBJECTHDR hdr;
|
||||
|
@ -107,7 +119,9 @@ typedef struct tagMSIDATABASE
|
|||
UINT media_transform_disk_id;
|
||||
struct list tables;
|
||||
struct list transforms;
|
||||
struct list streams;
|
||||
MSISTREAM *streams;
|
||||
UINT num_streams;
|
||||
UINT num_streams_allocated;
|
||||
} MSIDATABASE;
|
||||
|
||||
typedef struct tagMSIVIEW MSIVIEW;
|
||||
|
@ -168,7 +182,6 @@ typedef struct tagMSIMEDIAINFO
|
|||
UINT last_sequence;
|
||||
LPWSTR disk_prompt;
|
||||
LPWSTR cabinet;
|
||||
LPWSTR first_volume;
|
||||
LPWSTR volume_label;
|
||||
BOOL is_continuous;
|
||||
BOOL is_extracted;
|
||||
|
@ -757,6 +770,7 @@ extern void msi_free_handle_table(void) DECLSPEC_HIDDEN;
|
|||
|
||||
extern void free_cached_tables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
|
||||
extern UINT MSI_CommitTables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_commit_streams( MSIDATABASE *db ) DECLSPEC_HIDDEN;
|
||||
|
||||
|
||||
/* string table functions */
|
||||
|
@ -766,7 +780,7 @@ enum StringPersistence
|
|||
StringNonPersistent = 1
|
||||
};
|
||||
|
||||
extern BOOL msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence ) DECLSPEC_HIDDEN;
|
||||
extern BOOL msi_add_string( string_table *st, const WCHAR *data, int len, enum StringPersistence persistence ) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_string2id( const string_table *st, const WCHAR *data, int len, UINT *id ) DECLSPEC_HIDDEN;
|
||||
extern VOID msi_destroy_stringtable( string_table *st ) DECLSPEC_HIDDEN;
|
||||
extern const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len ) DECLSPEC_HIDDEN;
|
||||
|
@ -844,9 +858,7 @@ extern LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) DECLSPEC_HIDDEN;
|
|||
extern BOOL decode_streamname(LPCWSTR in, LPWSTR out) DECLSPEC_HIDDEN;
|
||||
|
||||
/* database internals */
|
||||
extern UINT msi_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** ) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_clone_open_stream( MSIDATABASE *, IStorage *, const WCHAR *, IStream ** ) DECLSPEC_HIDDEN;
|
||||
void msi_destroy_stream( MSIDATABASE *, const WCHAR * ) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_get_stream( MSIDATABASE *, const WCHAR *, IStream ** ) DECLSPEC_HIDDEN;
|
||||
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ) DECLSPEC_HIDDEN;
|
||||
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ) DECLSPEC_HIDDEN;
|
||||
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ) DECLSPEC_HIDDEN;
|
||||
|
@ -879,7 +891,7 @@ extern UINT MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ) DECLSPEC_H
|
|||
extern UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename ) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_clone_properties(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_clone_properties(MSIDATABASE *) DECLSPEC_HIDDEN;
|
||||
extern UINT msi_set_context(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
||||
extern void msi_adjust_privilege_properties(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
||||
extern UINT MSI_GetFeatureCost(MSIPACKAGE *, MSIFEATURE *, MSICOSTTREE, INSTALLSTATE, LPINT) DECLSPEC_HIDDEN;
|
||||
|
@ -955,6 +967,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 enum platform parse_platform( const WCHAR *str ) DECLSPEC_HIDDEN;
|
||||
|
||||
/* undocumented functions */
|
||||
UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
|
||||
|
@ -1173,7 +1186,6 @@ static const WCHAR szX64[] = {'x','6','4',0};
|
|||
static const WCHAR szAMD64[] = {'A','M','D','6','4',0};
|
||||
static const WCHAR szARM[] = {'A','r','m',0};
|
||||
static const WCHAR szWow6432NodeCLSID[] = {'W','o','w','6','4','3','2','N','o','d','e','\\','C','L','S','I','D',0};
|
||||
static const WCHAR szWow6432Node[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
|
||||
static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0};
|
||||
static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0};
|
||||
static const WCHAR szMsiPublishAssemblies[] = {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
|
||||
|
@ -1194,6 +1206,7 @@ static const WCHAR szName[] = {'N','a','m','e',0};
|
|||
static const WCHAR szData[] = {'D','a','t','a',0};
|
||||
static const WCHAR szLangResource[] = {'\\','V','a','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n',0};
|
||||
static const WCHAR szInstallLocation[] = {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
|
||||
static const WCHAR szProperty[] = {'P','r','o','p','e','r','t','y',0};
|
||||
|
||||
/* memory allocation macro functions */
|
||||
static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
|
||||
|
|
|
@ -821,8 +821,13 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
|
|||
|
||||
/* FIXME: lock the database */
|
||||
|
||||
r = MSI_CommitTables( db );
|
||||
if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
|
||||
r = msi_commit_streams( db );
|
||||
if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
|
||||
else
|
||||
{
|
||||
r = MSI_CommitTables( db );
|
||||
if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
|
||||
}
|
||||
|
||||
/* FIXME: unlock the database */
|
||||
|
||||
|
|
|
@ -361,7 +361,7 @@ static UINT create_temp_property_table(MSIPACKAGE *package)
|
|||
return rc;
|
||||
}
|
||||
|
||||
UINT msi_clone_properties(MSIPACKAGE *package)
|
||||
UINT msi_clone_properties( MSIDATABASE *db )
|
||||
{
|
||||
static const WCHAR query_select[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
||||
|
@ -378,7 +378,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
|
|||
MSIQUERY *view_select;
|
||||
UINT rc;
|
||||
|
||||
rc = MSI_DatabaseOpenViewW( package->db, query_select, &view_select );
|
||||
rc = MSI_DatabaseOpenViewW( db, query_select, &view_select );
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
|
@ -399,7 +399,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
|
|||
if (rc != ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
rc = MSI_DatabaseOpenViewW( package->db, query_insert, &view_insert );
|
||||
rc = MSI_DatabaseOpenViewW( db, query_insert, &view_insert );
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
msiobj_release( &rec_select->hdr );
|
||||
|
@ -415,7 +415,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
|
|||
|
||||
TRACE("insert failed, trying update\n");
|
||||
|
||||
rc = MSI_DatabaseOpenViewW( package->db, query_update, &view_update );
|
||||
rc = MSI_DatabaseOpenViewW( db, query_update, &view_update );
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
WARN("open view failed %u\n", rc);
|
||||
|
@ -1150,7 +1150,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
|
|||
package->BaseURL = strdupW( base_url );
|
||||
|
||||
create_temp_property_table( package );
|
||||
msi_clone_properties( package );
|
||||
msi_clone_properties( package->db );
|
||||
msi_adjust_privilege_properties( package );
|
||||
|
||||
package->ProductCode = msi_dup_property( package->db, szProductCode );
|
||||
|
@ -1246,7 +1246,7 @@ UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix )
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static enum platform parse_platform( WCHAR *str )
|
||||
enum platform parse_platform( const WCHAR *str )
|
||||
{
|
||||
if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL;
|
||||
else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64;
|
||||
|
@ -1652,11 +1652,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
|||
}
|
||||
index++;
|
||||
}
|
||||
if (index)
|
||||
{
|
||||
msi_clone_properties( package );
|
||||
msi_adjust_privilege_properties( package );
|
||||
}
|
||||
if (index) msi_adjust_privilege_properties( package );
|
||||
|
||||
r = msi_set_original_database_property( package->db, szPackage );
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
|
|
|
@ -35,57 +35,220 @@ static BOOL match_language( MSIPACKAGE *package, LANGID langid )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
struct transform_desc
|
||||
{
|
||||
WCHAR *product_code_from;
|
||||
WCHAR *product_code_to;
|
||||
WCHAR *version_from;
|
||||
WCHAR *version_to;
|
||||
WCHAR *upgrade_code;
|
||||
};
|
||||
|
||||
static void free_transform_desc( struct transform_desc *desc )
|
||||
{
|
||||
msi_free( desc->product_code_from );
|
||||
msi_free( desc->product_code_to );
|
||||
msi_free( desc->version_from );
|
||||
msi_free( desc->version_to );
|
||||
msi_free( desc->upgrade_code );
|
||||
msi_free( desc );
|
||||
}
|
||||
|
||||
static struct transform_desc *parse_transform_desc( const WCHAR *str )
|
||||
{
|
||||
struct transform_desc *ret;
|
||||
const WCHAR *p = str, *q;
|
||||
UINT len;
|
||||
|
||||
if (!(ret = msi_alloc_zero( sizeof(*ret) ))) return NULL;
|
||||
|
||||
q = strchrW( p, '}' );
|
||||
if (*p != '{' || !q) goto error;
|
||||
|
||||
len = q - p + 1;
|
||||
if (!(ret->product_code_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
|
||||
memcpy( ret->product_code_from, p, len * sizeof(WCHAR) );
|
||||
ret->product_code_from[len] = 0;
|
||||
|
||||
p = q + 1;
|
||||
if (!(q = strchrW( p, ';' ))) goto error;
|
||||
len = q - p;
|
||||
if (!(ret->version_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
|
||||
memcpy( ret->version_from, p, len * sizeof(WCHAR) );
|
||||
ret->version_from[len] = 0;
|
||||
|
||||
p = q + 1;
|
||||
q = strchrW( p, '}' );
|
||||
if (*p != '{' || !q) goto error;
|
||||
|
||||
len = q - p + 1;
|
||||
if (!(ret->product_code_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
|
||||
memcpy( ret->product_code_to, p, len * sizeof(WCHAR) );
|
||||
ret->product_code_to[len] = 0;
|
||||
|
||||
p = q + 1;
|
||||
if (!(q = strchrW( p, ';' ))) goto error;
|
||||
len = q - p;
|
||||
if (!(ret->version_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
|
||||
memcpy( ret->version_to, p, len * sizeof(WCHAR) );
|
||||
ret->version_to[len] = 0;
|
||||
|
||||
p = q + 1;
|
||||
q = strchrW( p, '}' );
|
||||
if (*p != '{' || !q) goto error;
|
||||
|
||||
len = q - p + 1;
|
||||
if (!(ret->upgrade_code = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
|
||||
memcpy( ret->upgrade_code, p, len * sizeof(WCHAR) );
|
||||
ret->upgrade_code[len] = 0;
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
free_transform_desc( ret );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static UINT check_transform_applicable( MSIPACKAGE *package, IStorage *transform )
|
||||
{
|
||||
static const UINT supported_flags =
|
||||
MSITRANSFORM_VALIDATE_PRODUCT | MSITRANSFORM_VALIDATE_LANGUAGE |
|
||||
MSITRANSFORM_VALIDATE_PLATFORM | MSITRANSFORM_VALIDATE_MAJORVERSION |
|
||||
MSITRANSFORM_VALIDATE_MINORVERSION | MSITRANSFORM_VALIDATE_UPGRADECODE;
|
||||
MSISUMMARYINFO *si = MSI_GetSummaryInformationW( transform, 0 );
|
||||
UINT valid_flags = 0, wanted_flags = 0;
|
||||
WCHAR *template, *product, *p;
|
||||
struct transform_desc *desc;
|
||||
|
||||
if (si) wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT );
|
||||
TRACE("validation flags %x\n", wanted_flags);
|
||||
|
||||
if (wanted_flags & ~(MSITRANSFORM_VALIDATE_PRODUCT|MSITRANSFORM_VALIDATE_LANGUAGE))
|
||||
FIXME("unsupported validation flags %x\n", wanted_flags);
|
||||
|
||||
if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT)
|
||||
if (!si)
|
||||
{
|
||||
WCHAR *package_product = msi_dup_property( package->db, szProductCode );
|
||||
WCHAR *transform_product = msi_get_suminfo_product( transform );
|
||||
|
||||
TRACE("package = %s transform = %s\n", debugstr_w(package_product), debugstr_w(transform_product));
|
||||
|
||||
if (!transform_product || strstrW( transform_product, package_product ))
|
||||
{
|
||||
valid_flags |= MSITRANSFORM_VALIDATE_PRODUCT;
|
||||
}
|
||||
msi_free( transform_product );
|
||||
msi_free( package_product );
|
||||
WARN("no summary information!\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT );
|
||||
wanted_flags &= 0xffff; /* mask off error condition flags */
|
||||
TRACE("validation flags 0x%04x\n", wanted_flags);
|
||||
|
||||
if (wanted_flags & ~supported_flags)
|
||||
{
|
||||
FIXME("unsupported validation flags 0x%04x\n", wanted_flags);
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE )))
|
||||
{
|
||||
WARN("no template property!\n");
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
TRACE("template property: %s\n", debugstr_w(template));
|
||||
if (!(product = msi_get_suminfo_product( transform )))
|
||||
{
|
||||
WARN("no product property!\n");
|
||||
msi_free( template );
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
TRACE("product property: %s\n", debugstr_w(product));
|
||||
if (!(desc = parse_transform_desc( product )))
|
||||
{
|
||||
msi_free( template );
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
msi_free( product );
|
||||
|
||||
if (wanted_flags & MSITRANSFORM_VALIDATE_LANGUAGE)
|
||||
{
|
||||
WCHAR *template;
|
||||
const WCHAR *p;
|
||||
|
||||
if (!si)
|
||||
{
|
||||
ERR("no summary information!\n");
|
||||
goto end;
|
||||
}
|
||||
if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE )))
|
||||
{
|
||||
ERR("no template property!\n");
|
||||
goto end;
|
||||
}
|
||||
TRACE("template: %s\n", debugstr_w(template));
|
||||
if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) )))
|
||||
{
|
||||
valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE;
|
||||
}
|
||||
msi_free( template );
|
||||
}
|
||||
if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT)
|
||||
{
|
||||
WCHAR *product_code_installed = msi_dup_property( package->db, szProductCode );
|
||||
|
||||
if (!product_code_installed)
|
||||
{
|
||||
msi_free( template );
|
||||
free_transform_desc( desc );
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_INSTALL_PACKAGE_INVALID;
|
||||
}
|
||||
if (!strcmpW( desc->product_code_from, product_code_installed ))
|
||||
{
|
||||
valid_flags |= MSITRANSFORM_VALIDATE_PRODUCT;
|
||||
}
|
||||
msi_free( product_code_installed );
|
||||
}
|
||||
if (wanted_flags & MSITRANSFORM_VALIDATE_PLATFORM)
|
||||
{
|
||||
if ((p = strchrW( template, ';' )))
|
||||
{
|
||||
*p = 0;
|
||||
if (package->platform == parse_platform( template ))
|
||||
valid_flags |= MSITRANSFORM_VALIDATE_PLATFORM;
|
||||
}
|
||||
}
|
||||
msi_free( template );
|
||||
if (wanted_flags & MSITRANSFORM_VALIDATE_MAJORVERSION)
|
||||
{
|
||||
WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion );
|
||||
DWORD major_installed, minor_installed, major, minor;
|
||||
|
||||
if (!product_version_installed)
|
||||
{
|
||||
free_transform_desc( desc );
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_INSTALL_PACKAGE_INVALID;
|
||||
}
|
||||
msi_parse_version_string( product_version_installed, &major_installed, &minor_installed );
|
||||
msi_parse_version_string( desc->version_from, &major, &minor );
|
||||
|
||||
if (major_installed == major)
|
||||
{
|
||||
valid_flags |= MSITRANSFORM_VALIDATE_MAJORVERSION;
|
||||
wanted_flags &= ~MSITRANSFORM_VALIDATE_MINORVERSION;
|
||||
}
|
||||
msi_free( product_version_installed );
|
||||
}
|
||||
else if (wanted_flags & MSITRANSFORM_VALIDATE_MINORVERSION)
|
||||
{
|
||||
WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion );
|
||||
DWORD major_installed, minor_installed, major, minor;
|
||||
|
||||
if (!product_version_installed)
|
||||
{
|
||||
free_transform_desc( desc );
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_INSTALL_PACKAGE_INVALID;
|
||||
}
|
||||
msi_parse_version_string( product_version_installed, &major_installed, &minor_installed );
|
||||
msi_parse_version_string( desc->version_from, &major, &minor );
|
||||
|
||||
if (major_installed == major && minor_installed == minor)
|
||||
valid_flags |= MSITRANSFORM_VALIDATE_MINORVERSION;
|
||||
msi_free( product_version_installed );
|
||||
}
|
||||
if (wanted_flags & MSITRANSFORM_VALIDATE_UPGRADECODE)
|
||||
{
|
||||
WCHAR *upgrade_code_installed = msi_dup_property( package->db, szUpgradeCode );
|
||||
|
||||
if (!upgrade_code_installed)
|
||||
{
|
||||
free_transform_desc( desc );
|
||||
msiobj_release( &si->hdr );
|
||||
return ERROR_INSTALL_PACKAGE_INVALID;
|
||||
}
|
||||
if (!strcmpW( desc->upgrade_code, upgrade_code_installed ))
|
||||
valid_flags |= MSITRANSFORM_VALIDATE_UPGRADECODE;
|
||||
msi_free( upgrade_code_installed );
|
||||
}
|
||||
|
||||
end:
|
||||
free_transform_desc( desc );
|
||||
msiobj_release( &si->hdr );
|
||||
if (valid_flags & ~wanted_flags) return ERROR_FUNCTION_FAILED;
|
||||
if ((valid_flags & wanted_flags) != wanted_flags) return ERROR_FUNCTION_FAILED;
|
||||
TRACE("applicable transform\n");
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -83,12 +83,6 @@ static const WCHAR szInstallProperties_fmt[] = {
|
|||
'%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
|
||||
'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
|
||||
|
||||
static const WCHAR szInstaller_LocalManaged_fmt[] = {
|
||||
'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
|
||||
'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d','\\','%','s','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
|
||||
|
||||
static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
|
||||
'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
|
||||
'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
||||
|
@ -111,11 +105,6 @@ static const WCHAR szInstaller_Patches[] = {
|
|||
'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\','P','a','t','c','h','e','s',0};
|
||||
|
||||
static const WCHAR szInstaller_Components[] = {
|
||||
'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
|
||||
'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s',0};
|
||||
|
||||
static const WCHAR szInstaller_LocalClassesProducts[] = {
|
||||
'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
|
||||
|
@ -1497,6 +1486,24 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
|
|||
return r;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiEnumClientsExA(LPCSTR component, LPCSTR usersid, DWORD ctx, DWORD index,
|
||||
CHAR installed_product[GUID_SIZE],
|
||||
MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len)
|
||||
{
|
||||
FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid),
|
||||
ctx, index, installed_product, installed_ctx, sid, sid_len);
|
||||
return ERROR_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiEnumClientsExW(LPCWSTR component, LPCWSTR usersid, DWORD ctx, DWORD index,
|
||||
WCHAR installed_product[GUID_SIZE],
|
||||
MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len)
|
||||
{
|
||||
FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid),
|
||||
ctx, index, installed_product, installed_ctx, sid, sid_len);
|
||||
return ERROR_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
|
||||
awstring *lpQualBuf, LPDWORD pcchQual,
|
||||
awstring *lpAppBuf, LPDWORD pcchAppBuf )
|
||||
|
|
|
@ -344,7 +344,7 @@ DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function
|
|||
if (FAILED(hr)) goto done;
|
||||
|
||||
/* Call a function if necessary through the IDispatch interface */
|
||||
if (function != NULL && strlenW(function) > 0) {
|
||||
if (function && function[0]) {
|
||||
TRACE("Calling function %s\n", debugstr_w(function));
|
||||
|
||||
hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch);
|
||||
|
|
|
@ -62,7 +62,7 @@ static STORAGE *create_storage(MSISTORAGESVIEW *sv, LPCWSTR name, IStorage *stg)
|
|||
if (!storage)
|
||||
return NULL;
|
||||
|
||||
storage->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent);
|
||||
storage->str_index = msi_add_string(sv->db->strings, name, -1, StringNonPersistent);
|
||||
storage->storage = stg;
|
||||
|
||||
if (storage->storage)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2007 James Hawkins
|
||||
* Copyright 2015 Hans Leidekker for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -24,56 +25,32 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
|||
|
||||
#define NUM_STREAMS_COLS 2
|
||||
|
||||
typedef struct tabSTREAM
|
||||
{
|
||||
UINT str_index;
|
||||
IStream *stream;
|
||||
} STREAM;
|
||||
|
||||
typedef struct tagMSISTREAMSVIEW
|
||||
{
|
||||
MSIVIEW view;
|
||||
MSIDATABASE *db;
|
||||
STREAM **streams;
|
||||
UINT max_streams;
|
||||
UINT num_rows;
|
||||
UINT row_size;
|
||||
UINT num_cols;
|
||||
} MSISTREAMSVIEW;
|
||||
|
||||
static BOOL streams_set_table_size(MSISTREAMSVIEW *sv, UINT size)
|
||||
static BOOL streams_resize_table( MSIDATABASE *db, UINT size )
|
||||
{
|
||||
if (size >= sv->max_streams)
|
||||
if (!db->num_streams_allocated)
|
||||
{
|
||||
sv->max_streams *= 2;
|
||||
sv->streams = msi_realloc_zero(sv->streams, sv->max_streams * sizeof(STREAM *));
|
||||
if (!sv->streams)
|
||||
return FALSE;
|
||||
if (!(db->streams = msi_alloc_zero( size * sizeof(MSISTREAM) ))) return FALSE;
|
||||
db->num_streams_allocated = size;
|
||||
return TRUE;
|
||||
}
|
||||
while (size >= db->num_streams_allocated)
|
||||
{
|
||||
MSISTREAM *tmp;
|
||||
UINT new_size = db->num_streams_allocated * 2;
|
||||
if (!(tmp = msi_realloc_zero( db->streams, new_size * sizeof(MSISTREAM) ))) return FALSE;
|
||||
db->streams = tmp;
|
||||
db->num_streams_allocated = new_size;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static STREAM *create_stream(MSISTREAMSVIEW *sv, LPCWSTR name, BOOL encoded, IStream *stm)
|
||||
{
|
||||
STREAM *stream;
|
||||
WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
|
||||
|
||||
stream = msi_alloc(sizeof(STREAM));
|
||||
if (!stream)
|
||||
return NULL;
|
||||
|
||||
if (encoded)
|
||||
{
|
||||
decode_streamname(name, decoded);
|
||||
TRACE("stream -> %s %s\n", debugstr_w(name), debugstr_w(decoded));
|
||||
name = decoded;
|
||||
}
|
||||
|
||||
stream->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent);
|
||||
stream->stream = stm;
|
||||
return stream;
|
||||
}
|
||||
|
||||
static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val)
|
||||
{
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
|
@ -83,10 +60,10 @@ static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT
|
|||
if (col != 1)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (row >= sv->num_rows)
|
||||
if (row >= sv->db->num_streams)
|
||||
return ERROR_NO_MORE_ITEMS;
|
||||
|
||||
*val = sv->streams[row]->str_index;
|
||||
*val = sv->db->streams[row].str_index;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -94,14 +71,21 @@ static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT
|
|||
static UINT STREAMS_fetch_stream(struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
|
||||
{
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
LARGE_INTEGER pos;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p, %d, %d, %p)\n", view, row, col, stm);
|
||||
|
||||
if (row >= sv->num_rows)
|
||||
if (row >= sv->db->num_streams)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
IStream_AddRef(sv->streams[row]->stream);
|
||||
*stm = sv->streams[row]->stream;
|
||||
pos.QuadPart = 0;
|
||||
hr = IStream_Seek( sv->db->streams[row].stream, pos, STREAM_SEEK_SET, NULL );
|
||||
if (FAILED( hr ))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
*stm = sv->db->streams[row].stream;
|
||||
IStream_AddRef( *stm );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -118,110 +102,94 @@ static UINT STREAMS_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec
|
|||
static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
|
||||
{
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
STREAM *stream;
|
||||
IStream *stm;
|
||||
STATSTG stat;
|
||||
LPWSTR encname = NULL, name = NULL;
|
||||
USHORT *data = NULL;
|
||||
HRESULT hr;
|
||||
ULONG count;
|
||||
UINT r = ERROR_FUNCTION_FAILED;
|
||||
|
||||
TRACE("(%p, %d, %p, %08x)\n", view, row, rec, mask);
|
||||
|
||||
if (row > sv->num_rows)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if (row > sv->db->num_streams || mask >= (1 << sv->num_cols))
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
r = MSI_RecordGetIStream(rec, 2, &stm);
|
||||
if (mask & 1)
|
||||
{
|
||||
const WCHAR *name = MSI_RecordGetString( rec, 1 );
|
||||
|
||||
if (!name) return ERROR_INVALID_PARAMETER;
|
||||
sv->db->streams[row].str_index = msi_add_string( sv->db->strings, name, -1, StringNonPersistent );
|
||||
}
|
||||
if (mask & 2)
|
||||
{
|
||||
IStream *old, *new;
|
||||
HRESULT hr;
|
||||
UINT r;
|
||||
|
||||
r = MSI_RecordGetIStream( rec, 2, &new );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
old = sv->db->streams[row].stream;
|
||||
hr = IStream_QueryInterface( new, &IID_IStream, (void **)&sv->db->streams[row].stream );
|
||||
if (FAILED( hr ))
|
||||
{
|
||||
IStream_Release( new );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
if (old) IStream_Release( old );
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT streams_find_row( MSISTREAMSVIEW *sv, MSIRECORD *rec, UINT *row )
|
||||
{
|
||||
const WCHAR *str;
|
||||
UINT r, i, id, val;
|
||||
|
||||
str = MSI_RecordGetString( rec, 1 );
|
||||
r = msi_string2id( sv->db->strings, str, -1, &id );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
hr = IStream_Stat(stm, &stat, STATFLAG_NONAME);
|
||||
if (FAILED(hr))
|
||||
for (i = 0; i < sv->db->num_streams; i++)
|
||||
{
|
||||
WARN("failed to stat stream: %08x\n", hr);
|
||||
goto done;
|
||||
STREAMS_fetch_int( &sv->view, i, 1, &val );
|
||||
|
||||
if (val == id)
|
||||
{
|
||||
if (row) *row = i;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat.cbSize.QuadPart >> 32)
|
||||
{
|
||||
WARN("stream too large\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
data = msi_alloc(stat.cbSize.QuadPart);
|
||||
if (!data)
|
||||
goto done;
|
||||
|
||||
hr = IStream_Read(stm, data, stat.cbSize.QuadPart, &count);
|
||||
if (FAILED(hr) || count != stat.cbSize.QuadPart)
|
||||
{
|
||||
WARN("failed to read stream: %08x\n", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
name = strdupW(MSI_RecordGetString(rec, 1));
|
||||
if (!name)
|
||||
{
|
||||
WARN("failed to retrieve stream name\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
encname = encode_streamname(FALSE, name);
|
||||
msi_destroy_stream(sv->db, encname);
|
||||
|
||||
r = write_stream_data(sv->db->storage, name, data, count, FALSE);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
WARN("failed to write stream data: %d\n", r);
|
||||
goto done;
|
||||
}
|
||||
|
||||
stream = create_stream(sv, name, FALSE, NULL);
|
||||
if (!stream)
|
||||
goto done;
|
||||
|
||||
hr = IStorage_OpenStream(sv->db->storage, encname, 0,
|
||||
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("failed to open stream: %08x\n", hr);
|
||||
msi_free(stream);
|
||||
goto done;
|
||||
}
|
||||
|
||||
sv->streams[row] = stream;
|
||||
|
||||
done:
|
||||
msi_free(name);
|
||||
msi_free(data);
|
||||
msi_free(encname);
|
||||
|
||||
IStream_Release(stm);
|
||||
|
||||
return r;
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
|
||||
{
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
UINT i;
|
||||
UINT i, r, num_rows = sv->db->num_streams + 1;
|
||||
|
||||
TRACE("(%p, %p, %d, %d)\n", view, rec, row, temporary);
|
||||
|
||||
if (!streams_set_table_size(sv, ++sv->num_rows))
|
||||
r = streams_find_row( sv, rec, NULL );
|
||||
if (r == ERROR_SUCCESS)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
if (!streams_resize_table( sv->db, num_rows ))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
if (row == -1)
|
||||
row = sv->num_rows - 1;
|
||||
row = num_rows - 1;
|
||||
|
||||
/* shift the rows to make room for the new row */
|
||||
for (i = sv->num_rows - 1; i > row; i--)
|
||||
for (i = num_rows - 1; i > row; i--)
|
||||
{
|
||||
sv->streams[i] = sv->streams[i - 1];
|
||||
sv->db->streams[i] = sv->db->streams[i - 1];
|
||||
}
|
||||
|
||||
return STREAMS_set_row(view, row, rec, 0);
|
||||
r = STREAMS_set_row( view, row, rec, (1 << sv->num_cols) - 1 );
|
||||
if (r == ERROR_SUCCESS)
|
||||
sv->db->num_streams = num_rows;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT STREAMS_delete_row(struct tagMSIVIEW *view, UINT row)
|
||||
|
@ -248,8 +216,8 @@ static UINT STREAMS_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *co
|
|||
|
||||
TRACE("(%p, %p, %p)\n", view, rows, cols);
|
||||
|
||||
if (cols) *cols = NUM_STREAMS_COLS;
|
||||
if (rows) *rows = sv->num_rows;
|
||||
if (cols) *cols = sv->num_cols;
|
||||
if (rows) *rows = sv->db->num_streams;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -257,10 +225,11 @@ static UINT STREAMS_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *co
|
|||
static UINT STREAMS_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
|
||||
UINT *type, BOOL *temporary, LPCWSTR *table_name )
|
||||
{
|
||||
TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary,
|
||||
table_name);
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
|
||||
if (n == 0 || n > NUM_STREAMS_COLS)
|
||||
TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary, table_name);
|
||||
|
||||
if (!n || n > sv->num_cols)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
switch (n)
|
||||
|
@ -280,30 +249,6 @@ static UINT STREAMS_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *n
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT streams_find_row(MSISTREAMSVIEW *sv, MSIRECORD *rec, UINT *row)
|
||||
{
|
||||
LPCWSTR str;
|
||||
UINT r, i, id, data;
|
||||
|
||||
str = MSI_RecordGetString(rec, 1);
|
||||
r = msi_string2id(sv->db->strings, str, -1, &id);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
for (i = 0; i < sv->num_rows; i++)
|
||||
{
|
||||
STREAMS_fetch_int(&sv->view, i, 1, &data);
|
||||
|
||||
if (data == id)
|
||||
{
|
||||
*row = i;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT streams_modify_update(struct tagMSIVIEW *view, MSIRECORD *rec)
|
||||
{
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
|
@ -313,15 +258,15 @@ static UINT streams_modify_update(struct tagMSIVIEW *view, MSIRECORD *rec)
|
|||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
return STREAMS_set_row(view, row, rec, 0);
|
||||
return STREAMS_set_row( view, row, rec, (1 << sv->num_cols) - 1 );
|
||||
}
|
||||
|
||||
static UINT streams_modify_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
|
||||
{
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
UINT r, row;
|
||||
UINT r;
|
||||
|
||||
r = streams_find_row(sv, rec, &row);
|
||||
r = streams_find_row( sv, rec, NULL );
|
||||
if (r == ERROR_SUCCESS)
|
||||
return streams_modify_update(view, rec);
|
||||
|
||||
|
@ -371,23 +316,10 @@ static UINT STREAMS_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRE
|
|||
static UINT STREAMS_delete(struct tagMSIVIEW *view)
|
||||
{
|
||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||
UINT i;
|
||||
|
||||
TRACE("(%p)\n", view);
|
||||
|
||||
for (i = 0; i < sv->num_rows; i++)
|
||||
{
|
||||
if (sv->streams[i])
|
||||
{
|
||||
if (sv->streams[i]->stream)
|
||||
IStream_Release(sv->streams[i]->stream);
|
||||
msi_free(sv->streams[i]);
|
||||
}
|
||||
}
|
||||
|
||||
msi_free(sv->streams);
|
||||
msi_free(sv);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -399,23 +331,22 @@ static UINT STREAMS_find_matching_rows(struct tagMSIVIEW *view, UINT col,
|
|||
|
||||
TRACE("(%p, %d, %d, %p, %p)\n", view, col, val, row, handle);
|
||||
|
||||
if (col == 0 || col > NUM_STREAMS_COLS)
|
||||
if (!col || col > sv->num_cols)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
while (index < sv->num_rows)
|
||||
while (index < sv->db->num_streams)
|
||||
{
|
||||
if (sv->streams[index]->str_index == val)
|
||||
if (sv->db->streams[index].str_index == val)
|
||||
{
|
||||
*row = index;
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
*handle = UlongToPtr(++index);
|
||||
|
||||
if (index > sv->num_rows)
|
||||
if (index > sv->db->num_streams)
|
||||
return ERROR_NO_MORE_ITEMS;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
|
@ -444,107 +375,256 @@ static const MSIVIEWOPS streams_ops =
|
|||
NULL,
|
||||
};
|
||||
|
||||
static INT add_streams_to_table(MSISTREAMSVIEW *sv)
|
||||
static HRESULT open_stream( MSIDATABASE *db, const WCHAR *name, IStream **stream )
|
||||
{
|
||||
IEnumSTATSTG *stgenum = NULL;
|
||||
STATSTG stat;
|
||||
STREAM *stream = NULL;
|
||||
HRESULT hr;
|
||||
UINT r, count = 0, size;
|
||||
LPWSTR encname;
|
||||
|
||||
hr = IStorage_EnumElements(sv->db->storage, 0, NULL, 0, &stgenum);
|
||||
if (FAILED(hr))
|
||||
return -1;
|
||||
|
||||
sv->max_streams = 1;
|
||||
sv->streams = msi_alloc_zero(sizeof(STREAM *));
|
||||
if (!sv->streams)
|
||||
return -1;
|
||||
|
||||
while (TRUE)
|
||||
hr = IStorage_OpenStream( db->storage, name, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, stream );
|
||||
if (FAILED( hr ))
|
||||
{
|
||||
size = 0;
|
||||
hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &size);
|
||||
if (FAILED(hr) || !size)
|
||||
break;
|
||||
MSITRANSFORM *transform;
|
||||
|
||||
if (stat.type != STGTY_STREAM)
|
||||
LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
|
||||
{
|
||||
CoTaskMemFree(stat.pwcsName);
|
||||
continue;
|
||||
hr = IStorage_OpenStream( transform->stg, name, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, stream );
|
||||
if (SUCCEEDED( hr ))
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
static MSISTREAM *find_stream( MSIDATABASE *db, const WCHAR *name )
|
||||
{
|
||||
UINT r, id, i;
|
||||
|
||||
r = msi_string2id( db->strings, name, -1, &id );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < db->num_streams; i++)
|
||||
{
|
||||
if (db->streams[i].str_index == id) return &db->streams[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static UINT append_stream( MSIDATABASE *db, const WCHAR *name, IStream *stream )
|
||||
{
|
||||
WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
|
||||
UINT i = db->num_streams;
|
||||
|
||||
if (!streams_resize_table( db, db->num_streams + 1 ))
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
decode_streamname( name, decoded );
|
||||
db->streams[i].str_index = msi_add_string( db->strings, decoded, -1, StringNonPersistent );
|
||||
db->streams[i].stream = stream;
|
||||
db->num_streams++;
|
||||
|
||||
TRACE("added %s\n", debugstr_w( decoded ));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT load_streams( MSIDATABASE *db )
|
||||
{
|
||||
IEnumSTATSTG *stgenum;
|
||||
STATSTG stat;
|
||||
HRESULT hr;
|
||||
UINT count, r = ERROR_SUCCESS;
|
||||
IStream *stream;
|
||||
|
||||
hr = IStorage_EnumElements( db->storage, 0, NULL, 0, &stgenum );
|
||||
if (FAILED( hr ))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
count = 0;
|
||||
hr = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
|
||||
if (FAILED( hr ) || !count)
|
||||
break;
|
||||
|
||||
/* table streams are not in the _Streams table */
|
||||
if (*stat.pwcsName == 0x4840)
|
||||
if (stat.type != STGTY_STREAM || *stat.pwcsName == 0x4840 ||
|
||||
find_stream( db, stat.pwcsName ))
|
||||
{
|
||||
CoTaskMemFree(stat.pwcsName);
|
||||
CoTaskMemFree( stat.pwcsName );
|
||||
continue;
|
||||
}
|
||||
TRACE("found new stream %s\n", debugstr_w( stat.pwcsName ));
|
||||
|
||||
stream = create_stream(sv, stat.pwcsName, TRUE, NULL);
|
||||
if (!stream)
|
||||
hr = open_stream( db, stat.pwcsName, &stream );
|
||||
if (FAILED( hr ))
|
||||
{
|
||||
count = -1;
|
||||
CoTaskMemFree(stat.pwcsName);
|
||||
ERR("unable to open stream %08x\n", hr);
|
||||
CoTaskMemFree( stat.pwcsName );
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* these streams appear to be unencoded */
|
||||
if (*stat.pwcsName == 0x0005)
|
||||
{
|
||||
r = msi_get_raw_stream(sv->db, stat.pwcsName, &stream->stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
encname = encode_streamname(FALSE, stat.pwcsName);
|
||||
r = msi_get_raw_stream(sv->db, encname, &stream->stream);
|
||||
msi_free(encname);
|
||||
}
|
||||
CoTaskMemFree(stat.pwcsName);
|
||||
|
||||
r = append_stream( db, stat.pwcsName, stream );
|
||||
CoTaskMemFree( stat.pwcsName );
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
WARN("unable to get stream %u\n", r);
|
||||
count = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!streams_set_table_size(sv, ++count))
|
||||
{
|
||||
count = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
sv->streams[count - 1] = stream;
|
||||
}
|
||||
|
||||
IEnumSTATSTG_Release(stgenum);
|
||||
return count;
|
||||
TRACE("loaded %u streams\n", db->num_streams);
|
||||
IEnumSTATSTG_Release( stgenum );
|
||||
return r;
|
||||
}
|
||||
|
||||
UINT msi_get_stream( MSIDATABASE *db, const WCHAR *name, IStream **ret )
|
||||
{
|
||||
MSISTREAM *stream;
|
||||
WCHAR *encname;
|
||||
HRESULT hr;
|
||||
UINT r;
|
||||
|
||||
if ((stream = find_stream( db, name )))
|
||||
{
|
||||
LARGE_INTEGER pos;
|
||||
|
||||
pos.QuadPart = 0;
|
||||
hr = IStream_Seek( stream->stream, pos, STREAM_SEEK_SET, NULL );
|
||||
if (FAILED( hr ))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
*ret = stream->stream;
|
||||
IStream_AddRef( *ret );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (!(encname = encode_streamname( FALSE, name )))
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
hr = open_stream( db, encname, ret );
|
||||
msi_free( encname );
|
||||
if (FAILED( hr ))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = append_stream( db, name, *ret );
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
IStream_Release( *ret );
|
||||
return r;
|
||||
}
|
||||
|
||||
IStream_AddRef( *ret );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view)
|
||||
{
|
||||
MSISTREAMSVIEW *sv;
|
||||
INT rows;
|
||||
UINT r;
|
||||
|
||||
TRACE("(%p, %p)\n", db, view);
|
||||
|
||||
sv = msi_alloc_zero( sizeof(MSISTREAMSVIEW) );
|
||||
if (!sv)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
r = load_streams( db );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
if (!(sv = msi_alloc_zero( sizeof(MSISTREAMSVIEW) )))
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
sv->view.ops = &streams_ops;
|
||||
sv->num_cols = NUM_STREAMS_COLS;
|
||||
sv->db = db;
|
||||
rows = add_streams_to_table(sv);
|
||||
if (rows < 0)
|
||||
{
|
||||
msi_free( sv );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
sv->num_rows = rows;
|
||||
|
||||
*view = (MSIVIEW *)sv;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static HRESULT write_stream( IStream *dst, IStream *src )
|
||||
{
|
||||
HRESULT hr;
|
||||
char buf[4096];
|
||||
STATSTG stat;
|
||||
LARGE_INTEGER pos;
|
||||
UINT count, size;
|
||||
|
||||
hr = IStream_Stat( src, &stat, STATFLAG_NONAME );
|
||||
if (FAILED( hr )) return hr;
|
||||
|
||||
hr = IStream_SetSize( dst, stat.cbSize );
|
||||
if (FAILED( hr )) return hr;
|
||||
|
||||
pos.QuadPart = 0;
|
||||
hr = IStream_Seek( dst, pos, STREAM_SEEK_SET, NULL );
|
||||
if (FAILED( hr )) return hr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size = min( sizeof(buf), stat.cbSize.QuadPart );
|
||||
hr = IStream_Read( src, buf, size, &count );
|
||||
if (FAILED( hr ) || count != size)
|
||||
{
|
||||
WARN("failed to read stream: %08x\n", hr);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
stat.cbSize.QuadPart -= count;
|
||||
if (count)
|
||||
{
|
||||
size = count;
|
||||
hr = IStream_Write( dst, buf, size, &count );
|
||||
if (FAILED( hr ) || count != size)
|
||||
{
|
||||
WARN("failed to write stream: %08x\n", hr);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
if (!stat.cbSize.QuadPart) break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UINT msi_commit_streams( MSIDATABASE *db )
|
||||
{
|
||||
UINT i;
|
||||
const WCHAR *name;
|
||||
WCHAR *encname;
|
||||
IStream *stream;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("got %u streams\n", db->num_streams);
|
||||
|
||||
for (i = 0; i < db->num_streams; i++)
|
||||
{
|
||||
name = msi_string_lookup( db->strings, db->streams[i].str_index, NULL );
|
||||
if (!(encname = encode_streamname( FALSE, name ))) return ERROR_OUTOFMEMORY;
|
||||
|
||||
hr = open_stream( db, encname, &stream );
|
||||
if (FAILED( hr )) /* new stream */
|
||||
{
|
||||
hr = IStorage_CreateStream( db->storage, encname, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stream );
|
||||
if (FAILED( hr ))
|
||||
{
|
||||
ERR("failed to create stream %s (hr = %08x)\n", debugstr_w(encname), hr);
|
||||
msi_free( encname );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
hr = write_stream( stream, db->streams[i].stream );
|
||||
if (FAILED( hr ))
|
||||
{
|
||||
ERR("failed to write stream %s (hr = %08x)\n", debugstr_w(encname), hr);
|
||||
msi_free( encname );
|
||||
IStream_Release( stream );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
hr = IStream_Commit( stream, 0 );
|
||||
IStream_Release( stream );
|
||||
if (FAILED( hr ))
|
||||
{
|
||||
WARN("failed to commit stream %s (hr = %08x)\n", debugstr_w(encname), hr);
|
||||
msi_free( encname );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
msi_free( encname );
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ static void set_st_entry( string_table *st, UINT n, WCHAR *str, int len, USHORT
|
|||
st->freeslot = n + 1;
|
||||
}
|
||||
|
||||
static UINT msi_string2idA( const string_table *st, LPCSTR buffer, UINT *id )
|
||||
static UINT string2id( const string_table *st, const char *buffer, UINT *id )
|
||||
{
|
||||
DWORD sz;
|
||||
UINT r = ERROR_INVALID_PARAMETER;
|
||||
|
@ -241,7 +241,7 @@ static UINT msi_string2idA( const string_table *st, LPCSTR buffer, UINT *id )
|
|||
return r;
|
||||
}
|
||||
|
||||
static int msi_addstring( string_table *st, UINT n, const char *data, UINT len, USHORT refcount, enum StringPersistence persistence )
|
||||
static int add_string( string_table *st, UINT n, const char *data, UINT len, USHORT refcount, enum StringPersistence persistence )
|
||||
{
|
||||
LPWSTR str;
|
||||
int sz;
|
||||
|
@ -256,7 +256,7 @@ static int msi_addstring( string_table *st, UINT n, const char *data, UINT len,
|
|||
}
|
||||
else
|
||||
{
|
||||
if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) )
|
||||
if (string2id( st, data, &n ) == ERROR_SUCCESS)
|
||||
{
|
||||
if (persistence == StringPersistent)
|
||||
st->strings[n].persistent_refcount += refcount;
|
||||
|
@ -287,7 +287,7 @@ static int msi_addstring( string_table *st, UINT n, const char *data, UINT len,
|
|||
return n;
|
||||
}
|
||||
|
||||
int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence )
|
||||
int msi_add_string( string_table *st, const WCHAR *data, int len, enum StringPersistence persistence )
|
||||
{
|
||||
UINT n;
|
||||
LPWSTR str;
|
||||
|
@ -303,9 +303,9 @@ int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcoun
|
|||
if (msi_string2id( st, data, len, &n) == ERROR_SUCCESS )
|
||||
{
|
||||
if (persistence == StringPersistent)
|
||||
st->strings[n].persistent_refcount += refcount;
|
||||
st->strings[n].persistent_refcount++;
|
||||
else
|
||||
st->strings[n].nonpersistent_refcount += refcount;
|
||||
st->strings[n].nonpersistent_refcount++;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,7 @@ int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcoun
|
|||
memcpy( str, data, len*sizeof(WCHAR) );
|
||||
str[len] = 0;
|
||||
|
||||
set_st_entry( st, n, str, len, refcount, persistence );
|
||||
set_st_entry( st, n, str, len, 1, persistence );
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,7 @@ const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len )
|
|||
}
|
||||
|
||||
/*
|
||||
* msi_id2stringA
|
||||
* id2string
|
||||
*
|
||||
* [in] st - pointer to the string table
|
||||
* [in] id - id of the string to retrieve
|
||||
|
@ -356,7 +356,7 @@ const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len )
|
|||
*
|
||||
* Returned string is not nul terminated.
|
||||
*/
|
||||
static UINT msi_id2stringA( const string_table *st, UINT id, LPSTR buffer, UINT *sz )
|
||||
static UINT id2string( const string_table *st, UINT id, char *buffer, UINT *sz )
|
||||
{
|
||||
int len, lenW;
|
||||
const WCHAR *str;
|
||||
|
@ -529,7 +529,7 @@ string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref )
|
|||
break;
|
||||
}
|
||||
|
||||
r = msi_addstring( st, n, data+offset, len, refs, StringPersistent );
|
||||
r = add_string( st, n, data+offset, len, refs, StringPersistent );
|
||||
if( r != n )
|
||||
ERR("Failed to add string %d\n", n );
|
||||
n++;
|
||||
|
@ -599,7 +599,7 @@ UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *byt
|
|||
}
|
||||
|
||||
sz = datasize - used;
|
||||
r = msi_id2stringA( st, i, data+used, &sz );
|
||||
r = id2string( st, i, data+used, &sz );
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
ERR("failed to fetch string\n");
|
||||
|
|
|
@ -88,7 +88,7 @@ static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col,
|
|||
return 2;
|
||||
|
||||
if( (col->type & 0xff) != 4 )
|
||||
ERR("Invalid column size!\n");
|
||||
ERR("Invalid column size %u\n", col->type & 0xff);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
@ -741,8 +741,8 @@ UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info,
|
|||
|
||||
for( i = 0, col = col_info; col; i++, col = col->next )
|
||||
{
|
||||
UINT table_id = msi_addstringW( db->strings, col->table, -1, 1, string_persistence );
|
||||
UINT col_id = msi_addstringW( db->strings, col->column, -1, 1, string_persistence );
|
||||
UINT table_id = msi_add_string( db->strings, col->table, -1, string_persistence );
|
||||
UINT col_id = msi_add_string( db->strings, col->column, -1, string_persistence );
|
||||
|
||||
table->colinfo[ i ].tablename = msi_string_lookup( db->strings, table_id, NULL );
|
||||
table->colinfo[ i ].number = i + 1;
|
||||
|
@ -932,7 +932,7 @@ static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name )
|
|||
UINT size, offset, old_count;
|
||||
UINT n;
|
||||
|
||||
table = find_cached_table( db, name );
|
||||
if (!(table = find_cached_table( db, name ))) return;
|
||||
old_count = table->col_count;
|
||||
msi_free_colinfo( table->colinfo, table->col_count );
|
||||
msi_free( table->colinfo );
|
||||
|
@ -1130,25 +1130,23 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
|
|||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||
UINT r;
|
||||
LPWSTR encname, full_name = NULL;
|
||||
WCHAR *name;
|
||||
|
||||
if( !view->ops->fetch_int )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
r = msi_stream_name( tv, row, &full_name );
|
||||
if ( r != ERROR_SUCCESS )
|
||||
r = msi_stream_name( tv, row, &name );
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("fetching stream, error = %d\n", r);
|
||||
ERR("fetching stream, error = %u\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
encname = encode_streamname( FALSE, full_name );
|
||||
r = msi_get_raw_stream( tv->db, encname, stm );
|
||||
if( r )
|
||||
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
|
||||
r = msi_get_stream( tv->db, name, stm );
|
||||
if (r != ERROR_SUCCESS)
|
||||
ERR("fetching stream %s, error = %u\n", debugstr_w(name), r);
|
||||
|
||||
msi_free( full_name );
|
||||
msi_free( encname );
|
||||
msi_free( name );
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1350,8 +1348,8 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
|
|||
{
|
||||
int len;
|
||||
const WCHAR *sval = msi_record_get_string( rec, i + 1, &len );
|
||||
val = msi_addstringW( tv->db->strings, sval, len, 1,
|
||||
persistent ? StringPersistent : StringNonPersistent );
|
||||
val = msi_add_string( tv->db->strings, sval, len,
|
||||
persistent ? StringPersistent : StringNonPersistent );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2555,6 +2553,12 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
|||
*/
|
||||
sz = 2;
|
||||
num_cols = mask >> 8;
|
||||
if (num_cols > tv->num_cols)
|
||||
{
|
||||
ERR("excess columns in transform: %u > %u\n", num_cols, tv->num_cols);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_cols; i++)
|
||||
{
|
||||
if( (tv->columns[i].type & MSITYPE_STRING) &&
|
||||
|
@ -2612,7 +2616,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
|||
|
||||
/*
|
||||
* Native msi seems writes nul into the Number (2nd) column of
|
||||
* the _Columns table, only when the columns are from a new table
|
||||
* the _Columns table when there are new columns
|
||||
*/
|
||||
if ( number == MSI_NULL_INTEGER )
|
||||
{
|
||||
|
@ -2663,7 +2667,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
|||
WARN("failed to insert row %u\n", r);
|
||||
}
|
||||
|
||||
if (number != MSI_NULL_INTEGER && !strcmpW( name, szColumns ))
|
||||
if (!strcmpW( name, szColumns ))
|
||||
msi_update_table_columns( db, table );
|
||||
|
||||
msiobj_release( &rec->hdr );
|
||||
|
@ -2697,6 +2701,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
|||
string_table *strings;
|
||||
UINT ret = ERROR_FUNCTION_FAILED;
|
||||
UINT bytes_per_strref;
|
||||
BOOL property_update = FALSE;
|
||||
|
||||
TRACE("%p %p\n", db, stg );
|
||||
|
||||
|
@ -2741,6 +2746,8 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
|||
tables = transform;
|
||||
else if (!strcmpW( transform->name, szColumns ) )
|
||||
columns = transform;
|
||||
else if (!strcmpW( transform->name, szProperty ))
|
||||
property_update = TRUE;
|
||||
|
||||
TRACE("transform contains stream %s\n", debugstr_w(name));
|
||||
|
||||
|
@ -2790,7 +2797,10 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
|||
}
|
||||
|
||||
if ( ret == ERROR_SUCCESS )
|
||||
{
|
||||
append_storage_to_db( db, stg );
|
||||
if (property_update) msi_clone_properties( db );
|
||||
}
|
||||
|
||||
end:
|
||||
if ( stgenum )
|
||||
|
|
|
@ -123,7 +123,7 @@ reactos/dll/win32/msg711.acm # Synced to Wine-1.7.27
|
|||
reactos/dll/win32/msgsm32.acm # Synced to Wine-1.7.27
|
||||
reactos/dll/win32/mshtml # Synced to Wine-1.7.27
|
||||
reactos/dll/win32/mshtml.tlb # Synced to Wine-1.7.27
|
||||
reactos/dll/win32/msi # Synced to Wine-1.7.27
|
||||
reactos/dll/win32/msi # Synced to WineStaging-1.7.37
|
||||
reactos/dll/win32/msimg32 # Synced to Wine-1.7.27
|
||||
reactos/dll/win32/msimtf # Synced to Wine-1.7.27
|
||||
reactos/dll/win32/msisip # Synced to Wine-1.7.27
|
||||
|
|
Loading…
Reference in a new issue