Commit 92203f10 authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

msi: Implement the MsiPublishAssemblies and MsiUnpublishAssemblies standard actions.

parent 3eaf33ff
......@@ -7172,13 +7172,6 @@ static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
return msi_unimplemented_action_stub( package, "IsolateComponents", table );
}
static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
{
static const WCHAR table[] = {
'M','s','i','A','s','s','e','m','b','l','y',0 };
return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
}
static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
{
static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
......
......@@ -24,6 +24,7 @@
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "msipriv.h"
......@@ -318,20 +319,250 @@ UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
return ERROR_SUCCESS;
}
static WCHAR *build_local_assembly_path( const WCHAR *filename )
{
UINT i;
WCHAR *ret;
if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) )))
return NULL;
for (i = 0; filename[i]; i++)
{
if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
else ret[i] = filename[i];
}
ret[i] = 0;
return ret;
}
static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
{
static const WCHAR path_win32[] =
{'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
static const WCHAR path_dotnet[] =
{'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
static const WCHAR classes_path_win32[] =
{'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
static const WCHAR classes_path_dotnet[] =
{'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
HKEY root;
const WCHAR *path;
if (context == MSIINSTALLCONTEXT_MACHINE)
{
root = HKEY_CLASSES_ROOT;
if (win32) path = classes_path_win32;
else path = classes_path_dotnet;
}
else
{
root = HKEY_CURRENT_USER;
if (win32) path = path_win32;
else path = path_dotnet;
}
return RegCreateKeyW( root, path, hkey );
}
static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
{
LONG res;
HKEY root;
WCHAR *path;
if (!(path = build_local_assembly_path( filename )))
return ERROR_OUTOFMEMORY;
if ((res = open_assemblies_key( context, win32, &root )))
{
msi_free( path );
return res;
}
res = RegCreateKeyW( root, path, hkey );
RegCloseKey( root );
msi_free( path );
return res;
}
static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
{
LONG res;
HKEY root;
WCHAR *path;
if (!(path = build_local_assembly_path( filename )))
return ERROR_OUTOFMEMORY;
if ((res = open_assemblies_key( context, win32, &root )))
{
msi_free( path );
return res;
}
res = RegDeleteKeyW( root, path );
RegCloseKey( root );
msi_free( path );
return res;
}
static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
{
static const WCHAR path_win32[] =
{'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
'G','l','o','b','a','l',0};
static const WCHAR path_dotnet[] =
{'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
'G','l','o','b','a','l',0};
static const WCHAR classes_path_win32[] =
{'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
'G','l','o','b','a','l',0};
static const WCHAR classes_path_dotnet[] =
{'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\','G','l','o','b','a','l',0};
HKEY root;
const WCHAR *path;
if (context == MSIINSTALLCONTEXT_MACHINE)
{
root = HKEY_CLASSES_ROOT;
if (win32) path = classes_path_win32;
else path = classes_path_dotnet;
}
else
{
root = HKEY_CURRENT_USER;
if (win32) path = path_win32;
else path = path_dotnet;
}
return RegCreateKeyW( root, path, hkey );
}
UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
{
MSIRECORD *uirow;
MSICOMPONENT *comp;
LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
{
if (!comp->assembly || !comp->Enabled)
LONG res;
HKEY hkey;
GUID guid;
DWORD size;
WCHAR buffer[43];
MSIRECORD *uirow;
MSIASSEMBLY *assembly = comp->assembly;
BOOL win32;
if (!assembly || !comp->ComponentId) continue;
if (!comp->Enabled)
{
TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
continue;
}
if (comp->ActionRequest != INSTALLSTATE_LOCAL)
{
TRACE("Component not scheduled for installation: %s\n", debugstr_w(comp->Component));
comp->Action = comp->Installed;
continue;
}
comp->Action = INSTALLSTATE_LOCAL;
TRACE("publishing %s\n", debugstr_w(comp->Component));
CLSIDFromString( package->ProductCode, &guid );
encode_base85_guid( &guid, buffer );
buffer[20] = '>';
CLSIDFromString( comp->ComponentId, &guid );
encode_base85_guid( &guid, buffer + 21 );
buffer[42] = 0;
win32 = assembly->attributes & msidbAssemblyAttributesWin32;
if (assembly->application)
{
MSIFILE *file = get_loaded_file( package, assembly->application );
if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
{
WARN("failed to open local assembly key %d\n", res);
return ERROR_FUNCTION_FAILED;
}
}
else
{
if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
{
WARN("failed to open global assembly key %d\n", res);
return ERROR_FUNCTION_FAILED;
}
}
size = sizeof(buffer);
if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
{
WARN("failed to set assembly value %d\n", res);
}
RegCloseKey( hkey );
uirow = MSI_CreateRecord( 2 );
MSI_RecordSetStringW( uirow, 2, assembly->display_name );
ui_actiondata( package, szMsiPublishAssemblies, uirow );
msiobj_release( &uirow->hdr );
}
return ERROR_SUCCESS;
}
UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
{
MSICOMPONENT *comp;
LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
{
LONG res;
MSIRECORD *uirow;
MSIASSEMBLY *assembly = comp->assembly;
BOOL win32;
if (!assembly || !comp->ComponentId) continue;
if (!comp->Enabled)
{
TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
continue;
}
if (comp->ActionRequest != INSTALLSTATE_ABSENT)
{
TRACE("Component not scheduled for removal: %s\n", debugstr_w(comp->Component));
comp->Action = comp->Installed;
continue;
}
comp->Action = INSTALLSTATE_ABSENT;
/* FIXME: write assembly registry values */
TRACE("unpublishing %s\n", debugstr_w(comp->Component));
win32 = assembly->attributes & msidbAssemblyAttributesWin32;
if (assembly->application)
{
MSIFILE *file = get_loaded_file( package, assembly->application );
if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
WARN("failed to delete local assembly key %d\n", res);
}
else
{
HKEY hkey;
if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
WARN("failed to delete global assembly key %d\n", res);
else
{
if ((res = RegDeleteValueW( hkey, assembly->display_name )))
WARN("failed to delete global assembly value %d\n", res);
RegCloseKey( hkey );
}
}
uirow = MSI_CreateRecord( 2 );
MSI_RecordSetStringW( uirow, 2, comp->assembly->display_name );
MSI_RecordSetStringW( uirow, 2, assembly->display_name );
ui_actiondata( package, szMsiPublishAssemblies, uirow );
msiobj_release( &uirow->hdr );
}
......
......@@ -922,6 +922,7 @@ extern UINT ACTION_UnregisterFonts(MSIPACKAGE *package);
extern UINT ACTION_UnregisterMIMEInfo(MSIPACKAGE *package);
extern UINT ACTION_UnregisterProgIdInfo(MSIPACKAGE *package);
extern UINT ACTION_MsiPublishAssemblies(MSIPACKAGE *package);
extern UINT ACTION_MsiUnpublishAssemblies(MSIPACKAGE *package);
/* Helpers */
extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
......
......@@ -5903,7 +5903,6 @@ static void test_publish_assemblies(void)
}
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
todo_wine {
res = RegOpenKeyA(HKEY_CURRENT_USER, path_dotnet, &hkey);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
CHECK_REG_STR(hkey, name_dotnet, "rcHQPHq?CA@Uv-XqMI1e>Z'q,T*76M@=YEg6My?~]");
......@@ -5925,7 +5924,6 @@ static void test_publish_assemblies(void)
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
CHECK_REG_STR(hkey, name_win32_local, "rcHQPHq?CA@Uv-XqMI1e>C)Uvlj*53A)u(QQ9=)X!");
RegCloseKey(hkey);
}
r = MsiInstallProductA(msifile, "REMOVE=ALL");
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
......@@ -5959,7 +5957,6 @@ static void test_publish_assemblies(void)
r = MsiInstallProductA(msifile, "ALLUSERS=1");
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
todo_wine {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, classes_path_dotnet, &hkey);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
CHECK_REG_STR(hkey, name_dotnet, "rcHQPHq?CA@Uv-XqMI1e>Z'q,T*76M@=YEg6My?~]");
......@@ -5981,9 +5978,8 @@ static void test_publish_assemblies(void)
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
CHECK_REG_STR(hkey, name_win32_local, "rcHQPHq?CA@Uv-XqMI1e>C)Uvlj*53A)u(QQ9=)X!");
RegCloseKey(hkey);
}
r = MsiInstallProductA(msifile, "REMOVE=ALL");
r = MsiInstallProductA(msifile, "REMOVE=ALL ALLUSERS=1");
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
res = RegOpenKeyA(HKEY_CLASSES_ROOT, classes_path_dotnet, &hkey);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment