mirror of
https://github.com/reactos/reactos.git
synced 2025-05-07 18:56:48 +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 );
|
sprintfW( buf, fmtW, free.QuadPart / 512 );
|
||||||
msi_set_property( package->db, szPrimaryVolumeSpaceAvailable, buf, -1 );
|
msi_set_property( package->db, szPrimaryVolumeSpaceAvailable, buf, -1 );
|
||||||
}
|
}
|
||||||
toupperW( primary_folder[0] );
|
|
||||||
msi_set_property( package->db, szPrimaryVolumePath, primary_folder, 2 );
|
msi_set_property( package->db, szPrimaryVolumePath, primary_folder, 2 );
|
||||||
}
|
}
|
||||||
msi_free( primary_folder );
|
msi_free( primary_folder );
|
||||||
|
@ -2422,9 +2421,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
|
||||||
return MSI_SetFeatureStates(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)
|
if (!value)
|
||||||
{
|
{
|
||||||
|
@ -2513,19 +2512,18 @@ static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const WCHAR *ptr = value;
|
const WCHAR *ptr = value;
|
||||||
DWORD len;
|
|
||||||
|
|
||||||
*type = REG_SZ;
|
*type = REG_SZ;
|
||||||
if (value[0] == '#')
|
if (value[0] == '#')
|
||||||
{
|
{
|
||||||
ptr++;
|
ptr++; len--;
|
||||||
if (value[1] == '%')
|
if (value[1] == '%')
|
||||||
{
|
{
|
||||||
ptr++;
|
ptr++; len--;
|
||||||
*type = REG_EXPAND_SZ;
|
*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;
|
if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
|
||||||
*size = (len + 1) * sizeof(WCHAR);
|
*size = (len + 1) * sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
|
@ -2574,38 +2572,22 @@ static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key
|
||||||
return ret;
|
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','\\'};
|
REGSAM view = 0;
|
||||||
static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
|
if (is_wow64 || is_64bit)
|
||||||
|
view |= (comp->Attributes & msidbComponentAttributes64bit) ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
|
||||||
if ((is_64bit || is_wow64) &&
|
return view;
|
||||||
!(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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
REGSAM access = KEY_ALL_ACCESS;
|
||||||
WCHAR *subkey, *p, *q;
|
WCHAR *subkey, *p, *q;
|
||||||
HKEY hkey, ret = NULL;
|
HKEY hkey, ret = NULL;
|
||||||
LONG res;
|
LONG res;
|
||||||
|
|
||||||
if (is_wow64) access |= KEY_WOW64_64KEY;
|
access |= get_registry_view( comp );
|
||||||
|
|
||||||
if (!(subkey = strdupW( path ))) return NULL;
|
if (!(subkey = strdupW( path ))) return NULL;
|
||||||
p = subkey;
|
p = subkey;
|
||||||
|
@ -2622,7 +2604,7 @@ static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
|
||||||
}
|
}
|
||||||
if (q && q[1])
|
if (q && q[1])
|
||||||
{
|
{
|
||||||
ret = open_key( hkey, q + 1, create );
|
ret = open_key( comp, hkey, q + 1, create );
|
||||||
RegCloseKey( hkey );
|
RegCloseKey( hkey );
|
||||||
}
|
}
|
||||||
else ret = hkey;
|
else ret = hkey;
|
||||||
|
@ -2803,7 +2785,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
|
||||||
BYTE *new_value, *old_value = NULL;
|
BYTE *new_value, *old_value = NULL;
|
||||||
HKEY root_key, hkey;
|
HKEY root_key, hkey;
|
||||||
DWORD type, old_type, new_size, old_size = 0;
|
DWORD type, old_type, new_size, old_size = 0;
|
||||||
LPWSTR deformated, uikey, keypath;
|
LPWSTR deformated, uikey;
|
||||||
const WCHAR *szRoot, *component, *name, *key, *str;
|
const WCHAR *szRoot, *component, *name, *key, *str;
|
||||||
MSICOMPONENT *comp;
|
MSICOMPONENT *comp;
|
||||||
MSIRECORD * uirow;
|
MSIRECORD * uirow;
|
||||||
|
@ -2847,23 +2829,19 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
|
||||||
strcpyW(uikey,szRoot);
|
strcpyW(uikey,szRoot);
|
||||||
strcatW(uikey,deformated);
|
strcatW(uikey,deformated);
|
||||||
|
|
||||||
keypath = get_keypath( comp, root_key, deformated );
|
if (!(hkey = open_key( comp, root_key, deformated, TRUE )))
|
||||||
msi_free( deformated );
|
|
||||||
if (!(hkey = open_key( root_key, keypath, 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(uikey);
|
||||||
msi_free(keypath);
|
msi_free(deformated);
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
str = msi_record_get_string( row, 5, &len );
|
msi_free( deformated );
|
||||||
if (str && len > strlenW( str ))
|
str = msi_record_get_string( row, 5, NULL );
|
||||||
{
|
len = deformat_string( package, str, &deformated );
|
||||||
type = REG_MULTI_SZ;
|
new_value = parse_value( package, deformated, len, &type, &new_size );
|
||||||
new_size = (len + 1) * sizeof(WCHAR);
|
|
||||||
new_value = (BYTE *)msi_strdupW( str, len );
|
msi_free( deformated );
|
||||||
}
|
|
||||||
else new_value = parse_value( package, str, &type, &new_size );
|
|
||||||
deformat_string(package, name, &deformated);
|
deformat_string(package, name, &deformated);
|
||||||
|
|
||||||
if (!is_special_entry( name ))
|
if (!is_special_entry( name ))
|
||||||
|
@ -2911,7 +2889,6 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
|
||||||
msi_free(old_value);
|
msi_free(old_value);
|
||||||
msi_free(deformated);
|
msi_free(deformated);
|
||||||
msi_free(uikey);
|
msi_free(uikey);
|
||||||
msi_free(keypath);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2933,20 +2910,20 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
|
||||||
return rc;
|
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;
|
REGSAM access = 0;
|
||||||
WCHAR *subkey, *p;
|
WCHAR *subkey, *p;
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
LONG res;
|
LONG res;
|
||||||
|
|
||||||
if (is_wow64) access |= KEY_WOW64_64KEY;
|
access |= get_registry_view( comp );
|
||||||
|
|
||||||
if (!(subkey = strdupW( path ))) return;
|
if (!(subkey = strdupW( path ))) return;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if ((p = strrchrW( subkey, '\\' ))) *p = 0;
|
if ((p = strrchrW( subkey, '\\' ))) *p = 0;
|
||||||
hkey = open_key( root, subkey, FALSE );
|
hkey = open_key( comp, root, subkey, FALSE );
|
||||||
if (!hkey) break;
|
if (!hkey) break;
|
||||||
if (p && p[1])
|
if (p && p[1])
|
||||||
res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
|
res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
|
||||||
|
@ -2963,13 +2940,13 @@ static void delete_key( HKEY root, const WCHAR *path )
|
||||||
msi_free( subkey );
|
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;
|
LONG res;
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
DWORD num_subkeys, num_values;
|
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 )))
|
if ((res = RegDeleteValueW( hkey, value )))
|
||||||
TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
|
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)
|
if (!res && !num_subkeys && !num_values)
|
||||||
{
|
{
|
||||||
TRACE("removing empty key %s\n", debugstr_w(path));
|
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;
|
LONG res;
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
|
|
||||||
if (!(hkey = open_key( root, path, FALSE ))) return;
|
if (!(hkey = open_key( comp, root, path, FALSE ))) return;
|
||||||
res = SHDeleteKeyW( hkey, NULL );
|
res = SHDeleteKeyW( hkey, NULL );
|
||||||
if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
|
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 );
|
RegCloseKey( hkey );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3001,7 +2978,7 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para
|
||||||
{
|
{
|
||||||
MSIPACKAGE *package = param;
|
MSIPACKAGE *package = param;
|
||||||
LPCWSTR component, name, key_str, root_key_str;
|
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;
|
MSICOMPONENT *comp;
|
||||||
MSIRECORD *uirow;
|
MSIRECORD *uirow;
|
||||||
BOOL delete_key = FALSE;
|
BOOL delete_key = FALSE;
|
||||||
|
@ -3050,11 +3027,9 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para
|
||||||
|
|
||||||
deformat_string( package, name, &deformated_name );
|
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 );
|
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 );
|
uirow = MSI_CreateRecord( 2 );
|
||||||
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
||||||
|
@ -3071,7 +3046,7 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param
|
||||||
{
|
{
|
||||||
MSIPACKAGE *package = param;
|
MSIPACKAGE *package = param;
|
||||||
LPCWSTR component, name, key_str, root_key_str;
|
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;
|
MSICOMPONENT *comp;
|
||||||
MSIRECORD *uirow;
|
MSIRECORD *uirow;
|
||||||
BOOL delete_key = FALSE;
|
BOOL delete_key = FALSE;
|
||||||
|
@ -3115,11 +3090,9 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param
|
||||||
|
|
||||||
deformat_string( package, name, &deformated_name );
|
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 );
|
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 );
|
uirow = MSI_CreateRecord( 2 );
|
||||||
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
||||||
|
@ -5300,7 +5273,7 @@ static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
|
||||||
WCHAR *remove;
|
WCHAR *remove;
|
||||||
|
|
||||||
/* first do the same as an InstallExecute */
|
/* first do the same as an InstallExecute */
|
||||||
rc = ACTION_InstallExecute(package);
|
rc = execute_script(package, SCRIPT_INSTALL);
|
||||||
if (rc != ERROR_SUCCESS)
|
if (rc != ERROR_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -5940,24 +5913,21 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
|
||||||
if (!comp)
|
if (!comp)
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
|
event = MSI_RecordGetInteger( rec, 3 );
|
||||||
|
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
||||||
|
|
||||||
comp->Action = msi_get_component_action( package, comp );
|
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;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
deformat_string(package, MSI_RecordGetString(rec, 2), &name);
|
|
||||||
deformat_string(package, MSI_RecordGetString(rec, 4), &args);
|
deformat_string(package, MSI_RecordGetString(rec, 4), &args);
|
||||||
event = MSI_RecordGetInteger(rec, 3);
|
|
||||||
wait = MSI_RecordGetInteger(rec, 5);
|
wait = MSI_RecordGetInteger(rec, 5);
|
||||||
|
|
||||||
if (!(event & msidbServiceControlEventStart))
|
|
||||||
{
|
|
||||||
r = ERROR_SUCCESS;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
|
scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
|
||||||
if (!scm)
|
if (!scm)
|
||||||
{
|
{
|
||||||
|
@ -6147,23 +6117,24 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
|
||||||
MSICOMPONENT *comp;
|
MSICOMPONENT *comp;
|
||||||
MSIRECORD *uirow;
|
MSIRECORD *uirow;
|
||||||
LPCWSTR component;
|
LPCWSTR component;
|
||||||
LPWSTR name = NULL, display_name = NULL;
|
WCHAR *name, *display_name = NULL;
|
||||||
DWORD event, len;
|
DWORD event, len;
|
||||||
SC_HANDLE scm;
|
SC_HANDLE scm;
|
||||||
|
|
||||||
event = MSI_RecordGetInteger( rec, 3 );
|
|
||||||
if (!(event & msidbServiceControlEventStop))
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
|
|
||||||
component = MSI_RecordGetString( rec, 6 );
|
component = MSI_RecordGetString( rec, 6 );
|
||||||
comp = msi_get_loaded_component( package, component );
|
comp = msi_get_loaded_component( package, component );
|
||||||
if (!comp)
|
if (!comp)
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
|
event = MSI_RecordGetInteger( rec, 3 );
|
||||||
|
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
||||||
|
|
||||||
comp->Action = msi_get_component_action( package, comp );
|
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;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6183,7 +6154,6 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
|
||||||
}
|
}
|
||||||
CloseServiceHandle( scm );
|
CloseServiceHandle( scm );
|
||||||
|
|
||||||
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
|
||||||
stop_service( name );
|
stop_service( name );
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -6982,6 +6952,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
|
||||||
data = msi_alloc(size);
|
data = msi_alloc(size);
|
||||||
if (!data)
|
if (!data)
|
||||||
{
|
{
|
||||||
|
msi_free(deformatted);
|
||||||
RegCloseKey(env);
|
RegCloseKey(env);
|
||||||
return ERROR_OUTOFMEMORY;
|
return ERROR_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
@ -7801,10 +7772,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
|
||||||
package->full_reinstall = 1;
|
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_set_original_database_property( package->db, szPackagePath );
|
||||||
|
|
||||||
msi_parse_command_line( package, szCommandLine, FALSE );
|
msi_parse_command_line( package, szCommandLine, FALSE );
|
||||||
msi_adjust_privilege_properties( package );
|
msi_adjust_privilege_properties( package );
|
||||||
msi_set_context( 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) );
|
memset( &info, 0, sizeof(info) );
|
||||||
info.cbAssemblyInfo = sizeof(info);
|
info.cbAssemblyInfo = sizeof(info);
|
||||||
hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &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);
|
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;
|
if (!pGetFileVersion) return CLR_VERSION_V10;
|
||||||
|
|
||||||
hr = pGetFileVersion( filename, NULL, 0, &len );
|
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) )))
|
if ((strW = msi_alloc( len * sizeof(WCHAR) )))
|
||||||
{
|
{
|
||||||
hr = pGetFileVersion( filename, strW, len, &len );
|
hr = pGetFileVersion( filename, strW, len, &len );
|
||||||
|
|
|
@ -36,179 +36,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||||
|
|
||||||
#define IS_INTMSIDBOPEN(x) (((ULONG_PTR)(x) >> 16) == 0)
|
#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 )
|
static void free_transforms( MSIDATABASE *db )
|
||||||
{
|
{
|
||||||
while( !list_empty( &db->transforms ) )
|
while( !list_empty( &db->transforms ) )
|
||||||
{
|
{
|
||||||
MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
|
MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ), MSITRANSFORM, entry );
|
||||||
MSITRANSFORM, entry );
|
|
||||||
list_remove( &t->entry );
|
list_remove( &t->entry );
|
||||||
IStorage_Release( t->stg );
|
IStorage_Release( t->stg );
|
||||||
msi_free( t );
|
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 )
|
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);
|
if (db->streams[i].stream) IStream_Release( db->streams[i].stream );
|
||||||
list_remove( &s->entry );
|
|
||||||
IStream_Release( s->stm );
|
|
||||||
IStorage_Release( s->stg );
|
|
||||||
msi_free( s );
|
|
||||||
}
|
}
|
||||||
|
msi_free( db->streams );
|
||||||
}
|
}
|
||||||
|
|
||||||
void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
|
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;
|
t->stg = stg;
|
||||||
IStorage_AddRef( stg );
|
IStorage_AddRef( stg );
|
||||||
list_add_head( &db->transforms, &t->entry );
|
list_add_head( &db->transforms, &t->entry );
|
||||||
|
|
||||||
/* the transform may add or replace streams */
|
|
||||||
free_streams( db );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
||||||
|
@ -229,8 +72,8 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
||||||
MSIDATABASE *db = (MSIDATABASE *) arg;
|
MSIDATABASE *db = (MSIDATABASE *) arg;
|
||||||
|
|
||||||
msi_free(db->path);
|
msi_free(db->path);
|
||||||
free_cached_tables( db );
|
|
||||||
free_streams( db );
|
free_streams( db );
|
||||||
|
free_cached_tables( db );
|
||||||
free_transforms( db );
|
free_transforms( db );
|
||||||
if (db->strings) msi_destroy_stringtable( db->strings );
|
if (db->strings) msi_destroy_stringtable( db->strings );
|
||||||
IStorage_Release( db->storage );
|
IStorage_Release( db->storage );
|
||||||
|
@ -413,7 +256,6 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
||||||
db->deletefile = strdupW( szDBPath );
|
db->deletefile = strdupW( szDBPath );
|
||||||
list_init( &db->tables );
|
list_init( &db->tables );
|
||||||
list_init( &db->transforms );
|
list_init( &db->transforms );
|
||||||
list_init( &db->streams );
|
|
||||||
|
|
||||||
db->strings = msi_load_string_table( stg, &db->bytes_per_strref );
|
db->strings = msi_load_string_table( stg, &db->bytes_per_strref );
|
||||||
if( !db->strings )
|
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 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 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 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};
|
static const WCHAR szHyperLink[] = {'H','y','p','e','r','L','i','n','k',0};
|
||||||
|
|
||||||
/* dialog sequencing */
|
/* dialog sequencing */
|
||||||
|
@ -2152,7 +2151,7 @@ static void msi_dialog_update_pathedit( msi_dialog *dialog, msi_control *control
|
||||||
/* FIXME: test when this should fail */
|
/* FIXME: test when this should fail */
|
||||||
static BOOL msi_dialog_verify_path( LPWSTR path )
|
static BOOL msi_dialog_verify_path( LPWSTR path )
|
||||||
{
|
{
|
||||||
if ( !lstrlenW( path ) )
|
if ( !path[0] )
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if ( PathIsRelativeW( path ) )
|
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");
|
WARN("failed to encode stream name\n");
|
||||||
return -1;
|
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 );
|
WARN("failed to open stream 0x%08x\n", hr);
|
||||||
if (FAILED(hr))
|
msi_free( encoded );
|
||||||
{
|
return -1;
|
||||||
WARN("failed to open stream 0x%08x\n", hr);
|
|
||||||
msi_free( encoded );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
msi_free( encoded );
|
msi_free( encoded );
|
||||||
return (INT_PTR)stream;
|
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->cabinet = strdupW(MSI_RecordGetString(row, 4));
|
||||||
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||||
|
|
||||||
if (!mi->first_volume)
|
|
||||||
mi->first_volume = strdupW(mi->volume_label);
|
|
||||||
|
|
||||||
msiobj_release(&row->hdr);
|
msiobj_release(&row->hdr);
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -662,7 +656,6 @@ void msi_free_media_info(MSIMEDIAINFO *mi)
|
||||||
msi_free(mi->disk_prompt);
|
msi_free(mi->disk_prompt);
|
||||||
msi_free(mi->cabinet);
|
msi_free(mi->cabinet);
|
||||||
msi_free(mi->volume_label);
|
msi_free(mi->volume_label);
|
||||||
msi_free(mi->first_volume);
|
|
||||||
msi_free(mi);
|
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));
|
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||||
msiobj_release(&row->hdr);
|
msiobj_release(&row->hdr);
|
||||||
|
|
||||||
if (!mi->first_volume)
|
|
||||||
mi->first_volume = strdupW(mi->volume_label);
|
|
||||||
|
|
||||||
msi_set_sourcedir_props(package, FALSE);
|
msi_set_sourcedir_props(package, FALSE);
|
||||||
source_dir = msi_dup_property(package->db, szSourceDir);
|
source_dir = msi_dup_property(package->db, szSourceDir);
|
||||||
lstrcpyW(mi->sourcedir, source_dir);
|
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 */
|
/* 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 );
|
WCHAR *source = msi_dup_property( package->db, szSourceDir );
|
||||||
BOOL match = source_matches_volume( mi, source );
|
BOOL match = source_matches_volume( mi, source );
|
||||||
|
|
|
@ -1738,10 +1738,6 @@ UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
|
||||||
datakey = patch;
|
datakey = patch;
|
||||||
szProperty = szInstalled;
|
szProperty = szInstalled;
|
||||||
}
|
}
|
||||||
else if (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
|
|
||||||
{
|
|
||||||
datakey = udpatch;
|
|
||||||
}
|
|
||||||
else if (!strcmpW( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
|
else if (!strcmpW( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
|
||||||
!strcmpW( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
|
!strcmpW( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
|
||||||
!strcmpW( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
|
!strcmpW( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
|
||||||
|
@ -4178,6 +4174,92 @@ UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent,
|
||||||
return ERROR_SUCCESS;
|
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.@]
|
* 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);
|
FIXME("%p,%p,%p,%08x\n", a, b, c, d);
|
||||||
return ERROR_SUCCESS;
|
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_FILEDESCRIPTION_STR "Wine MSI dll"
|
||||||
#define WINE_FILENAME_STR "msi.dll"
|
#define WINE_FILENAME_STR "msi.dll"
|
||||||
#define WINE_FILEVERSION 4,5,6001,22299
|
#define WINE_FILEVERSION 4,5,6001,22308
|
||||||
#define WINE_FILEVERSION_STR "4.5.6001.22299"
|
#define WINE_FILEVERSION_STR "4.5.6001.22308"
|
||||||
#define WINE_PRODUCTVERSION 4,5,6001,22299
|
#define WINE_PRODUCTVERSION 4,5,6001,22308
|
||||||
#define WINE_PRODUCTVERSION_STR "4.5.6001.22299"
|
#define WINE_PRODUCTVERSION_STR "4.5.6001.22308"
|
||||||
|
|
||||||
#include <wine/wine_common_ver.rc>
|
#include <wine/wine_common_ver.rc>
|
||||||
|
|
|
@ -97,10 +97,10 @@
|
||||||
101 stub MsiProcessAdvertiseScriptA
|
101 stub MsiProcessAdvertiseScriptA
|
||||||
102 stub MsiProcessAdvertiseScriptW
|
102 stub MsiProcessAdvertiseScriptW
|
||||||
103 stdcall MsiProcessMessage(long long long)
|
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)
|
105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr)
|
||||||
106 stdcall MsiProvideComponentFromDescriptorW(wstr 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)
|
108 stdcall MsiProvideQualifiedComponentA(str str long ptr ptr)
|
||||||
109 stdcall MsiProvideQualifiedComponentW(wstr wstr long ptr ptr)
|
109 stdcall MsiProvideQualifiedComponentW(wstr wstr long ptr ptr)
|
||||||
110 stdcall MsiQueryFeatureStateA(str str)
|
110 stdcall MsiQueryFeatureStateA(str str)
|
||||||
|
@ -230,8 +230,8 @@
|
||||||
234 stub MsiDeleteUserDataW
|
234 stub MsiDeleteUserDataW
|
||||||
235 stub Migrate10CachedPackagesA
|
235 stub Migrate10CachedPackagesA
|
||||||
236 stdcall Migrate10CachedPackagesW(ptr ptr ptr long)
|
236 stdcall Migrate10CachedPackagesW(ptr ptr ptr long)
|
||||||
237 stub MsiRemovePatchesA
|
237 stdcall MsiRemovePatchesA(str str long str)
|
||||||
238 stub MsiRemovePatchesW
|
238 stdcall MsiRemovePatchesW(wstr wstr long wstr)
|
||||||
239 stdcall MsiApplyMultiplePatchesA(str str str)
|
239 stdcall MsiApplyMultiplePatchesA(str str str)
|
||||||
240 stdcall MsiApplyMultiplePatchesW(wstr wstr wstr)
|
240 stdcall MsiApplyMultiplePatchesW(wstr wstr wstr)
|
||||||
241 stub MsiExtractPatchXMLDataA
|
241 stub MsiExtractPatchXMLDataA
|
||||||
|
@ -281,9 +281,16 @@
|
||||||
285 stdcall MsiBeginTransactionW(wstr long ptr ptr)
|
285 stdcall MsiBeginTransactionW(wstr long ptr ptr)
|
||||||
286 stdcall MsiEndTransaction(long)
|
286 stdcall MsiEndTransaction(long)
|
||||||
287 stub MsiJoinTransaction
|
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 DllCanUnloadNow()
|
||||||
@ stdcall -private DllGetClassObject(ptr ptr ptr)
|
@ stdcall -private DllGetClassObject(ptr ptr ptr)
|
||||||
@ stdcall -private DllRegisterServer()
|
@ stdcall -private DllRegisterServer()
|
||||||
@ stdcall -private DllUnregisterServer()
|
@ stdcall -private DllUnregisterServer()
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,18 @@ struct tagMSIOBJECTHDR
|
||||||
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
|
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
|
||||||
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID 30000
|
#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
|
typedef struct tagMSIDATABASE
|
||||||
{
|
{
|
||||||
MSIOBJECTHDR hdr;
|
MSIOBJECTHDR hdr;
|
||||||
|
@ -107,7 +119,9 @@ typedef struct tagMSIDATABASE
|
||||||
UINT media_transform_disk_id;
|
UINT media_transform_disk_id;
|
||||||
struct list tables;
|
struct list tables;
|
||||||
struct list transforms;
|
struct list transforms;
|
||||||
struct list streams;
|
MSISTREAM *streams;
|
||||||
|
UINT num_streams;
|
||||||
|
UINT num_streams_allocated;
|
||||||
} MSIDATABASE;
|
} MSIDATABASE;
|
||||||
|
|
||||||
typedef struct tagMSIVIEW MSIVIEW;
|
typedef struct tagMSIVIEW MSIVIEW;
|
||||||
|
@ -168,7 +182,6 @@ typedef struct tagMSIMEDIAINFO
|
||||||
UINT last_sequence;
|
UINT last_sequence;
|
||||||
LPWSTR disk_prompt;
|
LPWSTR disk_prompt;
|
||||||
LPWSTR cabinet;
|
LPWSTR cabinet;
|
||||||
LPWSTR first_volume;
|
|
||||||
LPWSTR volume_label;
|
LPWSTR volume_label;
|
||||||
BOOL is_continuous;
|
BOOL is_continuous;
|
||||||
BOOL is_extracted;
|
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 void free_cached_tables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
|
||||||
extern UINT MSI_CommitTables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
|
extern UINT MSI_CommitTables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
|
||||||
|
extern UINT msi_commit_streams( MSIDATABASE *db ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
||||||
/* string table functions */
|
/* string table functions */
|
||||||
|
@ -766,7 +780,7 @@ enum StringPersistence
|
||||||
StringNonPersistent = 1
|
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 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 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;
|
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;
|
extern BOOL decode_streamname(LPCWSTR in, LPWSTR out) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
/* database internals */
|
/* database internals */
|
||||||
extern UINT msi_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** ) DECLSPEC_HIDDEN;
|
extern UINT msi_get_stream( MSIDATABASE *, const WCHAR *, 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_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ) DECLSPEC_HIDDEN;
|
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ) DECLSPEC_HIDDEN;
|
||||||
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ) DECLSPEC_HIDDEN;
|
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ) DECLSPEC_HIDDEN;
|
||||||
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ) 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_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_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_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 UINT msi_set_context(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
||||||
extern void msi_adjust_privilege_properties(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
extern void msi_adjust_privilege_properties(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
||||||
extern UINT MSI_GetFeatureCost(MSIPACKAGE *, MSIFEATURE *, MSICOSTTREE, INSTALLSTATE, LPINT) 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 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN;
|
||||||
extern LPWSTR msi_get_suminfo_product( IStorage *stg ) 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_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 */
|
/* undocumented functions */
|
||||||
UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
|
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 szAMD64[] = {'A','M','D','6','4',0};
|
||||||
static const WCHAR szARM[] = {'A','r','m',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 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 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 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};
|
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 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 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 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 */
|
/* memory allocation macro functions */
|
||||||
static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
|
static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
|
||||||
|
|
|
@ -821,8 +821,13 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
|
||||||
|
|
||||||
/* FIXME: lock the database */
|
/* FIXME: lock the database */
|
||||||
|
|
||||||
r = MSI_CommitTables( db );
|
r = msi_commit_streams( db );
|
||||||
if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
|
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 */
|
/* FIXME: unlock the database */
|
||||||
|
|
||||||
|
|
|
@ -361,7 +361,7 @@ static UINT create_temp_property_table(MSIPACKAGE *package)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT msi_clone_properties(MSIPACKAGE *package)
|
UINT msi_clone_properties( MSIDATABASE *db )
|
||||||
{
|
{
|
||||||
static const WCHAR query_select[] = {
|
static const WCHAR query_select[] = {
|
||||||
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
||||||
|
@ -378,7 +378,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
|
||||||
MSIQUERY *view_select;
|
MSIQUERY *view_select;
|
||||||
UINT rc;
|
UINT rc;
|
||||||
|
|
||||||
rc = MSI_DatabaseOpenViewW( package->db, query_select, &view_select );
|
rc = MSI_DatabaseOpenViewW( db, query_select, &view_select );
|
||||||
if (rc != ERROR_SUCCESS)
|
if (rc != ERROR_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -399,7 +399,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
|
||||||
if (rc != ERROR_SUCCESS)
|
if (rc != ERROR_SUCCESS)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
rc = MSI_DatabaseOpenViewW( package->db, query_insert, &view_insert );
|
rc = MSI_DatabaseOpenViewW( db, query_insert, &view_insert );
|
||||||
if (rc != ERROR_SUCCESS)
|
if (rc != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
msiobj_release( &rec_select->hdr );
|
msiobj_release( &rec_select->hdr );
|
||||||
|
@ -415,7 +415,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
|
||||||
|
|
||||||
TRACE("insert failed, trying update\n");
|
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)
|
if (rc != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
WARN("open view failed %u\n", rc);
|
WARN("open view failed %u\n", rc);
|
||||||
|
@ -1150,7 +1150,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
|
||||||
package->BaseURL = strdupW( base_url );
|
package->BaseURL = strdupW( base_url );
|
||||||
|
|
||||||
create_temp_property_table( package );
|
create_temp_property_table( package );
|
||||||
msi_clone_properties( package );
|
msi_clone_properties( package->db );
|
||||||
msi_adjust_privilege_properties( package );
|
msi_adjust_privilege_properties( package );
|
||||||
|
|
||||||
package->ProductCode = msi_dup_property( package->db, szProductCode );
|
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;
|
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;
|
if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL;
|
||||||
else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64;
|
else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64;
|
||||||
|
@ -1652,11 +1652,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
if (index)
|
if (index) msi_adjust_privilege_properties( package );
|
||||||
{
|
|
||||||
msi_clone_properties( package );
|
|
||||||
msi_adjust_privilege_properties( package );
|
|
||||||
}
|
|
||||||
r = msi_set_original_database_property( package->db, szPackage );
|
r = msi_set_original_database_property( package->db, szPackage );
|
||||||
if (r != ERROR_SUCCESS)
|
if (r != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,57 +35,220 @@ static BOOL match_language( MSIPACKAGE *package, LANGID langid )
|
||||||
return FALSE;
|
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 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 );
|
MSISUMMARYINFO *si = MSI_GetSummaryInformationW( transform, 0 );
|
||||||
UINT valid_flags = 0, wanted_flags = 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 );
|
if (!si)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
WCHAR *package_product = msi_dup_property( package->db, szProductCode );
|
WARN("no summary information!\n");
|
||||||
WCHAR *transform_product = msi_get_suminfo_product( transform );
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
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)
|
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 ) )))
|
if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) )))
|
||||||
{
|
{
|
||||||
valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE;
|
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 );
|
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");
|
TRACE("applicable transform\n");
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,12 +83,6 @@ static const WCHAR szInstallProperties_fmt[] = {
|
||||||
'%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
|
'%','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};
|
'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[] = {
|
static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
|
||||||
'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
|
'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','\\',
|
'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','\\',
|
'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};
|
'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[] = {
|
static const WCHAR szInstaller_LocalClassesProducts[] = {
|
||||||
'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
|
'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};
|
'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;
|
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,
|
static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
|
||||||
awstring *lpQualBuf, LPDWORD pcchQual,
|
awstring *lpQualBuf, LPDWORD pcchQual,
|
||||||
awstring *lpAppBuf, LPDWORD pcchAppBuf )
|
awstring *lpAppBuf, LPDWORD pcchAppBuf )
|
||||||
|
|
|
@ -344,7 +344,7 @@ DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function
|
||||||
if (FAILED(hr)) goto done;
|
if (FAILED(hr)) goto done;
|
||||||
|
|
||||||
/* Call a function if necessary through the IDispatch interface */
|
/* 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));
|
TRACE("Calling function %s\n", debugstr_w(function));
|
||||||
|
|
||||||
hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch);
|
hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch);
|
||||||
|
|
|
@ -62,7 +62,7 @@ static STORAGE *create_storage(MSISTORAGESVIEW *sv, LPCWSTR name, IStorage *stg)
|
||||||
if (!storage)
|
if (!storage)
|
||||||
return NULL;
|
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;
|
storage->storage = stg;
|
||||||
|
|
||||||
if (storage->storage)
|
if (storage->storage)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Implementation of the Microsoft Installer (msi.dll)
|
* Implementation of the Microsoft Installer (msi.dll)
|
||||||
*
|
*
|
||||||
* Copyright 2007 James Hawkins
|
* Copyright 2007 James Hawkins
|
||||||
|
* Copyright 2015 Hans Leidekker for CodeWeavers
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* 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
|
#define NUM_STREAMS_COLS 2
|
||||||
|
|
||||||
typedef struct tabSTREAM
|
|
||||||
{
|
|
||||||
UINT str_index;
|
|
||||||
IStream *stream;
|
|
||||||
} STREAM;
|
|
||||||
|
|
||||||
typedef struct tagMSISTREAMSVIEW
|
typedef struct tagMSISTREAMSVIEW
|
||||||
{
|
{
|
||||||
MSIVIEW view;
|
MSIVIEW view;
|
||||||
MSIDATABASE *db;
|
MSIDATABASE *db;
|
||||||
STREAM **streams;
|
UINT num_cols;
|
||||||
UINT max_streams;
|
|
||||||
UINT num_rows;
|
|
||||||
UINT row_size;
|
|
||||||
} MSISTREAMSVIEW;
|
} 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;
|
if (!(db->streams = msi_alloc_zero( size * sizeof(MSISTREAM) ))) return FALSE;
|
||||||
sv->streams = msi_realloc_zero(sv->streams, sv->max_streams * sizeof(STREAM *));
|
db->num_streams_allocated = size;
|
||||||
if (!sv->streams)
|
return TRUE;
|
||||||
return FALSE;
|
}
|
||||||
|
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;
|
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)
|
static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||||
|
@ -83,10 +60,10 @@ static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT
|
||||||
if (col != 1)
|
if (col != 1)
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
if (row >= sv->num_rows)
|
if (row >= sv->db->num_streams)
|
||||||
return ERROR_NO_MORE_ITEMS;
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
*val = sv->streams[row]->str_index;
|
*val = sv->db->streams[row].str_index;
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
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)
|
static UINT STREAMS_fetch_stream(struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||||
|
LARGE_INTEGER pos;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(%p, %d, %d, %p)\n", view, row, col, stm);
|
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;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
IStream_AddRef(sv->streams[row]->stream);
|
pos.QuadPart = 0;
|
||||||
*stm = sv->streams[row]->stream;
|
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;
|
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)
|
static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
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);
|
TRACE("(%p, %d, %p, %08x)\n", view, row, rec, mask);
|
||||||
|
|
||||||
if (row > sv->num_rows)
|
if (row > sv->db->num_streams || mask >= (1 << sv->num_cols))
|
||||||
return ERROR_FUNCTION_FAILED;
|
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)
|
if (r != ERROR_SUCCESS)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
hr = IStream_Stat(stm, &stat, STATFLAG_NONAME);
|
for (i = 0; i < sv->db->num_streams; i++)
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
{
|
||||||
WARN("failed to stat stream: %08x\n", hr);
|
STREAMS_fetch_int( &sv->view, i, 1, &val );
|
||||||
goto done;
|
|
||||||
|
if (val == id)
|
||||||
|
{
|
||||||
|
if (row) *row = i;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat.cbSize.QuadPart >> 32)
|
return ERROR_FUNCTION_FAILED;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
|
static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
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);
|
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;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
if (row == -1)
|
if (row == -1)
|
||||||
row = sv->num_rows - 1;
|
row = num_rows - 1;
|
||||||
|
|
||||||
/* shift the rows to make room for the new row */
|
/* 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)
|
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);
|
TRACE("(%p, %p, %p)\n", view, rows, cols);
|
||||||
|
|
||||||
if (cols) *cols = NUM_STREAMS_COLS;
|
if (cols) *cols = sv->num_cols;
|
||||||
if (rows) *rows = sv->num_rows;
|
if (rows) *rows = sv->db->num_streams;
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
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,
|
static UINT STREAMS_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
|
||||||
UINT *type, BOOL *temporary, LPCWSTR *table_name )
|
UINT *type, BOOL *temporary, LPCWSTR *table_name )
|
||||||
{
|
{
|
||||||
TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary,
|
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||||
table_name);
|
|
||||||
|
|
||||||
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;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
switch (n)
|
switch (n)
|
||||||
|
@ -280,30 +249,6 @@ static UINT STREAMS_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *n
|
||||||
return ERROR_SUCCESS;
|
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)
|
static UINT streams_modify_update(struct tagMSIVIEW *view, MSIRECORD *rec)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||||
|
@ -313,15 +258,15 @@ static UINT streams_modify_update(struct tagMSIVIEW *view, MSIRECORD *rec)
|
||||||
if (r != ERROR_SUCCESS)
|
if (r != ERROR_SUCCESS)
|
||||||
return ERROR_FUNCTION_FAILED;
|
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)
|
static UINT streams_modify_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
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)
|
if (r == ERROR_SUCCESS)
|
||||||
return streams_modify_update(view, rec);
|
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)
|
static UINT STREAMS_delete(struct tagMSIVIEW *view)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
|
||||||
UINT i;
|
|
||||||
|
|
||||||
TRACE("(%p)\n", view);
|
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);
|
msi_free(sv);
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
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);
|
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;
|
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;
|
*row = index;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*handle = UlongToPtr(++index);
|
*handle = UlongToPtr(++index);
|
||||||
|
|
||||||
if (index > sv->num_rows)
|
if (index > sv->db->num_streams)
|
||||||
return ERROR_NO_MORE_ITEMS;
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
@ -444,107 +375,256 @@ static const MSIVIEWOPS streams_ops =
|
||||||
NULL,
|
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;
|
HRESULT hr;
|
||||||
UINT r, count = 0, size;
|
|
||||||
LPWSTR encname;
|
|
||||||
|
|
||||||
hr = IStorage_EnumElements(sv->db->storage, 0, NULL, 0, &stgenum);
|
hr = IStorage_OpenStream( db->storage, name, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, stream );
|
||||||
if (FAILED(hr))
|
if (FAILED( hr ))
|
||||||
return -1;
|
|
||||||
|
|
||||||
sv->max_streams = 1;
|
|
||||||
sv->streams = msi_alloc_zero(sizeof(STREAM *));
|
|
||||||
if (!sv->streams)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
{
|
||||||
size = 0;
|
MSITRANSFORM *transform;
|
||||||
hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &size);
|
|
||||||
if (FAILED(hr) || !size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (stat.type != STGTY_STREAM)
|
LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
|
||||||
{
|
{
|
||||||
CoTaskMemFree(stat.pwcsName);
|
hr = IStorage_OpenStream( transform->stg, name, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, stream );
|
||||||
continue;
|
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 */
|
/* 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
TRACE("found new stream %s\n", debugstr_w( stat.pwcsName ));
|
||||||
|
|
||||||
stream = create_stream(sv, stat.pwcsName, TRUE, NULL);
|
hr = open_stream( db, stat.pwcsName, &stream );
|
||||||
if (!stream)
|
if (FAILED( hr ))
|
||||||
{
|
{
|
||||||
count = -1;
|
ERR("unable to open stream %08x\n", hr);
|
||||||
CoTaskMemFree(stat.pwcsName);
|
CoTaskMemFree( stat.pwcsName );
|
||||||
|
r = ERROR_FUNCTION_FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* these streams appear to be unencoded */
|
r = append_stream( db, stat.pwcsName, stream );
|
||||||
if (*stat.pwcsName == 0x0005)
|
CoTaskMemFree( stat.pwcsName );
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (r != ERROR_SUCCESS)
|
if (r != ERROR_SUCCESS)
|
||||||
{
|
|
||||||
WARN("unable to get stream %u\n", r);
|
|
||||||
count = -1;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (!streams_set_table_size(sv, ++count))
|
|
||||||
{
|
|
||||||
count = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sv->streams[count - 1] = stream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumSTATSTG_Release(stgenum);
|
TRACE("loaded %u streams\n", db->num_streams);
|
||||||
return count;
|
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)
|
UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view)
|
||||||
{
|
{
|
||||||
MSISTREAMSVIEW *sv;
|
MSISTREAMSVIEW *sv;
|
||||||
INT rows;
|
UINT r;
|
||||||
|
|
||||||
TRACE("(%p, %p)\n", db, view);
|
TRACE("(%p, %p)\n", db, view);
|
||||||
|
|
||||||
sv = msi_alloc_zero( sizeof(MSISTREAMSVIEW) );
|
r = load_streams( db );
|
||||||
if (!sv)
|
if (r != ERROR_SUCCESS)
|
||||||
return ERROR_FUNCTION_FAILED;
|
return r;
|
||||||
|
|
||||||
|
if (!(sv = msi_alloc_zero( sizeof(MSISTREAMSVIEW) )))
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
|
||||||
sv->view.ops = &streams_ops;
|
sv->view.ops = &streams_ops;
|
||||||
|
sv->num_cols = NUM_STREAMS_COLS;
|
||||||
sv->db = db;
|
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;
|
*view = (MSIVIEW *)sv;
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
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;
|
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;
|
DWORD sz;
|
||||||
UINT r = ERROR_INVALID_PARAMETER;
|
UINT r = ERROR_INVALID_PARAMETER;
|
||||||
|
@ -241,7 +241,7 @@ static UINT msi_string2idA( const string_table *st, LPCSTR buffer, UINT *id )
|
||||||
return r;
|
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;
|
LPWSTR str;
|
||||||
int sz;
|
int sz;
|
||||||
|
@ -256,7 +256,7 @@ static int msi_addstring( string_table *st, UINT n, const char *data, UINT len,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) )
|
if (string2id( st, data, &n ) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (persistence == StringPersistent)
|
if (persistence == StringPersistent)
|
||||||
st->strings[n].persistent_refcount += refcount;
|
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;
|
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;
|
UINT n;
|
||||||
LPWSTR str;
|
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 (msi_string2id( st, data, len, &n) == ERROR_SUCCESS )
|
||||||
{
|
{
|
||||||
if (persistence == StringPersistent)
|
if (persistence == StringPersistent)
|
||||||
st->strings[n].persistent_refcount += refcount;
|
st->strings[n].persistent_refcount++;
|
||||||
else
|
else
|
||||||
st->strings[n].nonpersistent_refcount += refcount;
|
st->strings[n].nonpersistent_refcount++;
|
||||||
return n;
|
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) );
|
memcpy( str, data, len*sizeof(WCHAR) );
|
||||||
str[len] = 0;
|
str[len] = 0;
|
||||||
|
|
||||||
set_st_entry( st, n, str, len, refcount, persistence );
|
set_st_entry( st, n, str, len, 1, persistence );
|
||||||
return n;
|
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] st - pointer to the string table
|
||||||
* [in] id - id of the string to retrieve
|
* [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.
|
* 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;
|
int len, lenW;
|
||||||
const WCHAR *str;
|
const WCHAR *str;
|
||||||
|
@ -529,7 +529,7 @@ string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = msi_addstring( st, n, data+offset, len, refs, StringPersistent );
|
r = add_string( st, n, data+offset, len, refs, StringPersistent );
|
||||||
if( r != n )
|
if( r != n )
|
||||||
ERR("Failed to add string %d\n", n );
|
ERR("Failed to add string %d\n", n );
|
||||||
n++;
|
n++;
|
||||||
|
@ -599,7 +599,7 @@ UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *byt
|
||||||
}
|
}
|
||||||
|
|
||||||
sz = datasize - used;
|
sz = datasize - used;
|
||||||
r = msi_id2stringA( st, i, data+used, &sz );
|
r = id2string( st, i, data+used, &sz );
|
||||||
if( r != ERROR_SUCCESS )
|
if( r != ERROR_SUCCESS )
|
||||||
{
|
{
|
||||||
ERR("failed to fetch string\n");
|
ERR("failed to fetch string\n");
|
||||||
|
|
|
@ -88,7 +88,7 @@ static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col,
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
if( (col->type & 0xff) != 4 )
|
if( (col->type & 0xff) != 4 )
|
||||||
ERR("Invalid column size!\n");
|
ERR("Invalid column size %u\n", col->type & 0xff);
|
||||||
|
|
||||||
return 4;
|
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 )
|
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 table_id = msi_add_string( db->strings, col->table, -1, string_persistence );
|
||||||
UINT col_id = msi_addstringW( db->strings, col->column, -1, 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 ].tablename = msi_string_lookup( db->strings, table_id, NULL );
|
||||||
table->colinfo[ i ].number = i + 1;
|
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 size, offset, old_count;
|
||||||
UINT n;
|
UINT n;
|
||||||
|
|
||||||
table = find_cached_table( db, name );
|
if (!(table = find_cached_table( db, name ))) return;
|
||||||
old_count = table->col_count;
|
old_count = table->col_count;
|
||||||
msi_free_colinfo( table->colinfo, table->col_count );
|
msi_free_colinfo( table->colinfo, table->col_count );
|
||||||
msi_free( table->colinfo );
|
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;
|
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||||
UINT r;
|
UINT r;
|
||||||
LPWSTR encname, full_name = NULL;
|
WCHAR *name;
|
||||||
|
|
||||||
if( !view->ops->fetch_int )
|
if( !view->ops->fetch_int )
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
r = msi_stream_name( tv, row, &full_name );
|
r = msi_stream_name( tv, row, &name );
|
||||||
if ( r != ERROR_SUCCESS )
|
if (r != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
ERR("fetching stream, error = %d\n", r);
|
ERR("fetching stream, error = %u\n", r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
encname = encode_streamname( FALSE, full_name );
|
r = msi_get_stream( tv->db, name, stm );
|
||||||
r = msi_get_raw_stream( tv->db, encname, stm );
|
if (r != ERROR_SUCCESS)
|
||||||
if( r )
|
ERR("fetching stream %s, error = %u\n", debugstr_w(name), r);
|
||||||
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
|
|
||||||
|
|
||||||
msi_free( full_name );
|
msi_free( name );
|
||||||
msi_free( encname );
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1350,8 +1348,8 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
const WCHAR *sval = msi_record_get_string( rec, i + 1, &len );
|
const WCHAR *sval = msi_record_get_string( rec, i + 1, &len );
|
||||||
val = msi_addstringW( tv->db->strings, sval, len, 1,
|
val = msi_add_string( tv->db->strings, sval, len,
|
||||||
persistent ? StringPersistent : StringNonPersistent );
|
persistent ? StringPersistent : StringNonPersistent );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2555,6 +2553,12 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
||||||
*/
|
*/
|
||||||
sz = 2;
|
sz = 2;
|
||||||
num_cols = mask >> 8;
|
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++)
|
for (i = 0; i < num_cols; i++)
|
||||||
{
|
{
|
||||||
if( (tv->columns[i].type & MSITYPE_STRING) &&
|
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
|
* 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 )
|
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);
|
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 );
|
msi_update_table_columns( db, table );
|
||||||
|
|
||||||
msiobj_release( &rec->hdr );
|
msiobj_release( &rec->hdr );
|
||||||
|
@ -2697,6 +2701,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
||||||
string_table *strings;
|
string_table *strings;
|
||||||
UINT ret = ERROR_FUNCTION_FAILED;
|
UINT ret = ERROR_FUNCTION_FAILED;
|
||||||
UINT bytes_per_strref;
|
UINT bytes_per_strref;
|
||||||
|
BOOL property_update = FALSE;
|
||||||
|
|
||||||
TRACE("%p %p\n", db, stg );
|
TRACE("%p %p\n", db, stg );
|
||||||
|
|
||||||
|
@ -2741,6 +2746,8 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
||||||
tables = transform;
|
tables = transform;
|
||||||
else if (!strcmpW( transform->name, szColumns ) )
|
else if (!strcmpW( transform->name, szColumns ) )
|
||||||
columns = transform;
|
columns = transform;
|
||||||
|
else if (!strcmpW( transform->name, szProperty ))
|
||||||
|
property_update = TRUE;
|
||||||
|
|
||||||
TRACE("transform contains stream %s\n", debugstr_w(name));
|
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 )
|
if ( ret == ERROR_SUCCESS )
|
||||||
|
{
|
||||||
append_storage_to_db( db, stg );
|
append_storage_to_db( db, stg );
|
||||||
|
if (property_update) msi_clone_properties( db );
|
||||||
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if ( stgenum )
|
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/msgsm32.acm # Synced to Wine-1.7.27
|
||||||
reactos/dll/win32/mshtml # 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/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/msimg32 # Synced to Wine-1.7.27
|
||||||
reactos/dll/win32/msimtf # 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
|
reactos/dll/win32/msisip # Synced to Wine-1.7.27
|
||||||
|
|
Loading…
Reference in a new issue