msi: Make the MSI SelectionTree control do something useful.

This commit is contained in:
Mike McCormack 2006-01-11 21:12:06 +01:00 committed by Alexandre Julliard
parent b54e9e94e9
commit 848f67e13e
4 changed files with 303 additions and 18 deletions

3
dlls/msi/.gitignore vendored
View File

@ -1,6 +1,9 @@
Makefile Makefile
cond.tab.c cond.tab.c
cond.tab.h cond.tab.h
instabsent.bmp
instadvert.bmp
instlocal.bmp
libmsi.def libmsi.def
msi.res msi.res
sql.tab.c sql.tab.c

View File

@ -4,7 +4,7 @@ SRCDIR = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
MODULE = msi.dll MODULE = msi.dll
IMPORTLIB = libmsi.$(IMPLIBEXT) IMPORTLIB = libmsi.$(IMPLIBEXT)
IMPORTS = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 IMPORTS = comctl32 shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
EXTRALIBS = -luuid $(LIBUNICODE) EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \ C_SRCS = \
@ -43,6 +43,11 @@ C_SRCS = \
where.c where.c
RC_SRCS = msi.rc RC_SRCS = msi.rc
RC_BINSRC = msi.rc
RC_BINARIES = \
instabsent.bmp \
instadvert.bmp \
instlocal.bmp
EXTRA_SRCS = sql.y cond.y EXTRA_SRCS = sql.y cond.y
EXTRA_OBJS = sql.tab.o cond.tab.o EXTRA_OBJS = sql.tab.o cond.tab.o

View File

@ -45,6 +45,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(msi); WINE_DEFAULT_DEBUG_CHANNEL(msi);
extern HINSTANCE msi_hInstance;
struct msi_control_tag; struct msi_control_tag;
typedef struct msi_control_tag msi_control; typedef struct msi_control_tag msi_control;
typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM ); typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM );
@ -1387,9 +1389,145 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
/******************** Selection Tree ***************************************/ /******************** Selection Tree ***************************************/
struct msi_selection_tree_info
{
msi_dialog *dialog;
HWND hwnd;
WNDPROC oldproc;
};
static void static void
msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd, msi_seltree_sync_item_state( HWND hwnd, MSIFEATURE *feature, HTREEITEM hItem )
LPCWSTR parent, HTREEITEM hParent ) {
TVITEMW tvi;
TRACE("Feature %s -> %d %d %d\n", debugstr_w(feature->Title),
feature->Installed, feature->Action, feature->ActionRequest);
tvi.mask = TVIF_STATE;
tvi.hItem = hItem;
tvi.state = INDEXTOSTATEIMAGEMASK( feature->Action );
tvi.stateMask = TVIS_STATEIMAGEMASK;
SendMessageW( hwnd, TVM_SETITEMW, 0, (LPARAM) &tvi );
}
static UINT
msi_seltree_popup_menu( HWND hwnd, INT x, INT y )
{
HMENU hMenu;
INT r;
/* create a menu to display */
hMenu = CreatePopupMenu();
/* FIXME: load strings from resources */
AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_LOCAL, "Install feature locally");
AppendMenuA( hMenu, MF_GRAYED, 0x1000, "Install entire feature");
AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ADVERTISED, "Install on demand");
AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ABSENT, "Don't install");
r = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
x, y, 0, hwnd, NULL );
DestroyMenu( hMenu );
return r;
}
static MSIFEATURE *
msi_seltree_feature_from_item( HWND hwnd, HTREEITEM hItem )
{
TVITEMW tvi;
/* get the feature from the item */
memset( &tvi, 0, sizeof tvi );
tvi.hItem = hItem;
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
SendMessageW( hwnd, TVM_GETITEMW, 0, (LPARAM) &tvi );
return (MSIFEATURE*) tvi.lParam;
}
static LRESULT
msi_seltree_menu( HWND hwnd, HTREEITEM hItem )
{
MSIFEATURE *feature;
union {
RECT rc;
POINT pt[2];
HTREEITEM hItem;
} u;
UINT r;
feature = msi_seltree_feature_from_item( hwnd, hItem );
if (!feature)
{
ERR("item %p feature was NULL\n", hItem);
return 0;
}
/* get the item's rectangle to put the menu just below it */
u.hItem = hItem;
SendMessageW( hwnd, TVM_GETITEMRECT, 0, (LPARAM) &u.rc );
MapWindowPoints( hwnd, NULL, u.pt, 2 );
r = msi_seltree_popup_menu( hwnd, u.rc.left, u.rc.top );
switch (r)
{
case INSTALLSTATE_LOCAL:
case INSTALLSTATE_ADVERTISED:
case INSTALLSTATE_ABSENT:
feature->ActionRequest = r;
feature->Action = r;
break;
default:
FIXME("select feature and all children\n");
}
/* update */
msi_seltree_sync_item_state( hwnd, feature, hItem );
return 0;
}
static LRESULT WINAPI
MSISelectionTree_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct msi_selection_tree_info *info;
TVHITTESTINFO tvhti;
HRESULT r;
TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam);
info = GetPropW(hWnd, szButtonData);
switch( msg )
{
case WM_LBUTTONDOWN:
tvhti.pt.x = LOWORD( lParam );
tvhti.pt.y = HIWORD( lParam );
tvhti.flags = 0;
tvhti.hItem = 0;
r = CallWindowProcW(info->oldproc, hWnd, TVM_HITTEST, 0, (LPARAM) &tvhti );
if (tvhti.flags & TVHT_ONITEMSTATEICON)
return msi_seltree_menu( hWnd, tvhti.hItem );
break;
}
r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam);
switch( msg )
{
case WM_NCDESTROY:
msi_free( info );
RemovePropW( hWnd, szButtonData );
break;
}
return r;
}
static void
msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd,
LPCWSTR parent, HTREEITEM hParent )
{ {
MSIFEATURE *feature; MSIFEATURE *feature;
TVINSERTSTRUCTW tvis; TVINSERTSTRUCTW tvis;
@ -1406,38 +1544,90 @@ msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
memset( &tvis, 0, sizeof tvis ); memset( &tvis, 0, sizeof tvis );
tvis.hParent = hParent; tvis.hParent = hParent;
tvis.hInsertAfter = TVI_SORT; tvis.hInsertAfter = TVI_SORT;
if (feature->Title) tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
{ tvis.u.item.pszText = feature->Title;
tvis.u.item.mask = TVIF_TEXT;
tvis.u.item.pszText = feature->Title;
}
tvis.u.item.lParam = (LPARAM) feature; tvis.u.item.lParam = (LPARAM) feature;
hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis ); hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis );
if (!hitem) if (!hitem)
continue; continue;
msi_dialog_tv_add_child_features( package, hwnd, msi_seltree_sync_item_state( hwnd, feature, hitem );
feature->Feature, hitem ); msi_seltree_add_child_features( package, hwnd,
feature->Feature, hitem );
} }
} }
static void msi_seltree_create_imagelist( HWND hwnd )
{
const int bm_width = 32, bm_height = 16, bm_count = 3;
const int bm_resource = 0x1001;
HIMAGELIST himl;
int i;
HBITMAP hbmp;
himl = ImageList_Create( bm_width, bm_height, FALSE, 4, 0 );
if (!himl)
{
ERR("failed to create image list\n");
return;
}
for (i=0; i<bm_count; i++)
{
hbmp = LoadBitmapW( msi_hInstance, MAKEINTRESOURCEW(i+bm_resource) );
if (!hbmp)
{
ERR("failed to load bitmap %d\n", i);
break;
}
/*
* Add a dummy bitmap at offset zero because the treeview
* can't use it as a state mask (zero means no user state).
*/
if (!i)
ImageList_Add( himl, hbmp, NULL );
ImageList_Add( himl, hbmp, NULL );
}
SendMessageW( hwnd, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl );
}
static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec ) static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec )
{ {
msi_control *control; msi_control *control;
LPCWSTR prop; LPCWSTR prop;
LPWSTR val;
MSIPACKAGE *package = dialog->package; MSIPACKAGE *package = dialog->package;
DWORD style;
struct msi_selection_tree_info *info;
prop = MSI_RecordGetString( rec, 9 ); info = msi_alloc( sizeof *info );
val = msi_dup_property( package, prop ); if (!info)
control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW,
TVS_HASBUTTONS | WS_GROUP | WS_VSCROLL );
if (!control)
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
msi_dialog_tv_add_child_features( package, control->hwnd, NULL, NULL ); /* create the treeview control */
prop = MSI_RecordGetString( rec, 9 );
style = TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT;
style |= WS_GROUP | WS_VSCROLL;
control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW, style );
if (!control)
{
msi_free(info);
return ERROR_FUNCTION_FAILED;
}
msi_free( val ); /* subclass */
info->dialog = dialog;
info->hwnd = control->hwnd;
info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
(LONG_PTR)MSISelectionTree_WndProc );
SetPropW( control->hwnd, szButtonData, info );
/* initialize it */
msi_seltree_create_imagelist( control->hwnd );
msi_seltree_add_child_features( package, control->hwnd, NULL, NULL );
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }

View File

@ -37,3 +37,90 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#include "msi_Nl.rc" #include "msi_Nl.rc"
#include "msi_No.rc" #include "msi_No.rc"
#include "msi_Pt.rc" #include "msi_Pt.rc"
/* BINRES instadvert.bmp */
0x1001 BITMAP instadvert.bmp
/* {
'42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
'00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 70 00 00 07 77 77 77 77'
'77 77 77 77 77 77 77 70 03 33 B3 30 07 77 77 77'
'77 77 77 77 77 77 77 00 B3 33 33 33 00 77 77 77'
'77 77 77 77 77 77 77 03 33 B3 A3 B3 30 77 77 77'
'77 77 07 77 77 77 70 33 33 33 33 33 B3 07 77 77'
'77 70 00 77 77 77 70 33 B3 30 03 33 33 07 77 77'
'77 00 00 07 77 77 70 33 33 00 00 3B 33 07 77 77'
'70 00 00 00 77 77 70 33 B3 30 0B 33 3B 07 77 77'
'00 00 00 00 07 77 70 3B 3A 33 33 33 33 07 77 70'
'00 00 00 00 00 77 77 03 3B 3B 3A 3B 30 77 77 77'
'77 77 77 77 77 77 77 00 33 33 3B 33 00 77 77 77'
'77 77 77 77 77 77 77 70 03 B3 33 30 07 77 77 77'
'77 77 77 77 77 77 77 77 70 00 00 07 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77'
} */
/* BINRES instabsent.bmp */
0x1002 BITMAP instabsent.bmp
/* {
'42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
'00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 70 07 77 77 77 77 70 07 77 77'
'77 77 77 77 77 77 70 00 77 77 77 77 00 07 77 77'
'77 77 77 77 77 77 77 00 07 77 77 70 00 77 77 77'
'77 77 77 77 77 77 77 70 00 77 77 00 07 77 77 77'
'77 77 77 77 77 77 77 77 00 07 70 00 77 77 77 77'
'77 77 07 77 77 77 77 77 70 00 00 07 77 77 77 77'
'77 70 00 77 77 77 77 77 77 00 00 77 77 77 77 77'
'77 00 00 07 77 77 77 77 77 00 00 77 77 77 77 77'
'70 00 00 00 77 77 77 77 70 00 00 07 77 77 77 77'
'00 00 00 00 07 77 77 77 00 07 70 00 77 77 77 70'
'00 00 00 00 00 77 77 70 00 77 77 00 07 77 77 77'
'77 77 77 77 77 77 77 00 07 77 77 70 00 77 77 77'
'77 77 77 77 77 77 70 00 77 77 77 77 00 07 77 77'
'77 77 77 77 77 77 70 07 77 77 77 77 70 07 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77'
} */
/* BINRES instlocal.bmp */
0x1003 BITMAP instlocal.bmp
/* {
'42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
'00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 70 07 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 0F F0 77 77 77 77 77 77'
'77 77 77 77 77 77 77 70 FF FF 07 77 77 77 77 77'
'77 77 07 77 77 77 77 0F F0 0F F0 77 77 77 77 77'
'77 70 00 77 77 77 77 0F 07 70 FF 07 77 77 77 77'
'77 00 00 07 77 77 77 70 77 77 0F F0 77 77 77 77'
'70 00 00 00 77 77 77 77 77 77 70 FF 07 77 77 77'
'00 00 00 00 07 77 77 77 77 77 77 0F F0 77 77 70'
'00 00 00 00 00 77 77 77 77 77 77 70 FF 07 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 0F F0 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 70 F0 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 07 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77'
} */