📄 dialog.c
字号:
/*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "msi.h"
#include "msipriv.h"
#include "msidefs.h"
#include "ocidl.h"
#include "olectl.h"
#include "richedit.h"
#include "commctrl.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
extern HINSTANCE msi_hInstance;
struct msi_control_tag;
typedef struct msi_control_tag msi_control;
typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM );
struct msi_control_tag
{
struct list entry;
HWND hwnd;
msi_handler handler;
LPWSTR property;
LPWSTR value;
HBITMAP hBitmap;
HICON hIcon;
LPWSTR tabnext;
LPWSTR type;
HMODULE hDll;
float progress_current;
float progress_max;
DWORD attributes;
WCHAR name[1];
};
typedef struct msi_font_tag
{
struct msi_font_tag *next;
HFONT hfont;
COLORREF color;
WCHAR name[1];
} msi_font;
struct msi_dialog_tag
{
MSIPACKAGE *package;
msi_dialog *parent;
msi_dialog_event_handler event_handler;
BOOL finished;
INT scale;
DWORD attributes;
SIZE size;
HWND hwnd;
LPWSTR default_font;
msi_font *font_list;
struct list controls;
HWND hWndFocus;
LPWSTR control_default;
LPWSTR control_cancel;
WCHAR name[1];
};
typedef UINT (*msi_dialog_control_func)( msi_dialog *dialog, MSIRECORD *rec );
struct control_handler
{
LPCWSTR control_type;
msi_dialog_control_func func;
};
typedef struct
{
msi_dialog* dialog;
msi_control *parent;
DWORD attributes;
LPWSTR propval;
} radio_button_group_descr;
static const WCHAR szMsiDialogClass[] = {
'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0
};
static const WCHAR szMsiHiddenWindow[] = {
'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 };
static const WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
static const WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
static const WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
static const WCHAR szProgress[] = { 'P','r','o','g','r','e','s','s',0 };
static const WCHAR szText[] = { 'T','e','x','t',0 };
static const WCHAR szPushButton[] = { '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 };
static const WCHAR szCheckBox[] = { 'C','h','e','c','k','B','o','x',0 };
static const WCHAR szScrollableText[] = {
'S','c','r','o','l','l','a','b','l','e','T','e','x','t',0 };
static const WCHAR szComboBox[] = { 'C','o','m','b','o','B','o','x',0 };
static const WCHAR szEdit[] = { 'E','d','i','t',0 };
static const WCHAR szMaskedEdit[] = { 'M','a','s','k','e','d','E','d','i','t',0 };
static const WCHAR szPathEdit[] = { 'P','a','t','h','E','d','i','t',0 };
static const WCHAR szProgressBar[] = {
'P','r','o','g','r','e','s','s','B','a','r',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 const WCHAR szSelectionTree[] = {
'S','e','l','e','c','t','i','o','n','T','r','e','e',0 };
static const WCHAR szGroupBox[] = { 'G','r','o','u','p','B','o','x',0 };
static const WCHAR szListBox[] = { 'L','i','s','t','B','o','x',0 };
static const WCHAR szDirectoryCombo[] = { 'D','i','r','e','c','t','o','r','y','C','o','m','b','o',0 };
static const WCHAR szDirectoryList[] = { 'D','i','r','e','c','t','o','r','y','L','i','s','t',0 };
static const WCHAR szVolumeCostList[] = { 'V','o','l','u','m','e','C','o','s','t','L','i','s','t',0 };
static const WCHAR szSelectionDescription[] = {'S','e','l','e','c','t','i','o','n','D','e','s','c','r','i','p','t','i','o','n',0};
static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0};
static const WCHAR szProperty[] = {'P','r','o','p','e','r','t','y',0};
static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
static UINT msi_dialog_button_handler( msi_dialog *, msi_control *, WPARAM );
static UINT msi_dialog_edit_handler( msi_dialog *, msi_control *, WPARAM );
static UINT msi_dialog_radiogroup_handler( msi_dialog *, msi_control *, WPARAM param );
static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog );
static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static MSIFEATURE *msi_seltree_get_selected_feature( msi_control *control );
/* dialog sequencing */
#define WM_MSI_DIALOG_CREATE (WM_USER+0x100)
#define WM_MSI_DIALOG_DESTROY (WM_USER+0x101)
static DWORD uiThreadId;
static HWND hMsiHiddenWindow;
static INT msi_dialog_scale_unit( msi_dialog *dialog, INT val )
{
return (dialog->scale * val + 5) / 10;
}
static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name )
{
msi_control *control;
if( !name )
return NULL;
LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry )
if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */
return control;
return NULL;
}
static msi_control *msi_dialog_find_control_by_type( msi_dialog *dialog, LPCWSTR type )
{
msi_control *control;
if( !type )
return NULL;
LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry )
if( !strcmpW( control->type, type ) ) /* FIXME: case sensitive? */
return control;
return NULL;
}
static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd )
{
msi_control *control;
LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry )
if( hwnd == control->hwnd )
return control;
return NULL;
}
static LPWSTR msi_get_deformatted_field( MSIPACKAGE *package, MSIRECORD *rec, int field )
{
LPCWSTR str = MSI_RecordGetString( rec, field );
LPWSTR ret = NULL;
if (str)
deformat_string( package, str, &ret );
return ret;
}
static LPWSTR msi_dialog_dup_property( msi_dialog *dialog, LPCWSTR property, BOOL indirect )
{
LPWSTR prop = NULL;
if (!property)
return NULL;
if (indirect)
prop = msi_dup_property( dialog->package, property );
if (!prop)
prop = strdupW( property );
return prop;
}
msi_dialog *msi_dialog_get_parent( msi_dialog *dialog )
{
return dialog->parent;
}
LPWSTR msi_dialog_get_name( msi_dialog *dialog )
{
return dialog->name;
}
/*
* msi_dialog_get_style
*
* Extract the {\style} string from the front of the text to display and
* update the pointer. Only the last style in a list is applied.
*/
static LPWSTR msi_dialog_get_style( LPCWSTR p, LPCWSTR *rest )
{
LPWSTR ret;
LPCWSTR q, i, first;
DWORD len;
q = NULL;
*rest = p;
if( !p )
return NULL;
while ((first = strchrW( p, '{' )) && (q = strchrW( first + 1, '}' )))
{
p = first + 1;
if( *p == '\\' || *p == '&' )
p++;
/* little bit of sanity checking to stop us getting confused with RTF */
for( i=p; i<q; i++ )
if( *i == '}' || *i == '\\' )
return NULL;
}
if (!p || !q)
return NULL;
*rest = ++q;
len = q - p;
ret = msi_alloc( len*sizeof(WCHAR) );
if( !ret )
return ret;
memcpy( ret, p, len*sizeof(WCHAR) );
ret[len-1] = 0;
return ret;
}
static UINT msi_dialog_add_font( MSIRECORD *rec, LPVOID param )
{
msi_dialog *dialog = param;
msi_font *font;
LPCWSTR face, name;
LOGFONTW lf;
INT style;
HDC hdc;
/* create a font and add it to the list */
name = MSI_RecordGetString( rec, 1 );
font = msi_alloc( sizeof *font + strlenW( name )*sizeof (WCHAR) );
strcpyW( font->name, name );
font->next = dialog->font_list;
dialog->font_list = font;
font->color = MSI_RecordGetInteger( rec, 4 );
memset( &lf, 0, sizeof lf );
face = MSI_RecordGetString( rec, 2 );
lf.lfHeight = MSI_RecordGetInteger( rec, 3 );
style = MSI_RecordGetInteger( rec, 5 );
if( style & msidbTextStyleStyleBitsBold )
lf.lfWeight = FW_BOLD;
if( style & msidbTextStyleStyleBitsItalic )
lf.lfItalic = TRUE;
if( style & msidbTextStyleStyleBitsUnderline )
lf.lfUnderline = TRUE;
if( style & msidbTextStyleStyleBitsStrike )
lf.lfStrikeOut = TRUE;
lstrcpynW( lf.lfFaceName, face, LF_FACESIZE );
/* adjust the height */
hdc = GetDC( dialog->hwnd );
if (hdc)
{
lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC( dialog->hwnd, hdc );
}
font->hfont = CreateFontIndirectW( &lf );
TRACE("Adding font style %s\n", debugstr_w(font->name) );
return ERROR_SUCCESS;
}
static msi_font *msi_dialog_find_font( msi_dialog *dialog, LPCWSTR name )
{
msi_font *font;
for( font = dialog->font_list; font; font = font->next )
if( !strcmpW( font->name, name ) ) /* FIXME: case sensitive? */
break;
return font;
}
static UINT msi_dialog_set_font( msi_dialog *dialog, HWND hwnd, LPCWSTR name )
{
msi_font *font;
font = msi_dialog_find_font( dialog, name );
if( font )
SendMessageW( hwnd, WM_SETFONT, (WPARAM) font->hfont, TRUE );
else
ERR("No font entry for %s\n", debugstr_w(name));
return ERROR_SUCCESS;
}
static UINT msi_dialog_build_font_list( msi_dialog *dialog )
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ',
'F','R','O','M',' ','`','T','e','x','t','S','t','y','l','e','`',' ',0
};
UINT r;
MSIQUERY *view = NULL;
TRACE("dialog %p\n", dialog );
r = MSI_OpenQuery( dialog->package->db, &view, query );
if( r != ERROR_SUCCESS )
return r;
r = MSI_IterateRecords( view, NULL, msi_dialog_add_font, dialog );
msiobj_release( &view->hdr );
return r;
}
static msi_control *msi_dialog_create_window( msi_dialog *dialog,
MSIRECORD *rec, DWORD exstyle, LPCWSTR szCls, LPCWSTR name, LPCWSTR text,
DWORD style, HWND parent )
{
DWORD x, y, width, height;
LPWSTR font = NULL, title_font = NULL;
LPCWSTR title = NULL;
msi_control *control;
style |= WS_CHILD;
control = msi_alloc( sizeof *control + strlenW(name)*sizeof(WCHAR) );
strcpyW( control->name, name );
list_add_head( &dialog->controls, &control->entry );
control->handler = NULL;
control->property = NULL;
control->value = NULL;
control->hBitmap = NULL;
control->hIcon = NULL;
control->hDll = NULL;
control->tabnext = strdupW( MSI_RecordGetString( rec, 11) );
control->type = strdupW( MSI_RecordGetString( rec, 3 ) );
control->progress_current = 0;
control->progress_max = 100;
x = MSI_RecordGetInteger( rec, 4 );
y = MSI_RecordGetInteger( rec, 5 );
width = MSI_RecordGetInteger( rec, 6 );
height = MSI_RecordGetInteger( rec, 7 );
x = msi_dialog_scale_unit( dialog, x );
y = msi_dialog_scale_unit( dialog, y );
width = msi_dialog_scale_unit( dialog, width );
height = msi_dialog_scale_unit( dialog, height );
if( text )
{
deformat_string( dialog->package, text, &title_font );
font = msi_dialog_get_style( title_font, &title );
}
control->hwnd = CreateWindowExW( exstyle, szCls, title, style,
x, y, width, height, parent, NULL, NULL, NULL );
TRACE("Dialog %s control %s hwnd %p\n",
debugstr_w(dialog->name), debugstr_w(text), control->hwnd );
msi_dialog_set_font( dialog, control->hwnd,
font ? font : dialog->default_font );
msi_free( title_font );
msi_free( font );
return control;
}
static LPWSTR msi_dialog_get_uitext( msi_dialog *dialog, LPCWSTR key )
{
MSIRECORD *rec;
LPWSTR text;
static const WCHAR query[] = {
's','e','l','e','c','t',' ','*',' ',
'f','r','o','m',' ','`','U','I','T','e','x','t','`',' ',
'w','h','e','r','e',' ','`','K','e','y','`',' ','=',' ','\'','%','s','\'',0
};
rec = MSI_QueryGetRecord( dialog->package->db, query, key );
if (!rec) return NULL;
text = strdupW( MSI_RecordGetString( rec, 2 ) );
msiobj_release( &rec->hdr );
return text;
}
static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -