2006-02-17 00:04:10 +00:00
|
|
|
/*
|
|
|
|
* Implementation of the Microsoft Installer (msi.dll)
|
|
|
|
*
|
|
|
|
* Copyright 2005 Aric Stewart 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
|
2006-08-01 23:12:11 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winerror.h"
|
|
|
|
#include "winreg.h"
|
|
|
|
#include "msi.h"
|
|
|
|
#include "msipriv.h"
|
|
|
|
|
|
|
|
#include "wine/debug.h"
|
2006-08-01 23:12:11 +00:00
|
|
|
#include "wine/unicode.h"
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|
|
|
|
|
|
|
typedef UINT (*EVENTHANDLER)(MSIPACKAGE*,LPCWSTR,msi_dialog *);
|
|
|
|
|
|
|
|
struct _events {
|
|
|
|
LPCSTR event;
|
|
|
|
EVENTHANDLER handler;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct subscriber {
|
|
|
|
struct list entry;
|
2006-10-22 20:23:59 +00:00
|
|
|
msi_dialog *dialog;
|
2006-02-17 00:04:10 +00:00
|
|
|
LPWSTR event;
|
|
|
|
LPWSTR control;
|
|
|
|
LPWSTR attribute;
|
|
|
|
};
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog*);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a dialog box and run it if it's modal
|
|
|
|
*/
|
2006-10-22 20:23:59 +00:00
|
|
|
static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name, msi_dialog *parent, BOOL destroy_modeless )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
msi_dialog *dialog;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
/* create a new dialog */
|
2006-10-22 20:23:59 +00:00
|
|
|
dialog = msi_dialog_create( package, name, parent,
|
2006-02-17 00:04:10 +00:00
|
|
|
ControlEvent_HandleControlEvent );
|
|
|
|
if( dialog )
|
|
|
|
{
|
|
|
|
/* kill the current modeless dialog */
|
|
|
|
if( destroy_modeless && package->dialog )
|
|
|
|
{
|
|
|
|
msi_dialog_destroy( package->dialog );
|
|
|
|
package->dialog = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* modeless dialogs return an error message */
|
|
|
|
r = msi_dialog_run_message_loop( dialog );
|
|
|
|
if( r == ERROR_SUCCESS )
|
|
|
|
msi_dialog_destroy( dialog );
|
|
|
|
else
|
|
|
|
package->dialog = dialog;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
r = ERROR_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End a modal dialog box
|
|
|
|
*/
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument,
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog* dialog)
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
static const WCHAR szExit[] = {'E','x','i','t',0};
|
|
|
|
static const WCHAR szRetry[] = {'R','e','t','r','y',0};
|
|
|
|
static const WCHAR szIgnore[] = {'I','g','n','o','r','e',0};
|
|
|
|
static const WCHAR szReturn[] = {'R','e','t','u','r','n',0};
|
|
|
|
|
|
|
|
if (!strcmpW( argument, szExit ))
|
2006-02-17 00:04:10 +00:00
|
|
|
package->CurrentInstallState = ERROR_INSTALL_USEREXIT;
|
2011-03-20 08:47:41 +00:00
|
|
|
else if (!strcmpW( argument, szRetry ))
|
2006-02-17 00:04:10 +00:00
|
|
|
package->CurrentInstallState = ERROR_INSTALL_SUSPEND;
|
2011-03-20 08:47:41 +00:00
|
|
|
else if (!strcmpW( argument, szIgnore ))
|
2008-12-27 15:10:14 +00:00
|
|
|
package->CurrentInstallState = ERROR_SUCCESS;
|
2011-03-20 08:47:41 +00:00
|
|
|
else if (!strcmpW( argument, szReturn ))
|
2006-10-22 20:23:59 +00:00
|
|
|
{
|
|
|
|
msi_dialog *parent = msi_dialog_get_parent(dialog);
|
|
|
|
msi_free(package->next_dialog);
|
|
|
|
package->next_dialog = (parent) ? strdupW(msi_dialog_get_name(parent)) : NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
package->CurrentInstallState = ERROR_SUCCESS;
|
2006-10-22 20:23:59 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Unknown argument string %s\n",debugstr_w(argument));
|
|
|
|
package->CurrentInstallState = ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
ControlEvent_CleanupDialogSubscriptions(package, msi_dialog_get_name( dialog ));
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog_end_dialog( dialog );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transition from one modal dialog to another modal dialog
|
|
|
|
*/
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_NewDialog(MSIPACKAGE* package, LPCWSTR argument,
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog *dialog)
|
|
|
|
{
|
|
|
|
/* store the name of the next dialog, and signal this one to end */
|
|
|
|
package->next_dialog = strdupW(argument);
|
|
|
|
ControlEvent_CleanupSubscriptions(package);
|
|
|
|
msi_dialog_end_dialog( dialog );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new child dialog of an existing modal dialog
|
|
|
|
*/
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument,
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog *dialog)
|
|
|
|
{
|
|
|
|
/* don't destroy a modeless dialogs that might be our parent */
|
2006-10-22 20:23:59 +00:00
|
|
|
event_do_dialog( package, argument, dialog, FALSE );
|
2006-02-17 00:04:10 +00:00
|
|
|
if( package->CurrentInstallState != ERROR_SUCCESS )
|
|
|
|
msi_dialog_end_dialog( dialog );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Creates a dialog that remains up for a period of time
|
|
|
|
* based on a condition
|
|
|
|
*/
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_SpawnWaitDialog(MSIPACKAGE* package, LPCWSTR argument,
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog* dialog)
|
|
|
|
{
|
|
|
|
FIXME("Doing Nothing\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_DoAction(MSIPACKAGE* package, LPCWSTR argument,
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog* dialog)
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
ACTION_PerformAction(package, argument, -1);
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
static UINT ControlEvent_AddLocal( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIFEATURE *feature;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
|
|
|
|
{
|
|
|
|
if (feature->ActionRequest != INSTALLSTATE_LOCAL)
|
|
|
|
msi_set_property( package->db, szPreselected, szOne );
|
|
|
|
MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_LOCAL );
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
static UINT ControlEvent_Remove( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIFEATURE *feature;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
|
|
|
|
{
|
|
|
|
if (feature->ActionRequest != INSTALLSTATE_ABSENT)
|
|
|
|
msi_set_property( package->db, szPreselected, szOne );
|
|
|
|
MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_ABSENT );
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
static UINT ControlEvent_AddSource( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIFEATURE *feature;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
|
|
|
|
{
|
|
|
|
if (feature->ActionRequest != INSTALLSTATE_SOURCE)
|
|
|
|
msi_set_property( package->db, szPreselected, szOne );
|
|
|
|
MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_SOURCE );
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument,
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog* dialog)
|
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
LPWSTR path = msi_dup_property( package->db, argument );
|
2006-10-22 20:23:59 +00:00
|
|
|
MSIRECORD *rec = MSI_CreateRecord( 1 );
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT r;
|
2006-10-22 20:23:59 +00:00
|
|
|
|
|
|
|
static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0};
|
|
|
|
|
|
|
|
MSI_RecordSetStringW( rec, 1, path );
|
|
|
|
ControlEvent_FireSubscribedEvent( package, szSelectionPath, rec );
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/* failure to set the path halts the executing of control events */
|
|
|
|
r = MSI_SetTargetPathW(package, argument, path);
|
|
|
|
msi_free(path);
|
2006-10-22 20:23:59 +00:00
|
|
|
msi_free(&rec->hdr);
|
2006-02-17 00:04:10 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_Reset(MSIPACKAGE* package, LPCWSTR argument,
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_dialog* dialog)
|
|
|
|
{
|
|
|
|
msi_dialog_reset(dialog);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Subscribed events
|
|
|
|
*/
|
|
|
|
static void free_subscriber( struct subscriber *sub )
|
|
|
|
{
|
|
|
|
msi_free(sub->event);
|
|
|
|
msi_free(sub->control);
|
|
|
|
msi_free(sub->attribute);
|
|
|
|
msi_free(sub);
|
|
|
|
}
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, msi_dialog *dialog,
|
|
|
|
LPCWSTR event, LPCWSTR control, LPCWSTR attribute )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
struct subscriber *sub;
|
|
|
|
|
|
|
|
sub = msi_alloc(sizeof (*sub));
|
|
|
|
if( !sub )
|
|
|
|
return;
|
2006-10-22 20:23:59 +00:00
|
|
|
sub->dialog = dialog;
|
2006-02-17 00:04:10 +00:00
|
|
|
sub->event = strdupW(event);
|
|
|
|
sub->control = strdupW(control);
|
|
|
|
sub->attribute = strdupW(attribute);
|
|
|
|
list_add_tail( &package->subscriptions, &sub->entry );
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event,
|
2006-02-17 00:04:10 +00:00
|
|
|
MSIRECORD *rec )
|
|
|
|
{
|
|
|
|
struct subscriber *sub;
|
|
|
|
|
|
|
|
TRACE("Firing Event %s\n",debugstr_w(event));
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry )
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (strcmpiW( sub->event, event ))
|
2006-02-17 00:04:10 +00:00
|
|
|
continue;
|
2011-03-20 08:47:41 +00:00
|
|
|
msi_dialog_handle_event( sub->dialog, sub->control, sub->attribute, rec );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
VOID ControlEvent_CleanupDialogSubscriptions(MSIPACKAGE *package, LPWSTR dialog)
|
|
|
|
{
|
|
|
|
struct list *i, *t;
|
|
|
|
struct subscriber *sub;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
|
|
|
|
{
|
|
|
|
sub = LIST_ENTRY( i, struct subscriber, entry );
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (strcmpW( msi_dialog_get_name( sub->dialog ), dialog ))
|
2008-01-16 10:11:22 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
list_remove( &sub->entry );
|
|
|
|
free_subscriber( sub );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
struct list *i, *t;
|
|
|
|
struct subscriber *sub;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
|
|
|
|
{
|
|
|
|
sub = LIST_ENTRY( i, struct subscriber, entry );
|
|
|
|
|
|
|
|
list_remove( &sub->entry );
|
|
|
|
free_subscriber( sub );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ACTION_DialogBox()
|
|
|
|
*
|
|
|
|
* Return ERROR_SUCCESS if dialog is process and ERROR_FUNCTION_FAILED
|
|
|
|
* if the given parameter is not a dialog box
|
|
|
|
*/
|
|
|
|
UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName )
|
|
|
|
{
|
|
|
|
UINT r = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if( package->next_dialog )
|
|
|
|
ERR("Already a next dialog... ignoring it\n");
|
|
|
|
package->next_dialog = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Dialogs are chained by filling in the next_dialog member
|
|
|
|
* of the package structure, then terminating the current dialog.
|
|
|
|
* The code below sees the next_dialog member set, and runs the
|
|
|
|
* next dialog.
|
|
|
|
* We fall out of the loop below if we come across a modeless
|
|
|
|
* dialog, as it returns ERROR_IO_PENDING when we try to run
|
|
|
|
* its message loop.
|
|
|
|
*/
|
2006-10-22 20:23:59 +00:00
|
|
|
r = event_do_dialog( package, szDialogName, NULL, TRUE );
|
2006-02-17 00:04:10 +00:00
|
|
|
while( r == ERROR_SUCCESS && package->next_dialog )
|
|
|
|
{
|
|
|
|
LPWSTR name = package->next_dialog;
|
|
|
|
|
|
|
|
package->next_dialog = NULL;
|
2006-10-22 20:23:59 +00:00
|
|
|
r = event_do_dialog( package, name, NULL, TRUE );
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( r == ERROR_IO_PENDING )
|
|
|
|
r = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
static UINT ControlEvent_SetInstallLevel(MSIPACKAGE* package, LPCWSTR argument,
|
|
|
|
msi_dialog* dialog)
|
|
|
|
{
|
|
|
|
int iInstallLevel = atolW(argument);
|
|
|
|
|
|
|
|
TRACE("Setting install level: %i\n", iInstallLevel);
|
|
|
|
|
|
|
|
return MSI_SetInstallLevel( package, iInstallLevel );
|
|
|
|
}
|
|
|
|
|
2006-08-30 19:24:26 +00:00
|
|
|
static UINT ControlEvent_DirectoryListUp(MSIPACKAGE *package, LPCWSTR argument,
|
|
|
|
msi_dialog *dialog)
|
|
|
|
{
|
|
|
|
return msi_dialog_directorylist_up( dialog );
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ControlEvent_ReinstallMode(MSIPACKAGE *package, LPCWSTR argument,
|
|
|
|
msi_dialog *dialog)
|
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
return msi_set_property( package->db, szReinstallMode, argument );
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ControlEvent_Reinstall( MSIPACKAGE *package, LPCWSTR argument,
|
|
|
|
msi_dialog *dialog )
|
|
|
|
{
|
|
|
|
return msi_set_property( package->db, szReinstall, argument );
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
static UINT ControlEvent_ValidateProductID(MSIPACKAGE *package, LPCWSTR argument,
|
|
|
|
msi_dialog *dialog)
|
|
|
|
{
|
|
|
|
LPWSTR key, template;
|
|
|
|
UINT ret = ERROR_SUCCESS;
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
template = msi_dup_property( package->db, szPIDTemplate );
|
|
|
|
key = msi_dup_property( package->db, szPIDKEY );
|
2010-02-06 21:28:28 +00:00
|
|
|
|
|
|
|
if (key && template)
|
|
|
|
{
|
|
|
|
FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
|
2010-05-29 08:55:43 +00:00
|
|
|
ret = msi_set_property( package->db, szProductID, key );
|
2010-02-06 21:28:28 +00:00
|
|
|
}
|
|
|
|
msi_free( template );
|
|
|
|
msi_free( key );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
static const struct _events Events[] = {
|
2006-02-17 00:04:10 +00:00
|
|
|
{ "EndDialog",ControlEvent_EndDialog },
|
|
|
|
{ "NewDialog",ControlEvent_NewDialog },
|
|
|
|
{ "SpawnDialog",ControlEvent_SpawnDialog },
|
|
|
|
{ "SpawnWaitDialog",ControlEvent_SpawnWaitDialog },
|
|
|
|
{ "DoAction",ControlEvent_DoAction },
|
|
|
|
{ "AddLocal",ControlEvent_AddLocal },
|
|
|
|
{ "Remove",ControlEvent_Remove },
|
|
|
|
{ "AddSource",ControlEvent_AddSource },
|
|
|
|
{ "SetTargetPath",ControlEvent_SetTargetPath },
|
|
|
|
{ "Reset",ControlEvent_Reset },
|
2006-08-01 23:12:11 +00:00
|
|
|
{ "SetInstallLevel",ControlEvent_SetInstallLevel },
|
2006-08-30 19:24:26 +00:00
|
|
|
{ "DirectoryListUp",ControlEvent_DirectoryListUp },
|
2006-10-22 20:23:59 +00:00
|
|
|
{ "SelectionBrowse",ControlEvent_SpawnDialog },
|
2008-01-16 10:11:22 +00:00
|
|
|
{ "ReinstallMode",ControlEvent_ReinstallMode },
|
2010-05-29 08:55:43 +00:00
|
|
|
{ "Reinstall",ControlEvent_Reinstall },
|
2010-02-06 21:28:28 +00:00
|
|
|
{ "ValidateProductID",ControlEvent_ValidateProductID },
|
2006-02-17 00:04:10 +00:00
|
|
|
{ NULL,NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
UINT ControlEvent_HandleControlEvent(MSIPACKAGE *package, LPCWSTR event,
|
|
|
|
LPCWSTR argument, msi_dialog* dialog)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
UINT rc = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
TRACE("Handling Control Event %s\n",debugstr_w(event));
|
|
|
|
if (!event)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
while( Events[i].event != NULL)
|
|
|
|
{
|
|
|
|
LPWSTR wevent = strdupAtoW(Events[i].event);
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!strcmpW( wevent, event ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
msi_free(wevent);
|
|
|
|
rc = Events[i].handler(package,argument,dialog);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
msi_free(wevent);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
FIXME("unhandled control event %s arg(%s)\n",
|
|
|
|
debugstr_w(event), debugstr_w(argument));
|
|
|
|
return rc;
|
|
|
|
}
|