[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