[1/2] msi: Reuse temporary executables.
Hans Leidekker
hans at codeweavers.com
Thu Dec 2 04:32:26 CST 2010
Fixes a custom action in the Office 2010 installer and makes installers
that pack multiple custom actions in an executable faster.
---
dlls/msi/custom.c | 118 +++++++++++++++++++++++++++++++---------------------
dlls/msi/msipriv.h | 9 ++++
dlls/msi/package.c | 15 +++++++
3 files changed, 94 insertions(+), 48 deletions(-)
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index 8c080c9..391bf9a 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -355,60 +355,90 @@ end:
return rc;
}
-
-static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
- LPWSTR tmp_file)
+static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
'`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
- MSIRECORD *row = 0;
+ MSIRECORD *row;
+ MSIBINARY *binary;
HANDLE file;
CHAR buffer[1024];
- WCHAR fmt[MAX_PATH];
- DWORD sz = MAX_PATH;
+ WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH];
+ DWORD sz = MAX_PATH, write;
UINT r;
if (msi_get_property(package->db, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
GetTempPathW(MAX_PATH, fmt);
- if (GetTempFileNameW(fmt, szMsi, 0, tmp_file) == 0)
+ if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile ))
{
- TRACE("Unable to create file\n");
- return ERROR_FUNCTION_FAILED;
+ TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError());
+ return NULL;
}
- track_tempfile(package, tmp_file);
row = MSI_QueryGetRecord(package->db, query, source);
if (!row)
- return ERROR_FUNCTION_FAILED;
+ return NULL;
- /* write out the file */
- file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) )))
+ {
+ msiobj_release( &row->hdr );
+ return NULL;
+ }
+ file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if (file == INVALID_HANDLE_VALUE)
- r = ERROR_FUNCTION_FAILED;
- else
{
- do
+ msiobj_release( &row->hdr );
+ return NULL;
+ }
+ do
+ {
+ sz = sizeof(buffer);
+ r = MSI_RecordReadStream( row, 2, buffer, &sz );
+ if (r != ERROR_SUCCESS)
{
- DWORD write;
- sz = sizeof buffer;
- r = MSI_RecordReadStream(row, 2, buffer, &sz);
- if (r != ERROR_SUCCESS)
- {
- ERR("Failed to get stream\n");
- break;
- }
- WriteFile(file, buffer, sz, &write, NULL);
- } while (sz == sizeof buffer);
- CloseHandle(file);
+ ERR("Failed to get stream\n");
+ break;
+ }
+ WriteFile( file, buffer, sz, &write, NULL );
+ } while (sz == sizeof buffer);
+
+ CloseHandle( file );
+ msiobj_release( &row->hdr );
+ if (r != ERROR_SUCCESS)
+ {
+ DeleteFileW( tmpfile );
+ msi_free( binary );
+ return NULL;
}
- msiobj_release(&row->hdr);
+ /* keep a reference to prevent the dll from being unloaded */
+ if (dll && !(binary->module = LoadLibraryW( tmpfile )))
+ {
+ ERR("failed to load dll %s (%u)\n", debugstr_w( binary->tmpfile ), GetLastError() );
+ DeleteFileW( tmpfile );
+ msi_free( binary );
+ return NULL;
+ }
+ binary->source = strdupW( source );
+ binary->tmpfile = strdupW( tmpfile );
+ list_add_tail( &package->binaries, &binary->entry );
+ return binary;
+}
- return r;
+static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
+{
+ MSIBINARY *binary;
+
+ LIST_FOR_EACH_ENTRY( binary, &package->binaries, MSIBINARY, entry )
+ {
+ if (!strcmpW( binary->source, source ))
+ return binary;
+ }
+
+ return create_temp_binary( package, source, dll );
}
static void file_running_action(MSIPACKAGE* package, HANDLE Handle,
@@ -875,20 +905,15 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action)
{
msi_custom_action_info *info;
- WCHAR tmp_file[MAX_PATH];
+ MSIBINARY *binary;
UINT r;
- r = store_binary_to_temp(package, source, tmp_file);
- if (r != ERROR_SUCCESS)
- return r;
-
- TRACE("Calling function %s from %s\n",debugstr_w(target),
- debugstr_w(tmp_file));
+ if (!(binary = get_temp_binary( package, source, TRUE )))
+ return ERROR_FUNCTION_FAILED;
- if (!strchrW(tmp_file,'.'))
- strcatW(tmp_file, szDot);
+ TRACE("Calling function %s from %s\n", debugstr_w(target), debugstr_w(binary->tmpfile));
- info = do_msidbCustomActionTypeDll( package, type, tmp_file, target, action );
+ info = do_msidbCustomActionTypeDll( package, type, binary->tmpfile, target, action );
r = wait_thread_handle( info );
release_custom_action_data( info );
@@ -898,7 +923,6 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action)
{
- WCHAR tmp_file[MAX_PATH];
STARTUPINFOW si;
PROCESS_INFORMATION info;
BOOL rc;
@@ -906,29 +930,27 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
WCHAR *deformated = NULL;
WCHAR *cmd;
static const WCHAR spc[] = {' ',0};
+ MSIBINARY *binary;
UINT r;
memset(&si,0,sizeof(STARTUPINFOW));
- r = store_binary_to_temp(package, source, tmp_file);
- if (r != ERROR_SUCCESS)
- return r;
+ if (!(binary = get_temp_binary( package, source, FALSE )))
+ return ERROR_FUNCTION_FAILED;
deformat_string(package,target,&deformated);
- len = strlenW(tmp_file)+2;
-
+ len = strlenW( binary->tmpfile ) + 2;
if (deformated)
len += strlenW(deformated);
cmd = msi_alloc(sizeof(WCHAR)*len);
- strcpyW(cmd,tmp_file);
+ strcpyW( cmd, binary->tmpfile );
if (deformated)
{
strcatW(cmd,spc);
strcatW(cmd,deformated);
-
msi_free(deformated);
}
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index feb82a0..fb24d30 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -163,6 +163,14 @@ typedef struct tagMSIPATCHINFO
MSIPATCHSTATE state;
} MSIPATCHINFO;
+typedef struct tagMSIBINARY
+{
+ struct list entry;
+ WCHAR *source;
+ WCHAR *tmpfile;
+ HMODULE module;
+} MSIBINARY;
+
typedef struct _column_info
{
LPCWSTR table;
@@ -330,6 +338,7 @@ typedef struct tagMSIPACKAGE
struct list files;
struct list tempfiles;
struct list folders;
+ struct list binaries;
LPWSTR ActionFormat;
LPWSTR LastAction;
HANDLE log_file;
diff --git a/dlls/msi/package.c b/dlls/msi/package.c
index 596db2b..a81d0bd 100644
--- a/dlls/msi/package.c
+++ b/dlls/msi/package.c
@@ -284,6 +284,20 @@ static void free_package_structures( MSIPACKAGE *package )
msi_free( patch );
}
+ LIST_FOR_EACH_SAFE( item, cursor, &package->binaries )
+ {
+ MSIBINARY *binary = LIST_ENTRY( item, MSIBINARY, entry );
+
+ list_remove( &binary->entry );
+ if (binary->module)
+ FreeLibrary( binary->module );
+ if (!DeleteFileW( binary->tmpfile ))
+ ERR("failed to delete %s (%u)\n", debugstr_w(binary->tmpfile), GetLastError());
+ msi_free( binary->source );
+ msi_free( binary->tmpfile );
+ msi_free( binary );
+ }
+
msi_free( package->BaseURL );
msi_free( package->PackagePath );
msi_free( package->ProductCode );
@@ -1059,6 +1073,7 @@ static MSIPACKAGE *msi_alloc_package( void )
list_init( &package->sourcelist_info );
list_init( &package->sourcelist_media );
list_init( &package->patches );
+ list_init( &package->binaries );
}
return package;
--
1.7.1
More information about the wine-patches
mailing list