Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenevents.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
1.7.6.1
|