Commit bfe07d1d authored by James Hawkins's avatar James Hawkins Committed by Alexandre Julliard

msi: Add initial implementation of MsiPublishAssemblies.

parent e487b1e2
......@@ -33,6 +33,10 @@
#include "msipriv.h"
#include "winuser.h"
#include "shlobj.h"
#include "objbase.h"
#include "mscoree.h"
#include "fusion.h"
#include "shlwapi.h"
#include "wine/unicode.h"
#include "winver.h"
......@@ -1246,6 +1250,9 @@ static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
{
MSIFEATURE *feature;
if ( !name )
return NULL;
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
if ( !lstrcmpW( feature->Feature, name ) )
......@@ -5542,6 +5549,154 @@ static UINT ACTION_MoveFiles( MSIPACKAGE *package )
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,
LPCSTR action, LPCWSTR table )
{
......@@ -5630,13 +5785,6 @@ static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
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 const WCHAR table[] = {
......
......@@ -57,20 +57,7 @@ extern const WCHAR szRemoveFiles[];
static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
struct media_info {
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)
static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPWSTR source_root)
{
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);
}
static UINT msi_change_media( MSIPACKAGE *package, struct media_info *mi )
static UINT msi_change_media( MSIPACKAGE *package, MSIMEDIAINFO *mi )
{
LPSTR msg;
LPWSTR error, error_dialog;
......@@ -169,7 +156,7 @@ end:
typedef struct
{
MSIPACKAGE* package;
struct media_info *mi;
MSIMEDIAINFO *mi;
} CabData;
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);
}
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;
LPWSTR ptr;
......@@ -311,7 +298,7 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
case fdintNEXT_CABINET:
{
CabData *data = (CabData *)pfdin->pv;
struct media_info *mi = data->mi;
MSIMEDIAINFO *mi = data->mi;
LPWSTR cab = strdupAtoW(pfdin->psz1);
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.
*/
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;
LPWSTR ptr;
HFDI hfdi;
ERF erf;
BOOL ret = FALSE;
CabData data;
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';
data.package = package;
data.mi = mi;
ret = FDICopy(hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, &data);
ret = FDICopy(hfdi, cabinet, cab_path, 0, notify, NULL, data);
if (!ret)
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);
}
static void free_media_info( struct media_info *mi )
void msi_free_media_info( MSIMEDIAINFO *mi )
{
msi_free( mi->disk_prompt );
msi_free( mi->cabinet );
......@@ -504,7 +488,7 @@ static void free_media_info( struct media_info *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;
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 */
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 volume[MAX_PATH];
......@@ -634,7 +618,7 @@ static UINT find_published_source(MSIPACKAGE *package, struct media_info *mi)
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;
......@@ -642,7 +626,7 @@ static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, struct media_info *m
if (mi->is_continuous)
return ERROR_SUCCESS;
rc = load_media_info(package, file, mi);
rc = msi_load_media_info(package, file, mi);
if (rc != ERROR_SUCCESS)
{
ERR("Unable to load media info\n");
......@@ -808,7 +792,7 @@ static BOOL check_dest_hash_matches(MSIFILE *file)
*/
UINT ACTION_InstallFiles(MSIPACKAGE *package)
{
struct media_info *mi;
MSIMEDIAINFO *mi;
UINT rc = ERROR_SUCCESS;
MSIFILE *file;
......@@ -825,7 +809,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *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 )
{
......@@ -841,6 +825,8 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
if (file->Sequence > mi->last_sequence || mi->is_continuous ||
(file->IsCompressed && !mi->is_extracted))
{
CabData data;
rc = ready_media(package, file, mi);
if (rc != ERROR_SUCCESS)
{
......@@ -848,7 +834,11 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
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));
rc = ERROR_FUNCTION_FAILED;
......@@ -881,7 +871,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
}
}
free_media_info( mi );
msi_free_media_info( mi );
return rc;
}
......
......@@ -31,6 +31,8 @@
#include "wine/debug.h"
#include "msipriv.h"
#include "winuser.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wine/unicode.h"
#include "msidefs.h"
......@@ -1054,3 +1056,122 @@ void msi_ui_error( DWORD msg_id, DWORD 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;
}
......@@ -26,6 +26,7 @@
#include "windef.h"
#include "winbase.h"
#include "fdi.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
......@@ -133,6 +134,20 @@ typedef struct tagMSIMEDIADISK
LPWSTR disk_prompt;
} 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
{
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 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
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 */
extern VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event,
......
......@@ -201,6 +201,12 @@ enum msidbMoveFileOptions
msidbMoveFileOptionsMove = 0x00000001,
};
enum msidbAssemblyAttributes
{
msidbAssemblyAttributesURT = 0x00000000,
msidbAssemblyAttributesWin32 = 0x00000001,
};
/*
* Windows SDK braindamage alert
*
......
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