How to force an MSI dialog to repaint
November 21, 2008 12:13 PM   Subscribe

How to force Windows Installer (MSI) to redraw a listbox?

So we want to allow our users to set n configurations when they install our product. Each configuration is keyed to a value in a list box. The installer dialog, as designed, gives the user a listbox displaying the current config keys, a button to delete a value selected in the list box, an edit field for entering a new configuration key, and a button for adding said configuration key to the listbox table.

All works swimmingly except that the list box on the dialog screen does not refresh/repaint when a value has been added or removed. If the user cycles off the dialog (Previous / Next) and then returns to this screen after adding or removing a config key the listbox will show the current values. Per my PO, this is unacceptable (and I agree).

The only solution I've found to work is to create two identical dialog screens and toggle between them at the end of the add/remove action. This forces the repaint and from the end user's POV this process is transparent. Unfortunately, my PO doesn't find this solution acceptable either.

So, having exhausted Google and my patience with MSDN, I turn to the hive mind in the event someone else has come across this problem and solved it in a more elegant manner. If you think it might help, I can post code snippets and link to screencaps. I have a vested interest in getting this done today so I can leave at a reasonable hour.
posted by Fezboy! to Computers & Internet (8 answers total)
InvaliateRect on the ListBox's HWND and sending a WM_PAINT message doesn't work?
posted by orthogonality at 12:30 PM on November 21, 2008

Best answer: This is a quote from a post by Bill MacEachern elsewhere:

"There is no easy way to do this. I have heard of two methods, but they are both hacks and I haven't tried them. The first method was to just create a second dialog that is identical to the one with the listbox. After your CA runs, transition to the new dialog with the listbox properly filled. The second method involved placing a few events on your button. The first event is an EndDialog to nuke the current dialog. The second event is your custom action. The third event is a SpawnDialog with the same dialog as before, so oyu're essentially killing it, filling the listbox and then re-displaying it. "

Sorry, it's probably not the answer you hoped for! I've managed to avoid having anything to do with listboxes in my MSIs but from the sound of this you have a longish day ahead.

(responding to orthogonality: Windows Installer (MSI) Listboxes are totally different than Windows' ones; quite painful to manage.)
posted by anadem at 12:43 PM on November 21, 2008

Er, RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE) with the second and third parameters null should force the entire window to be redrawn. It returns (BOOL) true on success.

You can get the handle of the entore window, or just the handle of the list box.

HWND hWnd = GetApplicationOrListBoxHwnd();
printf(stderr, ( RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE) ? "Entire Window redrawn\n" : "ortho was wrong\n" ) );
posted by orthogonality at 12:45 PM on November 21, 2008

Response by poster:
HWND hWnd = GetApplicationOrListBoxHwnd();
printf(stderr, ( RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE) ? "Entire Window redrawn\n" : "ortho was wrong\n" ) );
I should probably elaborate that this is all being done in WIX so there's no programmability outside of CustomAction calls. I'm also discovering that it's not necessarily a redraw issue. The problem is that Windows Installer is creating the control based on the values in the ListBox table but that there is no dynamic link between the listbox control and the listbox table in the MSI database.

So to be clearer, I need a way to force Windows Installer to drop the listbox control and create a new one based on the updated listbox table.
posted by Fezboy! at 1:10 PM on November 21, 2008

Response by poster: Not to spam up my question thread, but the first method described, anadem, is the one I've got implemented and which my PO finds so offensive. The second is a play on the first and I tried that except for the EndDialog event so I kept getting 2856 errors. This may be enough to get sign-off. It's the maintenance of two identical (more or less) files that has the PO all shouty.
posted by Fezboy! at 1:13 PM on November 21, 2008

Oops,sorry I didn't digest your question enough to realize you were already using the method Bill described.

there is no dynamic link between the listbox control and the listbox table in the MSI database

I think that's the long and the short of it. Listbox implementation in msiexec is extremely basic (and despite being complained about hasn't really been improved in newer versions of msiexec.) Which you've already discovered so my post is pointless :-(
posted by anadem at 1:45 PM on November 21, 2008

I hate to say it, but: custom action using your own dialog and MsiSetProperty and MsiGetProperty. It's inelegant, but it'll save you a lot of time in the long run. I agree with anadem - MSI doesn't give you the kind of control you need, and any trick you discover could collapse in the next version of MSI.
posted by ignignokt at 2:13 PM on November 21, 2008

Response by poster: This was enough to convince the guy that I'm not sandbagging his installer so the twinned screen approach got the signature. That's the good. The bad is that next iteration I get to spend some quality time re-inventing listbox as a custom embedded UI.

At any rate, it's beer o'clock!

Oh, and I never got MacEachern's second option working. Instead of 2856 errors I got 2818 errors. Different. But not useful.
posted by Fezboy! at 2:32 PM on November 21, 2008

« Older Angel Eyes cover-who?   |   MacBook and Home Theater Newer »
This thread is closed to new comments.