Jump to content


This is a ready-only archive of the InstallSite Forum. You cannot post any new content here. / Dies ist ein Archiv des InstallSite Forums. Hier können keine neuen Beiträge veröffentlicht werden.
Photo

dynamic controls in dialog


9 replies to this topic

hsong3

hsong3
  • Members
  • 89 posts

Posted 08 January 2004 - 01:02

hello

this is the senario.

(1) i need to get some items during runtime (from txt or ini file. but total number of items are unknown)

(2) then these items are stored in list box (or some other dialog form). and user can select items from these entries.

(3) each entry has either indicator or flag when it is selected. and it uses that to call other function or dialog.

is this possible??

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 08 January 2004 - 08:41

Yes. You would write a custom action that reads the file, then uses MSI-SQL statements to add temporary rows to the ListBox table. Note that there are no multi-select list boxes in MSI so your user can only select one entry.

hsong3

hsong3
  • Members
  • 89 posts

Posted 08 January 2004 - 15:18

thank you for replying..

is there any way that the user can select multiple items??
if list bix is not an option then what else can i try?? would selection tree work??

thank you

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 08 January 2004 - 17:30

selection tree only work on features.
You could dynamically add check boxes to a dialog, but only if the number of items is not too large.

What I did in a similar case was: create two list boxes, with an "add" button that moves items from list 1 ("available items") to list 2 ("selected items"). There are some tricks involved and it's too long to post the explanation here.

Another alternative would be calling an external dialog.

hsong3

hsong3
  • Members
  • 89 posts

Posted 08 January 2004 - 22:40

thank you stefan, i'll try your method: 2 list boxes.

cooki

cooki
  • Full Members
  • 35 posts

Posted 13 August 2004 - 11:09

I have the same problem than hsong3 with a ListView, however i musn't use the "2 lists" trick.
In a msi custom action, i tried to create a temporary entry with the following SQL request:
INSERT INTO ListView(Property,Order,Value,Text,Binary_) VALUES('TARGETS_LIST','9','9','','') TEMPORARY
but MsiDatabaseOpenView returns error 1615. any idea why? the request seems correct to me.

I had also the idea to make the 'Property' column localizable, so that it would be formatted at runtime. example: [TEST] becomes the value of property TEST. I would set the value of TEST to the Property of the ListView if i wanted to display it, and anything else in the other case. I changed the table so, but [TEST] isn't formatted. Is there a chance that method could work?

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 13 August 2004 - 11:25

Try this SQL query instead:

INSERT INTO `ListView` ( `Property`, `Order`, `Value`, `Text,Binary_`) VALUES('TARGETS_LIST','9','9',NULL,NULL) TEMPORARY

I added some grave accents to avoid conflicts with SQL keywords, and I changed your empty strings to NULL values.

The Property colum is not localizable - why would you localize the property name?
As it is now, the TARGETS_LIST property will be set to 9 if the users selects that entry. Both the Value and the text fields are formatted, so you could display the value in the user's language, e.g.:

INSERT INTO `ListView` ( `Property`, `Order`, `Value`, `Text,Binary_`) VALUES('TARGETS_LIST','9','[NINE]',NULL,NULL) TEMPORARY

where you could set NINE = "nine" for English or NINE = "neun" for German

cooki

cooki
  • Full Members
  • 35 posts

Posted 13 August 2004 - 12:37

Thx, now the SQL request works fine.

It doesn't matter now, but the purpose of the other thing was:
fill the ListView Table with such lines:
'[TEST1]','1','1',NULL,NULL
'[TEST2]','2','2',NULL,NULL
.
.
.

define properties TEST1, TEST2... and TARGETS_LIST
the listview would be related to TARGETS_LIST

at runtime, if i wanted to see the line with order x, then set TESTx to TARGETS_LIST.
That's why i wanted to make the 'Property' column of Table ListView localizable

It's a little heavy mechanism, and since the temporary insert works i will use it.

You were quite fast to answer, thx again.


NB: I don't know why everybody says you can't make a listview become multi-select, you just need to find the window through it's name and look for controls' IDs. when you have identified which one is the CListCtrl then "listCtrl.ModifyStyle(LVS_SINGLESEL,0);" . It's OK, i already did it.

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 13 August 2004 - 14:49

QUOTE
'[TEST1]','1','1',NULL,NULL
'[TEST2]','2','2',NULL,NULL

This would define two different list views. Associated entries are identified by identical values in the first column. Since the first two columns are the keys of this msi database table you can't sue properties here.
You could use something liker MYLIST and later assign the value of MYLIST to TARGETS_LIST

I understand that you can dynamically change the style bits of the listview (care to share your code?) but how do you return the selected entires? It was my understanding that MSI assigns the one selected item to the property that's associated with the listview.

cooki

cooki
  • Full Members
  • 35 posts

Posted 13 August 2004 - 16:06

here is the function to find the dialog handle and its control which has the style seeked:

HWND __stdcall findListView(MSIHANDLE hInstall, CString szDialog, LONG_PTR styleSeeked)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

CString szTitle;
DWORD nSize;
PMSIHANDLE hDatabase, hView, hRecord, hRecord2;

// retrieve the title of the dialog
hDatabase = MsiGetActiveDatabase(hInstall);
MsiDatabaseOpenView(hDatabase, _T("SELECT `Title` FROM `Dialog` WHERE `Dialog`=\'") + szDialog + _T("\'"),&hView);
MsiViewExecute(hView,0);
MsiViewFetch(hView,&hRecord);

nSize=1024;
MsiRecordGetString(hRecord,1,szTitle.GetBufferSetLength(nSize),&nSize);
szTitle.ReleaseBuffer();

hRecord2 = MsiCreateRecord(1);
MsiRecordSetString(hRecord2,0,szTitle);
nSize=1024;
MsiFormatRecord(hInstall,hRecord2,szTitle.GetBufferSetLength(nSize),&nSize);
szTitle.ReleaseBuffer();

// get the dialog handle through its title
HWND hWnd = FindWindow(NULL,szTitle);

// get the listview through its parent and its style
// to find the right and whole style, use spy++
LONG_PTR styleCtrl;
HWND ctrl = ::GetNextDlgTabItem(hWnd,NULL,FALSE);
HWND lastCtrl = ::GetNextDlgTabItem(hWnd,ctrl,TRUE);
styleCtrl = GetWindowLongPtr(ctrl,GWL_STYLE);
while( ctrl!=lastCtrl && styleSeeked!=styleCtrl )
{
ctrl = ::GetNextDlgTabItem(hWnd,ctrl,FALSE);
styleCtrl = GetWindowLongPtr(ctrl,GWL_STYLE);
}

if( styleSeeked==styleCtrl )
return ctrl;
else
return 0;
}

the calling function, which changes the style of the listview:
this function must be from asynchronous type, and be called from the previous dialog when clicking "next" and just before calling "nextdialog"
WARNING: must make some changes if there are several controls with the same style in the dialog !!!

UINT __stdcall beginSelectTargets(MSIHANDLE hInstall)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

HWND ctrl;
LONG_PTR styleSeeked = LVS_REPORT|LVS_NOCOLUMNHEADER|WS_CHILDWINDOW|WS_VISIBLE|WS_BORDER|WS_GROUP|LVS_SHAREIMAGELISTS|LVS_SINGLESEL|LVS_SHOWSELALWAYS|WS_TABSTOP;
if( (ctrl=findListView(hInstall, _T("DestinationFolder"),styleSeeked))!=0 )
{
CListCtrl listCtrl;
listCtrl.Attach(ctrl);

// change of style
listCtrl.ModifyStyle(LVS_SINGLESEL,0);
listCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT);

listCtrl.Detach();
}

return ERROR_SUCCESS;
}

to retrieve the selected items and bring the control to its initial style:
UINT __stdcall endSelectTargets(MSIHANDLE hInstall)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

HWND ctrl;
LONG_PTR styleSeeked = LVS_REPORT|LVS_NOCOLUMNHEADER|WS_CHILDWINDOW|WS_VISIBLE|WS_BORDER|WS_GROUP|LVS_SHAREIMAGELISTS|LVS_SHOWSELALWAYS|WS_TABSTOP;
if( (ctrl=findListView(hInstall, _T("DestinationFolder"),styleSeeked))!=0 )
{
CListCtrl listCtrl;
listCtrl.Attach(ctrl);

int index;
CString szBuffer;
POSITION pos = listCtrl.GetFirstSelectedItemPosition();
while( pos )
{
index = listCtrl.GetNextSelectedItem(pos);
// not finished: my idea is to compare orders in the listview and in the database
}

listCtrl.ModifyStyle(0,LVS_SINGLESEL);
listCtrl.ModifyStyleEx(LVS_EX_FULLROWSELECT,0);

listCtrl.Detach();
}

return ERROR_SUCCESS;
}