MSI: implement MsiPreviewDialog

Mike McCormack mike at codeweavers.com
Fri Jan 28 04:20:37 CST 2005


The dialogs don't look too crash hot as yet.

Mike


ChangeLog:
* implement MsiPreviewDialog

-------------- next part --------------
? dlls/msi/dialog.c
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.20
diff -u -p -r1.20 Makefile.in
--- dlls/msi/Makefile.in	25 Jan 2005 20:17:09 -0000	1.20
+++ dlls/msi/Makefile.in	28 Jan 2005 10:18:41 -0000
@@ -10,6 +10,7 @@ C_SRCS = \
 	action.c \
 	create.c \
 	custom.c \
+	dialog.c \
 	distinct.c \
 	format.c \
 	handle.c \
Index: dlls/msi/msi.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/msi.c,v
retrieving revision 1.55
diff -u -p -r1.55 msi.c
--- dlls/msi/msi.c	26 Jan 2005 19:41:13 -0000	1.55
+++ dlls/msi/msi.c	28 Jan 2005 10:18:42 -0000
@@ -1467,8 +1467,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, 
     {
     case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls(hinstDLL);
+        msi_dialog_register_class();
         break;
     case DLL_PROCESS_DETACH:
+        msi_dialog_unregister_class();
         /* FIXME: Cleanup */
         break;
     }
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.43
diff -u -p -r1.43 msipriv.h
--- dlls/msi/msipriv.h	27 Jan 2005 11:12:56 -0000	1.43
+++ dlls/msi/msipriv.h	28 Jan 2005 10:18:42 -0000
@@ -1,7 +1,7 @@
 /*
  * Implementation of the Microsoft Installer (msi.dll)
  *
- * Copyright 2002 Mike McCormack for CodeWeavers
+ * Copyright 2002-2005 Mike McCormack for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -211,10 +211,14 @@ typedef struct tagMSIPACKAGE
     UINT CurrentInstallState;
 } MSIPACKAGE;
 
+struct tag_dialog_info;
+typedef struct tag_dialog_info dialog_info;
+
 typedef struct tagMSIPREVIEW
 {
     MSIOBJECTHDR hdr;
-    MSIDATABASE *db;
+    MSIPACKAGE *package;
+    dialog_info *dialog;
 } MSIPREVIEW;
 
 #define MSIHANDLETYPE_ANY 0
@@ -232,7 +236,7 @@ typedef struct tagMSIPREVIEW
 #define GUID_SIZE 39
 
 #define MSIHANDLE_MAGIC 0x4d434923
-#define MSIMAXHANDLES 0x80
+#define MSIMAXHANDLES 0xf0
 
 #define MSISUMINFO_OFFSET 0x30LL
 
@@ -325,33 +329,41 @@ extern UINT MSI_ViewFetch( MSIQUERY*, MS
 extern UINT MSI_ViewClose( MSIQUERY* );
 
 /* package internals */
-extern UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE ** );
-extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR);
+extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * );
+extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** );
+extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
 extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
-extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD* );
-extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD*);
+extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * );
+extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * );
 extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
 extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
-extern UINT MSI_GetComponentStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
-extern UINT MSI_GetFeatureStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
+extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * );
+extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * );
 
 /* for deformating */
 extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, 
                               LPWSTR buffer, DWORD *size);
     
 /* registry data encoding/decoding functions */
-BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
-BOOL squash_guid(LPCWSTR in, LPWSTR out);
-BOOL encode_base85_guid(GUID *,LPWSTR);
-BOOL decode_base85_guid(LPCWSTR,GUID*);
-UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create);
-UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
-UINT MSIREG_OpenFeatures(HKEY* key);
-UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
-UINT MSIREG_OpenComponents(HKEY* key);
-UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
-UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
-UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
+extern BOOL squash_guid(LPCWSTR in, LPWSTR out);
+extern BOOL encode_base85_guid(GUID *,LPWSTR);
+extern BOOL decode_base85_guid(LPCWSTR,GUID*);
+extern UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+extern UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+extern UINT MSIREG_OpenFeatures(HKEY* key);
+extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+extern UINT MSIREG_OpenComponents(HKEY* key);
+extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
+extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+
+/* msi dialog interface */
+typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, HWND );
+extern dialog_info *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler );
+extern void msi_dialog_destroy( dialog_info* );
+extern void msi_dialog_register_class( void );
+extern void msi_dialog_unregister_class( void );
 
 /* UI globals */
 extern INSTALLUILEVEL gUILevel;
Index: dlls/msi/package.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/package.c,v
retrieving revision 1.33
diff -u -p -r1.33 package.c
--- dlls/msi/package.c	27 Jan 2005 11:12:16 -0000	1.33
+++ dlls/msi/package.c	28 Jan 2005 10:18:42 -0000
@@ -352,15 +352,14 @@ Privileged
     ReleaseDC(0, dc);
 }
 
-UINT MSI_CreatePackage(MSIDATABASE *db, MSIPACKAGE **pPackage)
+MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
 {
     static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
     static const WCHAR szpi[] = {'%','i',0};
     MSIPACKAGE *package = NULL;
     WCHAR uilevel[10];
-    UINT ret = ERROR_FUNCTION_FAILED;
 
-    TRACE("%p %p\n", db, pPackage);
+    TRACE("%p\n", db);
 
     package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
                                MSI_FreePackage );
@@ -387,22 +386,15 @@ UINT MSI_CreatePackage(MSIDATABASE *db, 
         set_installer_properties(package);
         sprintfW(uilevel,szpi,gUILevel);
         MSI_SetPropertyW(package, szLevel, uilevel);
-
-        msiobj_addref( &package->hdr );
-        *pPackage = package;
-        ret = ERROR_SUCCESS;
     }
 
-    if( package )
-        msiobj_release( &package->hdr );
-
-    return ret;
+    return package;
 }
 
 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
 {
     MSIDATABASE *db = NULL;
-    UINT ret = ERROR_FUNCTION_FAILED;
+    MSIPACKAGE *package;
     MSIHANDLE handle;
 
     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
@@ -416,32 +408,34 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage,
     }
     else
     {
-        ret = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
-        if( ret != ERROR_SUCCESS )
-            return ret;
+        UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
+        if( r != ERROR_SUCCESS )
+            return r;
     }
 
-    ret = MSI_CreatePackage( db, pPackage );
+    package = MSI_CreatePackage( db );
+    msiobj_release( &db->hdr );
+    if( !package )
+        return ERROR_FUNCTION_FAILED;
 
     /* 
      * FIXME:  I don't think this is right.  Maybe we should be storing the
      * name of the database in the MSIDATABASE structure and fetching this
      * info from there, or maybe this is only relevant to cached databases.
      */
-    if( ret == ERROR_SUCCESS && szPackage[0] != '#' )
+    if( szPackage[0] != '#' )
     {
         static const WCHAR OriginalDatabase[] =
           {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
         static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
 
-        MSI_SetPropertyW(*pPackage, OriginalDatabase, szPackage);
-        MSI_SetPropertyW(*pPackage, Database, szPackage);
+        MSI_SetPropertyW( package, OriginalDatabase, szPackage );
+        MSI_SetPropertyW( package, Database, szPackage );
     }
 
-    if( db )
-        msiobj_release( &db->hdr );
+    *pPackage = package;
 
-    return ret;
+    return ERROR_SUCCESS;
 }
 
 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
Index: dlls/msi/preview.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/preview.c,v
retrieving revision 1.1
diff -u -p -r1.1 preview.c
--- dlls/msi/preview.c	21 Jan 2005 10:17:01 -0000	1.1
+++ dlls/msi/preview.c	28 Jan 2005 10:18:42 -0000
@@ -22,32 +22,39 @@
 
 #include "windef.h"
 #include "winbase.h"
-#include "winreg.h"
 #include "winnls.h"
-#include "shlwapi.h"
-#include "wine/debug.h"
 #include "msi.h"
 #include "msipriv.h"
 
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 static void MSI_ClosePreview( MSIOBJECTHDR *arg )
 {
     MSIPREVIEW *preview = (MSIPREVIEW *) arg;
 
-    msiobj_release( &preview->db->hdr );
+    msiobj_release( &preview->package->hdr );
 }
 
 MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE *db )
 {
-    MSIPREVIEW *preview;
+    MSIPREVIEW *preview = NULL;
+    MSIPACKAGE *package;
 
-    preview = alloc_msiobject( MSIHANDLETYPE_PREVIEW, sizeof (MSIPREVIEW),
-                               MSI_ClosePreview );
-    if( preview )
+    package = MSI_CreatePackage( db );
+    if( package )
     {
-        preview->db = db;
-        msiobj_addref( &db->hdr );
+        preview = alloc_msiobject( MSIHANDLETYPE_PREVIEW, sizeof (MSIPREVIEW),
+                               MSI_ClosePreview );
+        if( preview )
+        {
+            preview->package = package;
+            preview->dialog = 0;
+            msiobj_addref( &package->hdr );
+        }
+        msiobj_release( &package->hdr );
     }
     return preview;
 }
@@ -70,15 +77,54 @@ UINT WINAPI MsiEnableUIPreview( MSIHANDL
         msiobj_release( &preview->hdr );
         r = ERROR_SUCCESS;
     }
-    msiobj_release( &db->hdr );
+
+    return r;
+}
+
+static VOID preview_event_handler( MSIPACKAGE *package, LPCWSTR event,
+                                   LPCWSTR argument, HWND dialog )
+{
+    MESSAGE("Preview dialog event '%s' (arg='%s')\n",
+            debugstr_w( event ), debugstr_w( argument ));
+}
+
+UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName )
+{
+    dialog_info *dialog = NULL;
+    UINT r = ERROR_SUCCESS;
+
+    if( preview->dialog )
+        msi_dialog_destroy( preview->dialog );
+
+    /* an empty name means we should just destroy the current preview dialog */
+    if( szDialogName )
+    {
+        dialog = msi_dialog_create( preview->package, szDialogName,
+                                    preview_event_handler );
+        if( !dialog )
+            r = ERROR_FUNCTION_FAILED;
+    }
+    preview->dialog = dialog;
 
     return r;
 }
 
 UINT WINAPI MsiPreviewDialogW( MSIHANDLE hPreview, LPCWSTR szDialogName )
 {
-    FIXME("%ld %s\n", hPreview, debugstr_w(szDialogName));
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    MSIPREVIEW *preview;
+    UINT r;
+
+    TRACE("%ld %s\n", hPreview, debugstr_w(szDialogName));
+
+    preview = msihandle2msiinfo( hPreview, MSIHANDLETYPE_PREVIEW );
+    if( !preview )
+        return ERROR_INVALID_HANDLE;
+
+    r = MSI_PreviewDialogW( preview, szDialogName );
+
+    msiobj_release( &preview->hdr );
+
+    return r;
 }
 
 UINT WINAPI MsiPreviewDialogA( MSIHANDLE hPreview, LPCSTR szDialogName )
--- /dev/null	2004-12-26 03:00:47.000000000 +0900
+++ dlls/msi/dialog.c	2005-01-28 19:17:12.000000000 +0900
@@ -0,0 +1,470 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "wingdi.h"
+#include "msi.h"
+#include "msipriv.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+const WCHAR szMsiDialogClass[] = {
+    'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0
+};
+
+struct tag_dialog_info
+{
+    MSIPACKAGE *package;
+    msi_dialog_event_handler event_handler;
+    INT scale;
+    HWND hwnd;
+    WCHAR name[1];
+};
+
+typedef UINT (*msi_dialog_control_func)( dialog_info *dialog, MSIRECORD *rec );
+struct control_handler 
+{
+    LPCWSTR control_type;
+    msi_dialog_control_func func;
+};
+
+static UINT msi_dialog_text_control( dialog_info *dialog, MSIRECORD *rec )
+{
+    DWORD x, y, width, height;
+    LPCWSTR text;
+    const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
+    HWND hwnd;
+
+    TRACE("%p %p\n", dialog, rec);
+
+    x = MSI_RecordGetInteger( rec, 4 );
+    y = MSI_RecordGetInteger( rec, 5 );
+    width = MSI_RecordGetInteger( rec, 6 );
+    height = MSI_RecordGetInteger( rec, 7 );
+    text = MSI_RecordGetString( rec, 10 );
+
+    x = (dialog->scale * x) / 10;
+    y = (dialog->scale * y) / 10;
+    width = (dialog->scale * width) / 10;
+    height = (dialog->scale * height) / 10;
+
+    hwnd = CreateWindowW( szStatic, text, WS_CHILD | WS_VISIBLE |WS_GROUP,
+                          x, y, width, height, dialog->hwnd, NULL, NULL, NULL );
+    if (!hwnd)
+        ERR("Failed to create hwnd\n");
+
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_dialog_button_control( dialog_info *dialog, MSIRECORD *rec )
+{
+    const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
+    DWORD x, y, width, height;
+    LPCWSTR text;
+    HWND hwnd;
+
+    TRACE("%p %p\n", dialog, rec);
+
+    x = MSI_RecordGetInteger( rec, 4 );
+    y = MSI_RecordGetInteger( rec, 5 );
+    width = MSI_RecordGetInteger( rec, 6 );
+    height = MSI_RecordGetInteger( rec, 7 );
+    text = MSI_RecordGetString( rec, 10 );
+
+    x = (dialog->scale * x) / 10;
+    y = (dialog->scale * y) / 10;
+    width = (dialog->scale * width) / 10;
+    height = (dialog->scale * height) / 10;
+
+    hwnd = CreateWindowW( szButton, text, WS_CHILD | WS_VISIBLE |WS_GROUP,
+                          x, y, width, height, dialog->hwnd, NULL, NULL, NULL );
+
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_dialog_line_control( dialog_info *dialog, MSIRECORD *rec )
+{
+    DWORD x, y, width, height;
+    LPCWSTR text;
+    const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
+    HWND hwnd;
+
+    TRACE("%p %p\n", dialog, rec);
+
+    x = MSI_RecordGetInteger( rec, 4 );
+    y = MSI_RecordGetInteger( rec, 5 );
+    width = MSI_RecordGetInteger( rec, 6 );
+    height = MSI_RecordGetInteger( rec, 7 );
+    text = MSI_RecordGetString( rec, 10 );
+
+    x = (dialog->scale * x) / 10;
+    y = (dialog->scale * y) / 10;
+    width = (dialog->scale * width) / 10;
+    height = (dialog->scale * height) / 10;
+
+    hwnd = CreateWindowW( szStatic, text, WS_CHILD | WS_VISIBLE |WS_GROUP |
+                          SS_ETCHEDHORZ |SS_SUNKEN,
+                          x, y, width, height, dialog->hwnd, NULL, NULL, NULL );
+    if (!hwnd)
+        ERR("Failed to create hwnd\n");
+
+    return ERROR_SUCCESS;
+}
+
+#if 0
+static UINT msi_load_picture( MSIDATABASE *db, LPCWSTR name, HBITMAP *hbm )
+{
+    IPicture *pic = NULL;
+    IPersistFile *pf = NULL;
+    IStream *stm = NULL;
+    HRESULT r;
+
+    r = CoCreateObject( &CLSID_Picture, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IPicture, (LPVOID*)&pic );
+    if (FAILED(r))
+        return ERROR_FUNCTION_FAILED;
+
+    r = IPicture_QueryInterface( pic, &IID_IPersistFile, (LPVOID*) &pf );
+    if (SUCCEEDED(r) )
+    {
+        r = IPersistFile_Load( pf, stm );
+        IPersistFile_Release( pf );
+    }
+
+    if (SUCCEEDED(r) )
+        IPicture_get_Handle( pic, hbm );
+    IPicture_Release( pic );
+
+    return r;
+}
+#endif
+
+static UINT msi_dialog_bitmap_control( dialog_info *dialog, MSIRECORD *rec )
+{
+    DWORD x, y, width, height;
+    LPCWSTR text;
+    const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
+    HWND hwnd;
+
+    TRACE("%p %p\n", dialog, rec);
+
+    x = MSI_RecordGetInteger( rec, 4 );
+    y = MSI_RecordGetInteger( rec, 5 );
+    width = MSI_RecordGetInteger( rec, 6 );
+    height = MSI_RecordGetInteger( rec, 7 );
+    text = MSI_RecordGetString( rec, 10 );
+
+    x = (dialog->scale * x) / 10;
+    y = (dialog->scale * y) / 10;
+    width = (dialog->scale * width) / 10;
+    height = (dialog->scale * height) / 10;
+
+    hwnd = CreateWindowW( szStatic, text, WS_CHILD | WS_VISIBLE |WS_GROUP | WS_DISABLED |
+                          SS_BITMAP | SS_LEFT | SS_CENTERIMAGE,
+                          x, y, width, height, dialog->hwnd, NULL, NULL, NULL );
+    if (!hwnd)
+        ERR("Failed to create hwnd\n");
+
+    return ERROR_SUCCESS;
+}
+
+static const WCHAR szText[] = { 'T','e','x','t',0 };
+static const WCHAR szButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
+static const WCHAR szLine[] = { 'L','i','n','e',0 };
+static const WCHAR szBitmap[] = { 'B','i','t','m','a','p',0 };
+
+struct control_handler msi_dialog_handler[] =
+{
+    { szText, msi_dialog_text_control },
+    { szButton, msi_dialog_button_control },
+    { szLine, msi_dialog_line_control },
+    { szBitmap, msi_dialog_bitmap_control },
+};
+
+#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
+
+typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param );
+
+static UINT msi_iterate_records( MSIQUERY *view, record_func func, LPVOID param )
+{
+    MSIRECORD *rec = NULL;
+    UINT r;
+
+    r = MSI_ViewExecute( view, NULL );
+    if( r != ERROR_SUCCESS )
+        return r;
+
+    /* iterate a query */
+    while( 1 )
+    {
+        r = MSI_ViewFetch( view, &rec );
+        if( r != ERROR_SUCCESS )
+            break;
+        r = func( rec, param );
+        msiobj_release( &rec->hdr );
+        if( r != ERROR_SUCCESS )
+            break;
+    }
+
+    MSI_ViewClose( view );
+
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_dialog_create_controls( MSIRECORD *rec, LPVOID param )
+{
+    dialog_info *dialog = param;
+    LPCWSTR control_type;
+    UINT i;
+
+    /* find and call the function that can create this type of control */
+    control_type = MSI_RecordGetString( rec, 3 );
+    for( i=0; i<NUM_CONTROL_TYPES; i++ )
+        if (!strcmpiW( msi_dialog_handler[i].control_type, control_type ))
+            break;
+    if( i != NUM_CONTROL_TYPES )
+        msi_dialog_handler[i].func( dialog, rec );
+    else
+        ERR("no handler for element type %s\n", debugstr_w(control_type));
+
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_dialog_fill_controls( dialog_info *dialog, LPCWSTR name )
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ',
+        'F','R','O','M',' ','C','o','n','t','r','o','l',' ',
+        'W','H','E','R','E',' ',
+           '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',0};
+    UINT r;
+    MSIQUERY *view = NULL;
+    MSIPACKAGE *package = dialog->package;
+
+    TRACE("%p %s\n", dialog, debugstr_w(name) );
+
+    /* query the Control table for all the elements of the control */
+    r = MSI_OpenQuery( package->db, &view, query, name );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("query failed for dialog %s\n", debugstr_w(name));
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    r = msi_iterate_records( view, msi_dialog_create_controls, dialog );
+    msiobj_release( &view->hdr );
+
+    return r;
+}
+
+/* figure out the height of 10 point MS Sans Serif */
+static INT msi_dialog_get_sans_serif_height( HWND hwnd )
+{
+    static const WCHAR szSansSerif[] = {
+        'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0 };
+    LOGFONTW lf;
+    TEXTMETRICW tm;
+    BOOL r;
+    LONG height = 0;
+    HFONT hFont, hOldFont;
+    HDC hdc;
+
+    hdc = GetDC( hwnd );
+    if (hdc)
+    {
+        memset( &lf, 0, sizeof lf );
+        lf.lfHeight = -MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+        strcpyW( lf.lfFaceName, szSansSerif );
+        hFont = CreateFontIndirectW(&lf);
+        if (hFont)
+        {
+            hOldFont = SelectObject( hdc, hFont );
+            r = GetTextMetricsW( hdc, &tm );
+            if (r)
+                height = tm.tmHeight;
+            SelectObject( hdc, hOldFont );
+            DeleteObject( hFont );
+        }
+        ReleaseDC( hwnd, hdc );
+    }
+    return height;
+}
+
+static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ',
+        'F','R','O','M',' ','D','i','a','l','o','g',' ',
+        'W','H','E','R','E',' ',
+           '`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0};
+    dialog_info *dialog = (dialog_info*) cs->lpCreateParams;
+    MSIPACKAGE *package = dialog->package;
+    MSIQUERY *view = NULL;
+    MSIRECORD *rec = NULL;
+    DWORD width, height;
+    LPCWSTR title;
+    UINT r;
+
+    TRACE("%p %p\n", dialog, package);
+
+    dialog->hwnd = hwnd;
+    SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR) dialog );
+
+    /* fetch the associated record from the Dialog table */
+    r = MSI_OpenQuery( package->db, &view, query, dialog->name );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("query failed for dialog %s\n", debugstr_w(dialog->name));
+        return 1;
+    }
+    MSI_ViewExecute( view, NULL );
+    MSI_ViewFetch( view, &rec );
+    MSI_ViewClose( view );
+    msiobj_release( &view->hdr );
+
+    if( !rec )
+    {
+        ERR("No record found for dialog %s\n", debugstr_w(dialog->name));
+        return 1;
+    }
+
+    dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd);
+
+    width = MSI_RecordGetInteger( rec, 4 );
+    height = MSI_RecordGetInteger( rec, 5 );
+    title = MSI_RecordGetString( rec, 7 );
+
+    width = (dialog->scale * width) / 10;
+    height = (dialog->scale * height) / 10;
+
+    SetWindowTextW( hwnd, title );
+    SetWindowPos( hwnd, 0, 0, 0, width, height,
+                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW );
+
+    msiobj_release( &rec->hdr );
+
+    msi_dialog_fill_controls( dialog, dialog->name );
+
+    return 0;
+}
+
+static LRESULT msi_dialog_handle_click( dialog_info *dialog,
+                                     DWORD id, HWND handle )
+{
+    TRACE("BN_CLICKED %08lx %p\n", id, handle);
+
+    return 0;
+}
+
+static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg,
+                WPARAM wParam, LPARAM lParam )
+{
+    dialog_info *dialog = (LPVOID) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+
+    switch (msg)
+    {
+    case WM_CREATE:
+        return msi_dialog_oncreate( hwnd, (LPCREATESTRUCTW)lParam );
+
+    case WM_COMMAND:
+        if( HIWORD(wParam) == BN_CLICKED )
+            return msi_dialog_handle_click( dialog, LOWORD(wParam), (HWND)lParam );
+        break;
+
+    case WM_DESTROY:
+        dialog->hwnd = NULL;
+        return 0;
+    }
+    return DefWindowProcW(hwnd, msg, wParam, lParam);
+}
+
+/* functions that interface to other modules within MSI */
+
+dialog_info *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName,
+                                msi_dialog_event_handler event_handler )
+{
+    dialog_info *dialog;
+    HWND hwnd;
+
+    TRACE("%p %s\n", package, debugstr_w(szDialogName));
+
+    /* allocate the structure for the dialog to use */
+    dialog = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                        sizeof *dialog + sizeof(WCHAR)*strlenW(szDialogName) );
+    if( !dialog )
+        return NULL;
+    strcpyW( dialog->name, szDialogName );
+    dialog->package = package;
+    dialog->event_handler = event_handler;
+    msiobj_addref( &package->hdr );
+
+    /* create and show the dialog window */
+    hwnd = CreateWindowW( szMsiDialogClass, szDialogName, WS_OVERLAPPEDWINDOW,
+                     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+                     NULL, NULL, NULL, dialog );
+    if( !hwnd )
+    {
+        msi_dialog_destroy( dialog );
+        return NULL;
+    }
+    ShowWindow( hwnd, SW_SHOW );
+    UpdateWindow( hwnd );
+
+    return dialog;
+}
+
+void msi_dialog_destroy( dialog_info *dialog )
+{
+    if( dialog->hwnd )
+        DestroyWindow( dialog->hwnd );
+    msiobj_release( &dialog->package->hdr );
+    dialog->package = NULL;
+    HeapFree( GetProcessHeap(), 0, dialog );
+}
+
+void msi_dialog_register_class( void )
+{
+    WNDCLASSW cls;
+
+    ZeroMemory( &cls, sizeof cls );
+    cls.lpfnWndProc   = MSIDialog_WndProc;
+    cls.hInstance     = NULL;
+    cls.hIcon         = LoadIconW(0, (LPWSTR)IDI_APPLICATION);
+    cls.hCursor       = LoadCursorW(0, (LPWSTR)IDC_ARROW);
+    cls.hbrBackground = (HBRUSH)(COLOR_WINDOW);
+    cls.lpszMenuName  = NULL;
+    cls.lpszClassName = szMsiDialogClass;
+
+    RegisterClassW( &cls );
+}
+
+void msi_dialog_unregister_class( void )
+{
+    UnregisterClassW( szMsiDialogClass, NULL );
+}


More information about the wine-patches mailing list