MSI: make the msi icon control work

Mike McCormack mike at codeweavers.com
Thu Jun 23 08:16:13 CDT 2005


Makes the Office 2003 install process look that little bit nicer.

Mike


ChangeLog:
* make the msi icon control work
-------------- next part --------------
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.32
diff -u -p -r1.32 Makefile.in
--- dlls/msi/Makefile.in	17 Jun 2005 20:56:55 -0000	1.32
+++ dlls/msi/Makefile.in	23 Jun 2005 13:17:49 -0000
@@ -4,7 +4,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = msi.dll
 IMPORTLIB = libmsi.$(IMPLIBEXT)
-IMPORTS   = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
+IMPORTS   = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
 EXTRALIBS = -luuid $(LIBUNICODE)
 
 C_SRCS = \
Index: dlls/msi/dialog.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/dialog.c,v
retrieving revision 1.26
diff -u -p -r1.26 dialog.c
--- dlls/msi/dialog.c	20 Jun 2005 14:11:43 -0000	1.26
+++ dlls/msi/dialog.c	23 Jun 2005 13:17:50 -0000
@@ -54,6 +54,7 @@ struct msi_control_tag
     LPWSTR property;
     LPWSTR value;
     IPicture *pic;
+    HICON hIcon;
     WCHAR name[1];
 };
 
@@ -113,6 +114,7 @@ static const WCHAR szMaskedEdit[] = { 'M
 static const WCHAR szPathEdit[] = { 'P','a','t','h','E','d','i','t',0 };
 static const WCHAR szRadioButtonGroup[] = { 
     'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 };
+static const WCHAR szIcon[] = { 'I','c','o','n',0 };
 
 static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
 static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
@@ -296,6 +298,7 @@ static msi_control *msi_dialog_create_wi
     control->property = NULL;
     control->value = NULL;
     control->pic = NULL;
+    control->hIcon = NULL;
 
     x = MSI_RecordGetInteger( rec, 4 );
     y = MSI_RecordGetInteger( rec, 5 );
@@ -535,7 +538,7 @@ static UINT msi_dialog_scrolltext_contro
     return ERROR_SUCCESS;
 }
 
-static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic )
+static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
 {
     const static WCHAR query[] = {
         's','e','l','e','c','t',' ','*',' ',
@@ -543,11 +546,17 @@ static UINT msi_load_bitmap( MSIDATABASE
         'w','h','e','r','e',' ',
             '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0
     };
+
+    return MSI_QueryGetRecord( db, query, name );
+}
+
+static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic )
+{
     MSIRECORD *rec = NULL;
     IStream *stm = NULL;
     UINT r;
 
-    rec = MSI_QueryGetRecord( db, query, name );
+    rec = msi_get_binary_record( db, name );
     if( !rec )
         return ERROR_FUNCTION_FAILED;
 
@@ -587,6 +596,108 @@ static UINT msi_dialog_bitmap_control( m
     return ERROR_SUCCESS;
 }
 
+static LPWSTR msi_create_tmp_path(void)
+{
+    WCHAR tmp[MAX_PATH];
+    LPWSTR path = NULL;
+    static const WCHAR prefix[] = { 'm','s','i',0 };
+    DWORD len, r;
+
+    r = GetTempPathW( MAX_PATH, tmp );
+    if( !r )
+        return path;
+    len = lstrlenW( tmp ) + 20;
+    path = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
+    if( path )
+    {
+        r = GetTempFileNameW( tmp, prefix, 0, path );
+        if (!r)
+        {
+            HeapFree( GetProcessHeap(), 0, path );
+            path = NULL;
+        }
+    }
+    return path;
+}
+
+static UINT
+msi_load_icon( MSIDATABASE *db, LPCWSTR name, DWORD attributes, HICON *picon )
+{
+    UINT r = ERROR_FUNCTION_FAILED;
+    LPWSTR tmp;
+    MSIRECORD *rec;
+    HICON hicon = 0;
+
+    TRACE("loading %s\n", debugstr_w( name ) );
+
+    tmp = msi_create_tmp_path();
+    if( !tmp )
+        return r;
+
+    rec = msi_get_binary_record( db, name );
+    if( rec )
+    {
+        r = MSI_RecordStreamToFile( rec, 2, tmp );
+        if( r == ERROR_SUCCESS )
+        {
+            DWORD cx = 0, cy = 0, flags = LR_LOADFROMFILE | LR_DEFAULTSIZE;
+            
+            if( attributes & msidbControlAttributesFixedSize )
+            {
+                flags &= ~LR_DEFAULTSIZE;
+                if( attributes & msidbControlAttributesIconSize16 )
+                {
+                    cx += 16;
+                    cy += 16;
+                }
+                if( attributes & msidbControlAttributesIconSize32 )
+                {
+                    cx += 32;
+                    cy += 32;
+                }
+                /* msidbControlAttributesIconSize48 handled by above logic */
+            }
+            
+            hicon = LoadImageW( 0, tmp, IMAGE_ICON, cx, cy, flags );
+            if( hicon )
+                *picon = hicon;
+            else
+                ERR("failed to load icon from %s\n", debugstr_w( tmp ));
+            DeleteFileW( tmp );
+        }
+        msiobj_release( &rec->hdr );
+    }
+
+    HeapFree( GetProcessHeap(), 0, tmp );
+
+    return r;
+}
+
+static UINT msi_dialog_icon_control( msi_dialog *dialog, MSIRECORD *rec )
+{
+    msi_control *control;
+    DWORD attributes;
+    HICON hIcon = 0;
+    LPCWSTR text;
+    UINT r;
+
+    TRACE("\n");
+
+    control = msi_dialog_add_control( dialog, rec, szStatic,
+                            SS_ICON | SS_CENTERIMAGE | WS_GROUP );
+    text = MSI_RecordGetString( rec, 10 );
+    attributes = MSI_RecordGetInteger( rec, 8 );
+    r = msi_load_icon( dialog->package->db, text, attributes, &hIcon );
+    if( r == ERROR_SUCCESS )
+    {
+        r = SendMessageW( control->hwnd, STM_SETICON, (WPARAM) hIcon, 0 );
+        control->hIcon = hIcon;
+    }
+    else
+        ERR("Failed to load bitmap %s\n", debugstr_w(text));
+    return ERROR_SUCCESS;
+}
+
 static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec )
 {
     static const WCHAR szCombo[] = { 'C','O','M','B','O','B','O','X',0 };
@@ -982,6 +1093,7 @@ struct control_handler msi_dialog_handle
     { szMaskedEdit, msi_dialog_maskedit_control },
     { szPathEdit, msi_dialog_pathedit_control },
     { szRadioButtonGroup, msi_dialog_radiogroup_control },
+    { szIcon, msi_dialog_icon_control },
 };
 
 #define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
@@ -1634,6 +1746,8 @@ void msi_dialog_destroy( msi_dialog *dia
         HeapFree( GetProcessHeap(), 0, t->value );
         if( t->pic )
             IPicture_Release( t->pic );
+        if( t->hIcon )
+            DestroyIcon( t->hIcon );
         HeapFree( GetProcessHeap(), 0, t );
     }
 
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.67
diff -u -p -r1.67 msipriv.h
--- dlls/msi/msipriv.h	17 Jun 2005 21:31:06 -0000	1.67
+++ dlls/msi/msipriv.h	23 Jun 2005 13:17:50 -0000
@@ -328,6 +328,7 @@ extern unsigned int MSI_RecordGetFieldCo
 extern UINT MSI_RecordSetStreamW( MSIRECORD *, unsigned int, LPCWSTR );
 extern UINT MSI_RecordSetStreamA( MSIRECORD *, unsigned int, LPCSTR );
 extern UINT MSI_RecordDataSize( MSIRECORD *, unsigned int );
+extern UINT MSI_RecordStreamToFile( MSIRECORD *, unsigned int, LPCWSTR );
 
 /* stream internals */
 extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
Index: dlls/msi/record.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/record.c,v
retrieving revision 1.28
diff -u -p -r1.28 record.c
--- dlls/msi/record.c	31 May 2005 09:30:28 -0000	1.28
+++ dlls/msi/record.c	23 Jun 2005 13:17:50 -0000
@@ -34,6 +34,9 @@
 #include "winnls.h"
 #include "ole2.h"
 
+#include "winreg.h"
+#include "shlwapi.h"
+
 #include "query.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
@@ -773,4 +776,57 @@ UINT MSI_RecordGetIStream( MSIRECORD *re
     IStream_AddRef( *pstm );
 
     return ERROR_SUCCESS;
+}
+
+static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
+{
+    ULARGE_INTEGER size;
+    LARGE_INTEGER pos;
+    IStream *out;
+    DWORD stgm;
+    HRESULT r;
+
+    stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
+    r = SHCreateStreamOnFileW( name, stgm, &out );
+    if( FAILED( r ) )
+        return ERROR_FUNCTION_FAILED;
+
+    pos.QuadPart = 0;
+    r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
+    if( FAILED( r ) )
+        goto end;
+
+    pos.QuadPart = 0;
+    r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
+    if( FAILED( r ) )
+        goto end;
+
+    r = IStream_CopyTo( stm, out, size, NULL, NULL );
+
+end:
+    IStream_Release( out );
+    if( FAILED( r ) )
+        return ERROR_FUNCTION_FAILED;
+    return ERROR_SUCCESS;
+}
+
+UINT MSI_RecordStreamToFile( MSIRECORD *rec, unsigned int iField, LPCWSTR name )
+{
+    IStream *stm = NULL;
+    UINT r;
+
+    TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
+
+    msiobj_lock( &rec->hdr );
+
+    r = MSI_RecordGetIStream( rec, iField, &stm );
+    if( r == ERROR_SUCCESS )
+    {
+        r = msi_dump_stream_to_file( stm, name );
+        IStream_Release( stm );
+    }
+
+    msiobj_unlock( &rec->hdr );
+
+    return r;
 }


More information about the wine-patches mailing list