ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

events.c
Go to the documentation of this file.
00001 /*
00002  * Implementation of the Microsoft Installer (msi.dll)
00003  *
00004  * Copyright 2005 Aric Stewart for CodeWeavers
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <stdarg.h>
00022 #include <stdio.h>
00023 
00024 #include "windef.h"
00025 #include "winbase.h"
00026 #include "winerror.h"
00027 #include "winreg.h"
00028 #include "msi.h"
00029 #include "msipriv.h"
00030 
00031 #include "wine/debug.h"
00032 #include "wine/unicode.h"
00033 
00034 WINE_DEFAULT_DEBUG_CHANNEL(msi);
00035 
00036 typedef UINT (*EVENTHANDLER)(MSIPACKAGE*,LPCWSTR,msi_dialog *);
00037 
00038 struct control_events
00039 {
00040     const WCHAR *event;
00041     EVENTHANDLER handler;
00042 };
00043 
00044 struct subscriber {
00045     struct list entry;
00046     msi_dialog *dialog;
00047     LPWSTR event;
00048     LPWSTR control;
00049     LPWSTR attribute;
00050 };
00051 
00052 static UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog*);
00053 
00054 /*
00055  * Create a dialog box and run it if it's modal
00056  */
00057 static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name, msi_dialog *parent, BOOL destroy_modeless )
00058 {
00059     msi_dialog *dialog;
00060     UINT r;
00061 
00062     /* create a new dialog */
00063     dialog = msi_dialog_create( package, name, parent,
00064                                 ControlEvent_HandleControlEvent );
00065     if( dialog )
00066     {
00067         /* kill the current modeless dialog */
00068         if( destroy_modeless && package->dialog )
00069         {
00070             msi_dialog_destroy( package->dialog );
00071             package->dialog = NULL;
00072         }
00073 
00074         /* modeless dialogs return an error message */
00075         r = msi_dialog_run_message_loop( dialog );
00076         if( r == ERROR_SUCCESS )
00077             msi_dialog_destroy( dialog );
00078         else
00079             package->dialog = dialog;
00080     }
00081     else
00082         r = ERROR_FUNCTION_FAILED;
00083 
00084     return r;
00085 }
00086 
00087 
00088 /*
00089  * End a modal dialog box
00090  */
00091 static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument, 
00092                                    msi_dialog* dialog)
00093 {
00094     static const WCHAR szExit[] = {'E','x','i','t',0};
00095     static const WCHAR szRetry[] = {'R','e','t','r','y',0};
00096     static const WCHAR szIgnore[] = {'I','g','n','o','r','e',0};
00097     static const WCHAR szReturn[] = {'R','e','t','u','r','n',0};
00098 
00099     if (!strcmpW( argument, szExit ))
00100         package->CurrentInstallState = ERROR_INSTALL_USEREXIT;
00101     else if (!strcmpW( argument, szRetry ))
00102         package->CurrentInstallState = ERROR_INSTALL_SUSPEND;
00103     else if (!strcmpW( argument, szIgnore ))
00104         package->CurrentInstallState = ERROR_SUCCESS;
00105     else if (!strcmpW( argument, szReturn ))
00106     {
00107         msi_dialog *parent = msi_dialog_get_parent(dialog);
00108         msi_free(package->next_dialog);
00109         package->next_dialog = (parent) ? strdupW(msi_dialog_get_name(parent)) : NULL;
00110         package->CurrentInstallState = ERROR_SUCCESS;
00111     }
00112     else
00113     {
00114         ERR("Unknown argument string %s\n",debugstr_w(argument));
00115         package->CurrentInstallState = ERROR_FUNCTION_FAILED;
00116     }
00117 
00118     ControlEvent_CleanupDialogSubscriptions(package, msi_dialog_get_name( dialog ));
00119     msi_dialog_end_dialog( dialog );
00120     return ERROR_SUCCESS;
00121 }
00122 
00123 /*
00124  * transition from one modal dialog to another modal dialog
00125  */
00126 static UINT ControlEvent_NewDialog(MSIPACKAGE* package, LPCWSTR argument, 
00127                                    msi_dialog *dialog)
00128 {
00129     /* store the name of the next dialog, and signal this one to end */
00130     package->next_dialog = strdupW(argument);
00131     ControlEvent_CleanupSubscriptions(package);
00132     msi_dialog_end_dialog( dialog );
00133     return ERROR_SUCCESS;
00134 }
00135 
00136 /*
00137  * Create a new child dialog of an existing modal dialog
00138  */
00139 static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument, 
00140                               msi_dialog *dialog)
00141 {
00142     /* don't destroy a modeless dialogs that might be our parent */
00143     event_do_dialog( package, argument, dialog, FALSE );
00144     if( package->CurrentInstallState != ERROR_SUCCESS )
00145         msi_dialog_end_dialog( dialog );
00146     return ERROR_SUCCESS;
00147 }
00148 
00149 /*
00150  * Creates a dialog that remains up for a period of time
00151  * based on a condition
00152  */
00153 static UINT ControlEvent_SpawnWaitDialog(MSIPACKAGE* package, LPCWSTR argument, 
00154                                   msi_dialog* dialog)
00155 {
00156     FIXME("Doing Nothing\n");
00157     return ERROR_SUCCESS;
00158 }
00159 
00160 static UINT ControlEvent_DoAction(MSIPACKAGE* package, LPCWSTR argument, 
00161                                   msi_dialog* dialog)
00162 {
00163     ACTION_PerformAction(package, argument, SCRIPT_NONE);
00164     return ERROR_SUCCESS;
00165 }
00166 
00167 static UINT ControlEvent_AddLocal( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
00168 {
00169     MSIFEATURE *feature;
00170 
00171     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
00172     {
00173         if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
00174         {
00175             if (feature->ActionRequest != INSTALLSTATE_LOCAL)
00176                 msi_set_property( package->db, szPreselected, szOne );
00177             MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_LOCAL );
00178         }
00179     }
00180     return ERROR_SUCCESS;
00181 }
00182 
00183 static UINT ControlEvent_Remove( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
00184 {
00185     MSIFEATURE *feature;
00186 
00187     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
00188     {
00189         if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
00190         {
00191             if (feature->ActionRequest != INSTALLSTATE_ABSENT)
00192                 msi_set_property( package->db, szPreselected, szOne );
00193             MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_ABSENT );
00194         }
00195     }
00196     return ERROR_SUCCESS;
00197 }
00198 
00199 static UINT ControlEvent_AddSource( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
00200 {
00201     MSIFEATURE *feature;
00202 
00203     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
00204     {
00205         if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
00206         {
00207             if (feature->ActionRequest != INSTALLSTATE_SOURCE)
00208                 msi_set_property( package->db, szPreselected, szOne );
00209             MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_SOURCE );
00210         }
00211     }
00212     return ERROR_SUCCESS;
00213 }
00214 
00215 static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument, 
00216                                    msi_dialog* dialog)
00217 {
00218     static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0};
00219     LPWSTR path = msi_dup_property( package->db, argument );
00220     MSIRECORD *rec = MSI_CreateRecord( 1 );
00221     UINT r = ERROR_SUCCESS;
00222 
00223     MSI_RecordSetStringW( rec, 1, path );
00224     ControlEvent_FireSubscribedEvent( package, szSelectionPath, rec );
00225     if (path)
00226     {
00227         /* failure to set the path halts the executing of control events */
00228         r = MSI_SetTargetPathW(package, argument, path);
00229         msi_free(path);
00230     }
00231     msi_free(&rec->hdr);
00232     return r;
00233 }
00234 
00235 static UINT ControlEvent_Reset(MSIPACKAGE* package, LPCWSTR argument, 
00236                                    msi_dialog* dialog)
00237 {
00238     msi_dialog_reset(dialog);
00239     return ERROR_SUCCESS;
00240 }
00241 
00242 /*
00243  * Subscribed events
00244  */
00245 static void free_subscriber( struct subscriber *sub )
00246 {
00247     msi_free(sub->event);
00248     msi_free(sub->control);
00249     msi_free(sub->attribute);
00250     msi_free(sub);
00251 }
00252 
00253 VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, msi_dialog *dialog,
00254                                     LPCWSTR event, LPCWSTR control, LPCWSTR attribute )
00255 {
00256     struct subscriber *sub;
00257 
00258     TRACE("event %s control %s attribute %s\n", debugstr_w(event), debugstr_w(control), debugstr_w(attribute));
00259 
00260     LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry )
00261     {
00262         if (!strcmpiW( sub->event, event ) &&
00263             !strcmpiW( sub->control, control ) &&
00264             !strcmpiW( sub->attribute, attribute ))
00265         {
00266             TRACE("already subscribed\n");
00267             return;
00268         };
00269     }
00270     if (!(sub = msi_alloc( sizeof(*sub) ))) return;
00271     sub->dialog = dialog;
00272     sub->event = strdupW(event);
00273     sub->control = strdupW(control);
00274     sub->attribute = strdupW(attribute);
00275     list_add_tail( &package->subscriptions, &sub->entry );
00276 }
00277 
00278 VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event, MSIRECORD *rec )
00279 {
00280     struct subscriber *sub;
00281 
00282     TRACE("Firing event %s\n", debugstr_w(event));
00283 
00284     LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry )
00285     {
00286         if (strcmpiW( sub->event, event )) continue;
00287         msi_dialog_handle_event( sub->dialog, sub->control, sub->attribute, rec );
00288     }
00289 }
00290 
00291 VOID ControlEvent_CleanupDialogSubscriptions(MSIPACKAGE *package, LPWSTR dialog)
00292 {
00293     struct list *i, *t;
00294     struct subscriber *sub;
00295 
00296     LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
00297     {
00298         sub = LIST_ENTRY( i, struct subscriber, entry );
00299 
00300         if (strcmpW( msi_dialog_get_name( sub->dialog ), dialog ))
00301             continue;
00302 
00303         list_remove( &sub->entry );
00304         free_subscriber( sub );
00305     }
00306 }
00307 
00308 VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package)
00309 {
00310     struct list *i, *t;
00311     struct subscriber *sub;
00312 
00313     LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
00314     {
00315         sub = LIST_ENTRY( i, struct subscriber, entry );
00316 
00317         list_remove( &sub->entry );
00318         free_subscriber( sub );
00319     }
00320 }
00321 
00322 /*
00323  * ACTION_DialogBox()
00324  *
00325  * Return ERROR_SUCCESS if dialog is process and ERROR_FUNCTION_FAILED
00326  * if the given parameter is not a dialog box
00327  */
00328 UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName )
00329 {
00330     UINT r = ERROR_SUCCESS;
00331 
00332     if( package->next_dialog )
00333         ERR("Already a next dialog... ignoring it\n");
00334     package->next_dialog = NULL;
00335 
00336     /*
00337      * Dialogs are chained by filling in the next_dialog member
00338      *  of the package structure, then terminating the current dialog.
00339      *  The code below sees the next_dialog member set, and runs the
00340      *  next dialog.
00341      * We fall out of the loop below if we come across a modeless
00342      *  dialog, as it returns ERROR_IO_PENDING when we try to run
00343      *  its message loop.
00344      */
00345     r = event_do_dialog( package, szDialogName, NULL, TRUE );
00346     while( r == ERROR_SUCCESS && package->next_dialog )
00347     {
00348         LPWSTR name = package->next_dialog;
00349 
00350         package->next_dialog = NULL;
00351         r = event_do_dialog( package, name, NULL, TRUE );
00352         msi_free( name );
00353     }
00354 
00355     if( r == ERROR_IO_PENDING )
00356         r = ERROR_SUCCESS;
00357 
00358     return r;
00359 }
00360 
00361 static UINT ControlEvent_SetInstallLevel(MSIPACKAGE* package, LPCWSTR argument,
00362                                           msi_dialog* dialog)
00363 {
00364     int iInstallLevel = atolW(argument);
00365 
00366     TRACE("Setting install level: %i\n", iInstallLevel);
00367 
00368     return MSI_SetInstallLevel( package, iInstallLevel );
00369 }
00370 
00371 static UINT ControlEvent_DirectoryListUp(MSIPACKAGE *package, LPCWSTR argument,
00372                                          msi_dialog *dialog)
00373 {
00374     return msi_dialog_directorylist_up( dialog );
00375 }
00376 
00377 static UINT ControlEvent_ReinstallMode(MSIPACKAGE *package, LPCWSTR argument,
00378                                        msi_dialog *dialog)
00379 {
00380     return msi_set_property( package->db, szReinstallMode, argument );
00381 }
00382 
00383 static UINT ControlEvent_Reinstall( MSIPACKAGE *package, LPCWSTR argument,
00384                                     msi_dialog *dialog )
00385 {
00386     return msi_set_property( package->db, szReinstall, argument );
00387 }
00388 
00389 static UINT ControlEvent_ValidateProductID(MSIPACKAGE *package, LPCWSTR argument,
00390                                            msi_dialog *dialog)
00391 {
00392     return msi_validate_product_id( package );
00393 }
00394 
00395 static const WCHAR end_dialogW[] = {'E','n','d','D','i','a','l','o','g',0};
00396 static const WCHAR new_dialogW[] = {'N','e','w','D','i','a','l','o','g',0};
00397 static const WCHAR spawn_dialogW[] = {'S','p','a','w','n','D','i','a','l','o','g',0};
00398 static const WCHAR spawn_wait_dialogW[] = {'S','p','a','w','n','W','a','i','t','D','i','a','l','o','g',0};
00399 static const WCHAR do_actionW[] = {'D','o','A','c','t','i','o','n',0};
00400 static const WCHAR add_localW[] = {'A','d','d','L','o','c','a','l',0};
00401 static const WCHAR removeW[] = {'R','e','m','o','v','e',0};
00402 static const WCHAR add_sourceW[] = {'A','d','d','S','o','u','r','c','e',0};
00403 static const WCHAR set_target_pathW[] = {'S','e','t','T','a','r','g','e','t','P','a','t','h',0};
00404 static const WCHAR resetW[] = {'R','e','s','e','t',0};
00405 static const WCHAR set_install_levelW[] = {'S','e','t','I','n','s','t','a','l','l','L','e','v','e','l',0};
00406 static const WCHAR directory_list_upW[] = {'D','i','r','e','c','t','o','r','y','L','i','s','t','U','p',0};
00407 static const WCHAR selection_browseW[] = {'S','e','l','e','c','t','i','o','n','B','r','o','w','s','e',0};
00408 static const WCHAR reinstall_modeW[] = {'R','e','i','n','s','t','a','l','l','M','o','d','e',0};
00409 static const WCHAR reinstallW[] = {'R','e','i','n','s','t','a','l','l',0};
00410 static const WCHAR validate_product_idW[] = {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
00411 
00412 static const struct control_events control_events[] =
00413 {
00414     { end_dialogW, ControlEvent_EndDialog },
00415     { new_dialogW, ControlEvent_NewDialog },
00416     { spawn_dialogW, ControlEvent_SpawnDialog },
00417     { spawn_wait_dialogW, ControlEvent_SpawnWaitDialog },
00418     { do_actionW, ControlEvent_DoAction },
00419     { add_localW, ControlEvent_AddLocal },
00420     { removeW, ControlEvent_Remove },
00421     { add_sourceW, ControlEvent_AddSource },
00422     { set_target_pathW, ControlEvent_SetTargetPath },
00423     { resetW, ControlEvent_Reset },
00424     { set_install_levelW, ControlEvent_SetInstallLevel },
00425     { directory_list_upW, ControlEvent_DirectoryListUp },
00426     { selection_browseW, ControlEvent_SpawnDialog },
00427     { reinstall_modeW, ControlEvent_ReinstallMode },
00428     { reinstallW, ControlEvent_Reinstall },
00429     { validate_product_idW, ControlEvent_ValidateProductID },
00430     { NULL, NULL }
00431 };
00432 
00433 UINT ControlEvent_HandleControlEvent( MSIPACKAGE *package, LPCWSTR event,
00434                                       LPCWSTR argument, msi_dialog *dialog )
00435 {
00436     unsigned int i;
00437 
00438     TRACE("handling control event %s\n", debugstr_w(event));
00439 
00440     if (!event) return ERROR_SUCCESS;
00441 
00442     for (i = 0; control_events[i].event; i++)
00443     {
00444         if (!strcmpW( control_events[i].event, event ))
00445             return control_events[i].handler( package, argument, dialog );
00446     }
00447     FIXME("unhandled control event %s arg(%s)\n", debugstr_w(event), debugstr_w(argument));
00448     return ERROR_SUCCESS;
00449 }

Generated on Sat May 26 2012 04:23:48 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.