msi: Add initial implementation of MsiPublishAssemblies.

This commit is contained in:
James Hawkins 2008-04-30 04:22:46 -05:00 committed by Alexandre Julliard
parent e487b1e213
commit bfe07d1d07
5 changed files with 325 additions and 41 deletions

View File

@ -33,6 +33,10 @@
#include "msipriv.h" #include "msipriv.h"
#include "winuser.h" #include "winuser.h"
#include "shlobj.h" #include "shlobj.h"
#include "objbase.h"
#include "mscoree.h"
#include "fusion.h"
#include "shlwapi.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "winver.h" #include "winver.h"
@ -1246,6 +1250,9 @@ static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
{ {
MSIFEATURE *feature; MSIFEATURE *feature;
if ( !name )
return NULL;
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{ {
if ( !lstrcmpW( feature->Feature, name ) ) if ( !lstrcmpW( feature->Feature, name ) )
@ -5542,6 +5549,154 @@ static UINT ACTION_MoveFiles( MSIPACKAGE *package )
return rc; return rc;
} }
static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
DWORD dwReserved);
static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
LPVOID pvReserved, HMODULE *phModDll);
static BOOL init_functionpointers(void)
{
HRESULT hr;
HMODULE hfusion;
HMODULE hmscoree;
static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
hmscoree = LoadLibraryA("mscoree.dll");
if (!hmscoree)
{
WARN("mscoree.dll not available\n");
return FALSE;
}
pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
if (!pLoadLibraryShim)
{
WARN("LoadLibraryShim not available\n");
FreeLibrary(hmscoree);
return FALSE;
}
hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
if (FAILED(hr))
{
WARN("fusion.dll not available\n");
FreeLibrary(hmscoree);
return FALSE;
}
pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
FreeLibrary(hmscoree);
return TRUE;
}
static UINT install_assembly(LPWSTR path)
{
IAssemblyCache *cache;
HRESULT hr;
UINT r = ERROR_FUNCTION_FAILED;
if (!init_functionpointers() || !pCreateAssemblyCache)
return ERROR_FUNCTION_FAILED;
hr = pCreateAssemblyCache(&cache, 0);
if (FAILED(hr))
goto done;
hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
if (FAILED(hr))
ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
r = ERROR_SUCCESS;
done:
IAssemblyCache_Release(cache);
return r;
}
static UINT ITERATE_PublishAssembly( MSIRECORD *rec, LPVOID param )
{
MSIPACKAGE *package = param;
MSICOMPONENT *comp;
MSIFEATURE *feature;
MSIFILE *file;
WCHAR path[MAX_PATH];
LPCWSTR app;
DWORD attr;
UINT r;
comp = get_loaded_component(package, MSI_RecordGetString(rec, 1));
if (!comp || !comp->Enabled ||
!(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
{
ERR("Component not set for install, not publishing assembly\n");
return ERROR_SUCCESS;
}
feature = find_feature_by_name(package, MSI_RecordGetString(rec, 2));
if (feature)
msi_feature_set_state(feature, INSTALLSTATE_LOCAL);
if (MSI_RecordGetString(rec, 3))
FIXME("Manifest unhandled\n");
app = MSI_RecordGetString(rec, 4);
if (app)
{
FIXME("Assembly should be privately installed\n");
return ERROR_SUCCESS;
}
attr = MSI_RecordGetInteger(rec, 5);
if (attr == msidbAssemblyAttributesWin32)
{
FIXME("Win32 assemblies not handled\n");
return ERROR_SUCCESS;
}
/* FIXME: extract all files belonging to this component */
file = msi_find_file(package, comp->KeyPath);
GetTempPathW(MAX_PATH, path);
r = msi_extract_file(package, file, path);
if (r != ERROR_SUCCESS)
{
ERR("Failed to extract temporary assembly\n");
return r;
}
PathAddBackslashW(path);
lstrcatW(path, file->FileName);
r = install_assembly(path);
if (r != ERROR_SUCCESS)
ERR("Failed to install assembly\n");
/* FIXME: write Installer assembly reg values */
return r;
}
static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
{
UINT rc;
MSIQUERY *view;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','M','s','i','A','s','s','e','m','b','l','y','`',0};
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
rc = MSI_IterateRecords(view, NULL, ITERATE_PublishAssembly, package);
msiobj_release(&view->hdr);
return rc;
}
static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
LPCSTR action, LPCWSTR table ) LPCSTR action, LPCWSTR table )
{ {
@ -5630,13 +5785,6 @@ static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table ); return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
} }
static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
{
static const WCHAR table[] = {
'M','s','i','A','s','s','e','m','b','l','y',0 };
return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
}
static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package ) static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
{ {
static const WCHAR table[] = { static const WCHAR table[] = {

View File

@ -57,20 +57,7 @@ extern const WCHAR szRemoveFiles[];
static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
struct media_info { static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPWSTR source_root)
UINT disk_id;
UINT type;
UINT last_sequence;
LPWSTR disk_prompt;
LPWSTR cabinet;
LPWSTR first_volume;
LPWSTR volume_label;
BOOL is_continuous;
BOOL is_extracted;
WCHAR source[MAX_PATH];
};
static BOOL source_matches_volume(struct media_info *mi, LPWSTR source_root)
{ {
WCHAR volume_name[MAX_PATH + 1]; WCHAR volume_name[MAX_PATH + 1];
@ -84,7 +71,7 @@ static BOOL source_matches_volume(struct media_info *mi, LPWSTR source_root)
return !lstrcmpW(mi->volume_label, volume_name); return !lstrcmpW(mi->volume_label, volume_name);
} }
static UINT msi_change_media( MSIPACKAGE *package, struct media_info *mi ) static UINT msi_change_media( MSIPACKAGE *package, MSIMEDIAINFO *mi )
{ {
LPSTR msg; LPSTR msg;
LPWSTR error, error_dialog; LPWSTR error, error_dialog;
@ -169,7 +156,7 @@ end:
typedef struct typedef struct
{ {
MSIPACKAGE* package; MSIPACKAGE* package;
struct media_info *mi; MSIMEDIAINFO *mi;
} CabData; } CabData;
static void * cabinet_alloc(ULONG cb) static void * cabinet_alloc(ULONG cb)
@ -265,7 +252,7 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
ui_progress( package, 2, f->FileSize, 0, 0); ui_progress( package, 2, f->FileSize, 0, 0);
} }
static UINT msi_media_get_disk_info( MSIPACKAGE *package, struct media_info *mi ) static UINT msi_media_get_disk_info( MSIPACKAGE *package, MSIMEDIAINFO *mi )
{ {
MSIRECORD *row; MSIRECORD *row;
LPWSTR ptr; LPWSTR ptr;
@ -311,7 +298,7 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
case fdintNEXT_CABINET: case fdintNEXT_CABINET:
{ {
CabData *data = (CabData *)pfdin->pv; CabData *data = (CabData *)pfdin->pv;
struct media_info *mi = data->mi; MSIMEDIAINFO *mi = data->mi;
LPWSTR cab = strdupAtoW(pfdin->psz1); LPWSTR cab = strdupAtoW(pfdin->psz1);
UINT rc; UINT rc;
@ -423,18 +410,18 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
} }
/*********************************************************************** /***********************************************************************
* extract_cabinet_file * msi_cabextract
* *
* Extract files from a cab file. * Extract files from a cab file.
*/ */
static BOOL extract_cabinet_file(MSIPACKAGE* package, struct media_info *mi) BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi,
PFNFDINOTIFY notify, LPVOID data)
{ {
LPSTR cabinet, cab_path = NULL; LPSTR cabinet, cab_path = NULL;
LPWSTR ptr; LPWSTR ptr;
HFDI hfdi; HFDI hfdi;
ERF erf; ERF erf;
BOOL ret = FALSE; BOOL ret = FALSE;
CabData data;
TRACE("Extracting %s\n", debugstr_w(mi->source)); TRACE("Extracting %s\n", debugstr_w(mi->source));
@ -457,10 +444,7 @@ static BOOL extract_cabinet_file(MSIPACKAGE* package, struct media_info *mi)
cab_path[ptr - mi->source] = '\0'; cab_path[ptr - mi->source] = '\0';
data.package = package; ret = FDICopy(hfdi, cabinet, cab_path, 0, notify, NULL, data);
data.mi = mi;
ret = FDICopy(hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, &data);
if (!ret) if (!ret)
ERR("FDICopy failed\n"); ERR("FDICopy failed\n");
@ -495,7 +479,7 @@ static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, LPCWSTR path)
file->SourcePath = build_directory_name(2, path, file->File); file->SourcePath = build_directory_name(2, path, file->File);
} }
static void free_media_info( struct media_info *mi ) 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 );
@ -504,7 +488,7 @@ static void free_media_info( struct media_info *mi )
msi_free( mi ); msi_free( mi );
} }
static UINT load_media_info(MSIPACKAGE *package, MSIFILE *file, struct media_info *mi) UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
{ {
MSIRECORD *row; MSIRECORD *row;
LPWSTR source_dir; LPWSTR source_dir;
@ -593,7 +577,7 @@ static UINT load_media_info(MSIPACKAGE *package, MSIFILE *file, struct media_inf
} }
/* FIXME: search NETWORK and URL sources as well */ /* FIXME: search NETWORK and URL sources as well */
static UINT find_published_source(MSIPACKAGE *package, struct media_info *mi) static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
{ {
WCHAR source[MAX_PATH]; WCHAR source[MAX_PATH];
WCHAR volume[MAX_PATH]; WCHAR volume[MAX_PATH];
@ -634,7 +618,7 @@ static UINT find_published_source(MSIPACKAGE *package, struct media_info *mi)
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
} }
static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, struct media_info *mi) static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
{ {
UINT rc = ERROR_SUCCESS; UINT rc = ERROR_SUCCESS;
@ -642,7 +626,7 @@ static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, struct media_info *m
if (mi->is_continuous) if (mi->is_continuous)
return ERROR_SUCCESS; return ERROR_SUCCESS;
rc = load_media_info(package, file, mi); rc = msi_load_media_info(package, file, mi);
if (rc != ERROR_SUCCESS) if (rc != ERROR_SUCCESS)
{ {
ERR("Unable to load media info\n"); ERR("Unable to load media info\n");
@ -808,7 +792,7 @@ static BOOL check_dest_hash_matches(MSIFILE *file)
*/ */
UINT ACTION_InstallFiles(MSIPACKAGE *package) UINT ACTION_InstallFiles(MSIPACKAGE *package)
{ {
struct media_info *mi; MSIMEDIAINFO *mi;
UINT rc = ERROR_SUCCESS; UINT rc = ERROR_SUCCESS;
MSIFILE *file; MSIFILE *file;
@ -825,7 +809,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
*/ */
msi_create_component_directories( package ); msi_create_component_directories( package );
mi = msi_alloc_zero( sizeof(struct media_info) ); mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{ {
@ -841,6 +825,8 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
if (file->Sequence > mi->last_sequence || mi->is_continuous || if (file->Sequence > mi->last_sequence || mi->is_continuous ||
(file->IsCompressed && !mi->is_extracted)) (file->IsCompressed && !mi->is_extracted))
{ {
CabData data;
rc = ready_media(package, file, mi); rc = ready_media(package, file, mi);
if (rc != ERROR_SUCCESS) if (rc != ERROR_SUCCESS)
{ {
@ -848,7 +834,11 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
break; break;
} }
if (file->IsCompressed && !extract_cabinet_file(package, mi)) data.mi = mi;
data.package = package;
if (file->IsCompressed &&
!msi_cabextract(package, mi, cabinet_notify, &data))
{ {
ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet)); ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
rc = ERROR_FUNCTION_FAILED; rc = ERROR_FUNCTION_FAILED;
@ -881,7 +871,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
} }
} }
free_media_info( mi ); msi_free_media_info( mi );
return rc; return rc;
} }

View File

@ -31,6 +31,8 @@
#include "wine/debug.h" #include "wine/debug.h"
#include "msipriv.h" #include "msipriv.h"
#include "winuser.h" #include "winuser.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "msidefs.h" #include "msidefs.h"
@ -1054,3 +1056,122 @@ void msi_ui_error( DWORD msg_id, DWORD type )
MessageBoxW( NULL, text, title, type ); MessageBoxW( NULL, text, title, type );
} }
typedef struct
{
MSIPACKAGE *package;
MSIMEDIAINFO *mi;
MSIFILE *file;
LPWSTR destination;
} CabData;
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
TRACE("(%d)\n", fdint);
switch (fdint)
{
case fdintNEXT_CABINET:
{
ERR("continuous cabinets not handled\n");
return 0;
}
case fdintCOPY_FILE:
{
CabData *data = (CabData*) pfdin->pv;
LPWSTR file, path;
DWORD attrs, size;
HANDLE handle;
MSIFILE *f;
file = strdupAtoW(pfdin->psz1);
f = get_loaded_file(data->package, file);
msi_free(file);
if (!f)
{
WARN("unknown file in cabinet (%s)\n",debugstr_a(pfdin->psz1));
return 0;
}
if (lstrcmpW(f->File, data->file->File))
return 0;
size = lstrlenW(data->destination) + lstrlenW(file) + 2;
path = msi_alloc(size * sizeof(WCHAR));
lstrcpyW(path, data->destination);
PathAddBackslashW(path);
lstrcatW(path, data->file->FileName);
TRACE("extracting %s\n", debugstr_w(path));
attrs = f->Attributes & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
handle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, attrs, NULL);
if (handle == INVALID_HANDLE_VALUE)
{
if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
ERR("failed to create %s (error %d)\n",
debugstr_w(path), GetLastError());
msi_free(path);
return 0;
}
msi_free(path);
return (INT_PTR)handle;
}
case fdintCLOSE_FILE_INFO:
{
FILETIME ft;
FILETIME ftLocal;
HANDLE handle = (HANDLE)pfdin->hf;
if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
return -1;
if (!LocalFileTimeToFileTime(&ft, &ftLocal))
return -1;
if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
return -1;
CloseHandle(handle);
return 1;
}
default:
return 0;
}
}
UINT msi_extract_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR destdir)
{
MSIMEDIAINFO *mi;
CabData data;
UINT r;
mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
if (!mi)
return ERROR_OUTOFMEMORY;
r = msi_load_media_info(package, file, mi);
if (r != ERROR_SUCCESS)
goto done;
data.package = package;
data.mi = mi;
data.file = file;
data.destination = destdir;
if (!msi_cabextract(package, mi, cabinet_notify, &data))
{
ERR("Failed to extract cabinet file\n");
r = ERROR_FUNCTION_FAILED;
}
done:
msi_free_media_info(mi);
return r;
}

View File

@ -26,6 +26,7 @@
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "fdi.h"
#include "msi.h" #include "msi.h"
#include "msiquery.h" #include "msiquery.h"
#include "objbase.h" #include "objbase.h"
@ -133,6 +134,20 @@ typedef struct tagMSIMEDIADISK
LPWSTR disk_prompt; LPWSTR disk_prompt;
} MSIMEDIADISK; } MSIMEDIADISK;
typedef struct tagMSIMEDIAINFO
{
UINT disk_id;
UINT type;
UINT last_sequence;
LPWSTR disk_prompt;
LPWSTR cabinet;
LPWSTR first_volume;
LPWSTR volume_label;
BOOL is_continuous;
BOOL is_extracted;
WCHAR source[MAX_PATH];
} MSIMEDIAINFO;
typedef struct _column_info typedef struct _column_info
{ {
LPCWSTR table; LPCWSTR table;
@ -889,6 +904,10 @@ extern UINT msi_create_component_directories( MSIPACKAGE *package );
extern void msi_ui_error( DWORD msg_id, DWORD type ); extern void msi_ui_error( DWORD msg_id, DWORD type );
extern UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid, extern UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value); MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value);
extern UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi);
extern void msi_free_media_info(MSIMEDIAINFO *mi);
extern BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, PFNFDINOTIFY notify, LPVOID data);
extern UINT msi_extract_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR destdir);
/* control event stuff */ /* control event stuff */
extern VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event, extern VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event,

View File

@ -201,6 +201,12 @@ enum msidbMoveFileOptions
msidbMoveFileOptionsMove = 0x00000001, msidbMoveFileOptionsMove = 0x00000001,
}; };
enum msidbAssemblyAttributes
{
msidbAssemblyAttributesURT = 0x00000000,
msidbAssemblyAttributesWin32 = 0x00000001,
};
/* /*
* Windows SDK braindamage alert * Windows SDK braindamage alert
* *