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