From 479213c455ee0af872a8e2efc0572fb4b6a2a9fe Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 28 Jan 2005 12:39:57 +0000 Subject: [PATCH] Implement MsiPreviewDialog. --- dlls/msi/Makefile.in | 1 + dlls/msi/dialog.c | 470 +++++++++++++++++++++++++++++++++++++++++++ dlls/msi/msi.c | 2 + dlls/msi/msipriv.h | 54 +++-- dlls/msi/package.c | 38 ++-- dlls/msi/preview.c | 72 +++++-- 6 files changed, 581 insertions(+), 56 deletions(-) create mode 100644 dlls/msi/dialog.c diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in index 7db118bbc0d..efd51b66cd0 100644 --- a/dlls/msi/Makefile.in +++ b/dlls/msi/Makefile.in @@ -10,6 +10,7 @@ C_SRCS = \ action.c \ create.c \ custom.c \ + dialog.c \ distinct.c \ format.c \ handle.c \ diff --git a/dlls/msi/dialog.c b/dlls/msi/dialog.c new file mode 100644 index 00000000000..da49b8bfd67 --- /dev/null +++ b/dlls/msi/dialog.c @@ -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 + +#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; ipackage; + + 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 ); +} diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index be7f6038e66..06417256e27 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -1467,8 +1467,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); + msi_dialog_register_class(); break; case DLL_PROCESS_DETACH: + msi_dialog_unregister_class(); /* FIXME: Cleanup */ break; } diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 06e40021c4a..5622820a74b 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -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*, MSIRECORD ** ); 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; diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 428b87303ce..3283c090513 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -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, MSIPACKAGE **pPackage) 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, MSIPACKAGE **pPackage) } 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) diff --git a/dlls/msi/preview.c b/dlls/msi/preview.c index 42dbca7407c..623a27a390d 100644 --- a/dlls/msi/preview.c +++ b/dlls/msi/preview.c @@ -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( MSIHANDLE hdb, MSIHANDLE* phPreview ) 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 )