cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
anom217
Level 8

Force cancel during custom action

I have a Basic MSI project and there are a couple CA's that use LaunchAppAndWait and execute some task, such as running database scripts. These processes are lengthy (10 min) and during the installation if the user presses the Cancel button nothing happens until after the LaunchAppAndWait is finished. The user just has to sit there not knowing why it isn't aborting.

So basically, how do I force a Cancel action when the user presses the Cancel button while a custom action is launching something something on the command line?
Labels (1)
0 Kudos
(4) Replies
joshstechnij
Level 10 Flexeran
Level 10 Flexeran

To determine if the cancel button was clicked, you need to send progress bar update messages to Windows Installer using the MsiProcessMessage API. MsiProcessMessage will return IDCANCEL (if I remember correctly) if the cancel button has been clicked. Your custom action then needs to return ERROR_INSTALL_USEREXIT (and your custom action needs to be set to check the exit code) to allow the install to exit.

Since you are waiting for a process to exit, you need to use the LaunchAppAndWait callback to poll for exit, similar to the following sample code:

function MyFunction(hMSI)
begin
LaunchApplication(WINDIR ^ "notepad.exe", "", "", SW_NORMAL, INFINITE, LAAW_OPTION_WAIT | LAAW_OPTION_USE_CALLBACK);

if(LAAW_PARAMETERS.bCallbackEndedWait) then
return ERROR_INSTALL_USEREXIT;
endif;
// To Do: Write script that will be executed when MyFunction is called.

end;

function number OnLaunchAppAndWaitCallback( )
begin
//
// MSI progress messages with MsiProcessMessage would
// need to be sent here.
//
if(MsiProcessMessage(...) = IDCANCEL) then
return LAAW_CALLBACK_RETURN_END_WAIT;
endif;

return LAAW_CALLBACK_RETURN_CONTINUE_TO_WAIT;
end;
0 Kudos
anom217
Level 8

Okay, I believe I understand to some degree. What I don't understand is how to call MsiProcessMessage without having a handle to the installer being passed as a parameter. This is what I have so far, but I know I need to get access to hMSI somehow.

function number OnLaunchAppAndWaitCallback()
HWND hRec;
begin
hRec = MsiCreateRecord(3);
MsiRecordSetInteger(hRec, 1, 1);
MsiRecordSetInteger(hRec, 2, 1);
MsiRecordSetInteger(hRec, 3, 0);
//
// MSI progress messages with MsiProcessMessage would
// need to be sent here.
//
if(MsiProcessMessage(hMSI, INSTALLMESSAGE_PROGRESS, hRec) = IDCANCEL) then
return LAAW_CALLBACK_RETURN_END_WAIT;
else
return LAAW_CALLBACK_RETURN_CONTINUE_TO_WAIT;
endif;

MsiCloseHandle(hRec);
end;


And this what my actual custom action does:
nResult = LaunchAppAndWait(szApp, szCmd, WAIT | LAAW_OPTION_HIDDEN | LAAW_OPTION_USE_CALLBACK);
// Exit if user presses Cancel button
if(LAAW_PARAMETERS.bCallbackEndedWait) then
return ERROR_INSTALL_USEREXIT;
endif;


I feel like I'm on the right track, but need some more help with what I have.
0 Kudos
joshstechnij
Level 10 Flexeran
Level 10 Flexeran

You should be able to use ISMSI_HANDLE as the installer session handle, or, in your custom action, store hMSI in a global variable (the callback runs in the same context as your custom action function, so global variables are available).
0 Kudos
anom217
Level 8

I think I have it working correctly. thanks!
0 Kudos