Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencustom.c
Go to the documentation of this file.
00001 /* 00002 * Custom Action processing for 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 "config.h" 00022 #include "wine/port.h" 00023 00024 #define COBJMACROS 00025 00026 #include <stdarg.h> 00027 #include "windef.h" 00028 #include "winbase.h" 00029 #include "winerror.h" 00030 #include "msidefs.h" 00031 #include "winuser.h" 00032 #include "objbase.h" 00033 #include "oleauto.h" 00034 00035 #include "msipriv.h" 00036 #include "msiserver.h" 00037 #include "wine/debug.h" 00038 #include "wine/unicode.h" 00039 #include "wine/exception.h" 00040 00041 WINE_DEFAULT_DEBUG_CHANNEL(msi); 00042 00043 #define CUSTOM_ACTION_TYPE_MASK 0x3F 00044 00045 typedef struct tagMSIRUNNINGACTION 00046 { 00047 struct list entry; 00048 HANDLE handle; 00049 BOOL process; 00050 LPWSTR name; 00051 } MSIRUNNINGACTION; 00052 00053 typedef UINT (WINAPI *MsiCustomActionEntryPoint)( MSIHANDLE ); 00054 00055 static CRITICAL_SECTION msi_custom_action_cs; 00056 static CRITICAL_SECTION_DEBUG msi_custom_action_cs_debug = 00057 { 00058 0, 0, &msi_custom_action_cs, 00059 { &msi_custom_action_cs_debug.ProcessLocksList, 00060 &msi_custom_action_cs_debug.ProcessLocksList }, 00061 0, 0, { (DWORD_PTR)(__FILE__ ": msi_custom_action_cs") } 00062 }; 00063 static CRITICAL_SECTION msi_custom_action_cs = { &msi_custom_action_cs_debug, -1, 0, 0, 0, 0 }; 00064 00065 static struct list msi_pending_custom_actions = LIST_INIT( msi_pending_custom_actions ); 00066 00067 UINT msi_schedule_action( MSIPACKAGE *package, UINT script, const WCHAR *action ) 00068 { 00069 UINT count; 00070 WCHAR **newbuf = NULL; 00071 00072 if (script >= SCRIPT_MAX) 00073 { 00074 FIXME("Unknown script requested %u\n", script); 00075 return ERROR_FUNCTION_FAILED; 00076 } 00077 TRACE("Scheduling action %s in script %u\n", debugstr_w(action), script); 00078 00079 count = package->script->ActionCount[script]; 00080 package->script->ActionCount[script]++; 00081 if (count != 0) newbuf = msi_realloc( package->script->Actions[script], 00082 package->script->ActionCount[script] * sizeof(WCHAR *) ); 00083 else newbuf = msi_alloc( sizeof(WCHAR *) ); 00084 00085 newbuf[count] = strdupW( action ); 00086 package->script->Actions[script] = newbuf; 00087 return ERROR_SUCCESS; 00088 } 00089 00090 UINT msi_register_unique_action( MSIPACKAGE *package, const WCHAR *action ) 00091 { 00092 UINT count; 00093 WCHAR **newbuf = NULL; 00094 00095 if (!package->script) return FALSE; 00096 00097 TRACE("Registering %s as unique action\n", debugstr_w(action)); 00098 00099 count = package->script->UniqueActionsCount; 00100 package->script->UniqueActionsCount++; 00101 if (count != 0) newbuf = msi_realloc( package->script->UniqueActions, 00102 package->script->UniqueActionsCount * sizeof(WCHAR *) ); 00103 else newbuf = msi_alloc( sizeof(WCHAR *) ); 00104 00105 newbuf[count] = strdupW( action ); 00106 package->script->UniqueActions = newbuf; 00107 return ERROR_SUCCESS; 00108 } 00109 00110 BOOL msi_action_is_unique( const MSIPACKAGE *package, const WCHAR *action ) 00111 { 00112 UINT i; 00113 00114 if (!package->script) return FALSE; 00115 00116 for (i = 0; i < package->script->UniqueActionsCount; i++) 00117 { 00118 if (!strcmpW( package->script->UniqueActions[i], action )) return TRUE; 00119 } 00120 return FALSE; 00121 } 00122 00123 static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR action, UINT options) 00124 { 00125 if (!package->script) 00126 return TRUE; 00127 00128 if ((options & msidbCustomActionTypeClientRepeat) == 00129 msidbCustomActionTypeClientRepeat) 00130 { 00131 if (!(package->script->InWhatSequence & SEQUENCE_UI && 00132 package->script->InWhatSequence & SEQUENCE_EXEC)) 00133 { 00134 TRACE("Skipping action due to dbCustomActionTypeClientRepeat option.\n"); 00135 return FALSE; 00136 } 00137 } 00138 else if (options & msidbCustomActionTypeFirstSequence) 00139 { 00140 if (package->script->InWhatSequence & SEQUENCE_UI && 00141 package->script->InWhatSequence & SEQUENCE_EXEC ) 00142 { 00143 TRACE("Skipping action due to msidbCustomActionTypeFirstSequence option.\n"); 00144 return FALSE; 00145 } 00146 } 00147 else if (options & msidbCustomActionTypeOncePerProcess) 00148 { 00149 if (msi_action_is_unique(package, action)) 00150 { 00151 TRACE("Skipping action due to msidbCustomActionTypeOncePerProcess option.\n"); 00152 return FALSE; 00153 } 00154 else 00155 msi_register_unique_action(package, action); 00156 } 00157 00158 return TRUE; 00159 } 00160 00161 /* stores the following properties before the action: 00162 * 00163 * [CustomActionData<=>UserSID<=>ProductCode]Action 00164 */ 00165 static LPWSTR msi_get_deferred_action(LPCWSTR action, LPCWSTR actiondata, 00166 LPCWSTR usersid, LPCWSTR prodcode) 00167 { 00168 LPWSTR deferred; 00169 DWORD len; 00170 00171 static const WCHAR format[] = { 00172 '[','%','s','<','=','>','%','s','<','=','>','%','s',']','%','s',0 00173 }; 00174 00175 if (!actiondata) 00176 return strdupW(action); 00177 00178 len = lstrlenW(action) + lstrlenW(actiondata) + 00179 lstrlenW(usersid) + lstrlenW(prodcode) + 00180 lstrlenW(format) - 7; 00181 deferred = msi_alloc(len * sizeof(WCHAR)); 00182 00183 sprintfW(deferred, format, actiondata, usersid, prodcode, action); 00184 return deferred; 00185 } 00186 00187 static void set_deferred_action_props(MSIPACKAGE *package, LPWSTR deferred_data) 00188 { 00189 LPWSTR end, beg = deferred_data + 1; 00190 00191 static const WCHAR sep[] = {'<','=','>',0}; 00192 00193 end = strstrW(beg, sep); 00194 *end = '\0'; 00195 msi_set_property(package->db, szCustomActionData, beg); 00196 beg = end + 3; 00197 00198 end = strstrW(beg, sep); 00199 *end = '\0'; 00200 msi_set_property(package->db, szUserSID, beg); 00201 beg = end + 3; 00202 00203 end = strchrW(beg, ']'); 00204 *end = '\0'; 00205 msi_set_property(package->db, szProductCode, beg); 00206 } 00207 00208 static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll ) 00209 { 00210 static const WCHAR query[] = { 00211 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 00212 '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ', 00213 '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0}; 00214 MSIRECORD *row; 00215 MSIBINARY *binary; 00216 HANDLE file; 00217 CHAR buffer[1024]; 00218 WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH]; 00219 DWORD sz = MAX_PATH, write; 00220 UINT r; 00221 00222 if (msi_get_property(package->db, szTempFolder, fmt, &sz) != ERROR_SUCCESS) 00223 GetTempPathW(MAX_PATH, fmt); 00224 00225 if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile )) 00226 { 00227 TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError()); 00228 return NULL; 00229 } 00230 00231 row = MSI_QueryGetRecord(package->db, query, source); 00232 if (!row) 00233 return NULL; 00234 00235 if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) ))) 00236 { 00237 msiobj_release( &row->hdr ); 00238 return NULL; 00239 } 00240 file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 00241 if (file == INVALID_HANDLE_VALUE) 00242 { 00243 msiobj_release( &row->hdr ); 00244 msi_free( binary ); 00245 return NULL; 00246 } 00247 do 00248 { 00249 sz = sizeof(buffer); 00250 r = MSI_RecordReadStream( row, 2, buffer, &sz ); 00251 if (r != ERROR_SUCCESS) 00252 { 00253 ERR("Failed to get stream\n"); 00254 break; 00255 } 00256 WriteFile( file, buffer, sz, &write, NULL ); 00257 } while (sz == sizeof buffer); 00258 00259 CloseHandle( file ); 00260 msiobj_release( &row->hdr ); 00261 if (r != ERROR_SUCCESS) 00262 { 00263 DeleteFileW( tmpfile ); 00264 msi_free( binary ); 00265 return NULL; 00266 } 00267 00268 /* keep a reference to prevent the dll from being unloaded */ 00269 if (dll && !(binary->module = LoadLibraryW( tmpfile ))) 00270 { 00271 WARN( "failed to load dll %s (%u)\n", debugstr_w( tmpfile ), GetLastError() ); 00272 } 00273 binary->source = strdupW( source ); 00274 binary->tmpfile = strdupW( tmpfile ); 00275 list_add_tail( &package->binaries, &binary->entry ); 00276 return binary; 00277 } 00278 00279 static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll ) 00280 { 00281 MSIBINARY *binary; 00282 00283 LIST_FOR_EACH_ENTRY( binary, &package->binaries, MSIBINARY, entry ) 00284 { 00285 if (!strcmpW( binary->source, source )) 00286 return binary; 00287 } 00288 00289 return create_temp_binary( package, source, dll ); 00290 } 00291 00292 static void file_running_action(MSIPACKAGE* package, HANDLE Handle, 00293 BOOL process, LPCWSTR name) 00294 { 00295 MSIRUNNINGACTION *action; 00296 00297 action = msi_alloc( sizeof(MSIRUNNINGACTION) ); 00298 00299 action->handle = Handle; 00300 action->process = process; 00301 action->name = strdupW(name); 00302 00303 list_add_tail( &package->RunningActions, &action->entry ); 00304 } 00305 00306 static UINT custom_get_process_return( HANDLE process ) 00307 { 00308 DWORD rc = 0; 00309 00310 GetExitCodeProcess( process, &rc ); 00311 TRACE("exit code is %u\n", rc); 00312 if (rc != 0) 00313 return ERROR_FUNCTION_FAILED; 00314 return ERROR_SUCCESS; 00315 } 00316 00317 static UINT custom_get_thread_return( MSIPACKAGE *package, HANDLE thread ) 00318 { 00319 DWORD rc = 0; 00320 00321 GetExitCodeThread( thread, &rc ); 00322 00323 switch (rc) 00324 { 00325 case ERROR_FUNCTION_NOT_CALLED: 00326 case ERROR_SUCCESS: 00327 case ERROR_INSTALL_USEREXIT: 00328 case ERROR_INSTALL_FAILURE: 00329 return rc; 00330 case ERROR_NO_MORE_ITEMS: 00331 return ERROR_SUCCESS; 00332 case ERROR_INSTALL_SUSPEND: 00333 ACTION_ForceReboot( package ); 00334 return ERROR_SUCCESS; 00335 default: 00336 ERR("Invalid Return Code %d\n",rc); 00337 return ERROR_INSTALL_FAILURE; 00338 } 00339 } 00340 00341 static UINT wait_process_handle(MSIPACKAGE* package, UINT type, 00342 HANDLE ProcessHandle, LPCWSTR name) 00343 { 00344 UINT rc = ERROR_SUCCESS; 00345 00346 if (!(type & msidbCustomActionTypeAsync)) 00347 { 00348 TRACE("waiting for %s\n", debugstr_w(name)); 00349 00350 msi_dialog_check_messages(ProcessHandle); 00351 00352 if (!(type & msidbCustomActionTypeContinue)) 00353 rc = custom_get_process_return(ProcessHandle); 00354 00355 CloseHandle(ProcessHandle); 00356 } 00357 else 00358 { 00359 TRACE("%s running in background\n", debugstr_w(name)); 00360 00361 if (!(type & msidbCustomActionTypeContinue)) 00362 file_running_action(package, ProcessHandle, TRUE, name); 00363 else 00364 CloseHandle(ProcessHandle); 00365 } 00366 00367 return rc; 00368 } 00369 00370 typedef struct _msi_custom_action_info { 00371 struct list entry; 00372 LONG refs; 00373 MSIPACKAGE *package; 00374 LPWSTR source; 00375 LPWSTR target; 00376 HANDLE handle; 00377 LPWSTR action; 00378 INT type; 00379 GUID guid; 00380 } msi_custom_action_info; 00381 00382 static void release_custom_action_data( msi_custom_action_info *info ) 00383 { 00384 EnterCriticalSection( &msi_custom_action_cs ); 00385 00386 if (!--info->refs) 00387 { 00388 list_remove( &info->entry ); 00389 if (info->handle) 00390 CloseHandle( info->handle ); 00391 msi_free( info->action ); 00392 msi_free( info->source ); 00393 msi_free( info->target ); 00394 msiobj_release( &info->package->hdr ); 00395 msi_free( info ); 00396 } 00397 00398 LeaveCriticalSection( &msi_custom_action_cs ); 00399 } 00400 00401 /* must be called inside msi_custom_action_cs if info is in the pending custom actions list */ 00402 static void addref_custom_action_data( msi_custom_action_info *info ) 00403 { 00404 info->refs++; 00405 } 00406 00407 static UINT wait_thread_handle( msi_custom_action_info *info ) 00408 { 00409 UINT rc = ERROR_SUCCESS; 00410 00411 if (!(info->type & msidbCustomActionTypeAsync)) 00412 { 00413 TRACE("waiting for %s\n", debugstr_w( info->action )); 00414 00415 msi_dialog_check_messages( info->handle ); 00416 00417 if (!(info->type & msidbCustomActionTypeContinue)) 00418 rc = custom_get_thread_return( info->package, info->handle ); 00419 00420 release_custom_action_data( info ); 00421 } 00422 else 00423 { 00424 TRACE("%s running in background\n", debugstr_w( info->action )); 00425 } 00426 00427 return rc; 00428 } 00429 00430 static msi_custom_action_info *find_action_by_guid( const GUID *guid ) 00431 { 00432 msi_custom_action_info *info; 00433 BOOL found = FALSE; 00434 00435 EnterCriticalSection( &msi_custom_action_cs ); 00436 00437 LIST_FOR_EACH_ENTRY( info, &msi_pending_custom_actions, msi_custom_action_info, entry ) 00438 { 00439 if (IsEqualGUID( &info->guid, guid )) 00440 { 00441 addref_custom_action_data( info ); 00442 found = TRUE; 00443 break; 00444 } 00445 } 00446 00447 LeaveCriticalSection( &msi_custom_action_cs ); 00448 00449 if (!found) 00450 return NULL; 00451 00452 return info; 00453 } 00454 00455 static void handle_msi_break( LPCWSTR target ) 00456 { 00457 LPWSTR msg; 00458 WCHAR val[MAX_PATH]; 00459 00460 static const WCHAR MsiBreak[] = { 'M','s','i','B','r','e','a','k',0 }; 00461 static const WCHAR WindowsInstaller[] = { 00462 'W','i','n','d','o','w','s',' ','I','n','s','t','a','l','l','e','r',0 00463 }; 00464 00465 static const WCHAR format[] = { 00466 'T','o',' ','d','e','b','u','g',' ','y','o','u','r',' ', 00467 'c','u','s','t','o','m',' ','a','c','t','i','o','n',',',' ', 00468 'a','t','t','a','c','h',' ','y','o','u','r',' ','d','e','b','u','g','g','e','r',' ', 00469 't','o',' ','p','r','o','c','e','s','s',' ','%','i',' ','(','0','x','%','X',')',' ', 00470 'a','n','d',' ','p','r','e','s','s',' ','O','K',0 00471 }; 00472 00473 if( !GetEnvironmentVariableW( MsiBreak, val, MAX_PATH )) 00474 return; 00475 00476 if( strcmpiW( val, target )) 00477 return; 00478 00479 msg = msi_alloc( (lstrlenW(format) + 10) * sizeof(WCHAR) ); 00480 if (!msg) 00481 return; 00482 00483 wsprintfW( msg, format, GetCurrentProcessId(), GetCurrentProcessId()); 00484 MessageBoxW( NULL, msg, WindowsInstaller, MB_OK); 00485 msi_free(msg); 00486 DebugBreak(); 00487 } 00488 00489 static UINT get_action_info( const GUID *guid, INT *type, MSIHANDLE *handle, 00490 BSTR *dll, BSTR *funcname, 00491 IWineMsiRemotePackage **package ) 00492 { 00493 IClassFactory *cf = NULL; 00494 IWineMsiRemoteCustomAction *rca = NULL; 00495 HRESULT r; 00496 00497 r = DllGetClassObject( &CLSID_WineMsiRemoteCustomAction, 00498 &IID_IClassFactory, (LPVOID *)&cf ); 00499 if (FAILED(r)) 00500 { 00501 ERR("failed to get IClassFactory interface\n"); 00502 return ERROR_FUNCTION_FAILED; 00503 } 00504 00505 r = IClassFactory_CreateInstance( cf, NULL, &IID_IWineMsiRemoteCustomAction, (LPVOID *)&rca ); 00506 if (FAILED(r)) 00507 { 00508 ERR("failed to get IWineMsiRemoteCustomAction interface\n"); 00509 return ERROR_FUNCTION_FAILED; 00510 } 00511 00512 r = IWineMsiRemoteCustomAction_GetActionInfo( rca, guid, type, handle, dll, funcname, package ); 00513 IWineMsiRemoteCustomAction_Release( rca ); 00514 if (FAILED(r)) 00515 { 00516 ERR("GetActionInfo failed\n"); 00517 return ERROR_FUNCTION_FAILED; 00518 } 00519 00520 return ERROR_SUCCESS; 00521 } 00522 00523 #ifdef __i386__ 00524 extern UINT CUSTOMPROC_wrapper( MsiCustomActionEntryPoint proc, MSIHANDLE handle ); 00525 __ASM_GLOBAL_FUNC( CUSTOMPROC_wrapper, 00526 "pushl %ebp\n\t" 00527 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 00528 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") 00529 "movl %esp,%ebp\n\t" 00530 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") 00531 "pushl 12(%ebp)\n\t" 00532 "movl 8(%ebp),%eax\n\t" 00533 "call *%eax\n\t" 00534 "leave\n\t" 00535 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") 00536 __ASM_CFI(".cfi_same_value %ebp\n\t") 00537 "ret" ) 00538 #else 00539 static inline UINT CUSTOMPROC_wrapper( MsiCustomActionEntryPoint proc, MSIHANDLE handle ) 00540 { 00541 return proc(handle); 00542 } 00543 #endif 00544 00545 static DWORD ACTION_CallDllFunction( const GUID *guid ) 00546 { 00547 MsiCustomActionEntryPoint fn; 00548 MSIHANDLE hPackage, handle; 00549 HANDLE hModule; 00550 LPSTR proc; 00551 UINT r = ERROR_FUNCTION_FAILED; 00552 BSTR dll = NULL, function = NULL; 00553 INT type; 00554 IWineMsiRemotePackage *remote_package = NULL; 00555 00556 TRACE("%s\n", debugstr_guid( guid )); 00557 00558 r = get_action_info( guid, &type, &handle, &dll, &function, &remote_package ); 00559 if (r != ERROR_SUCCESS) 00560 return r; 00561 00562 hModule = LoadLibraryW( dll ); 00563 if (!hModule) 00564 { 00565 WARN( "failed to load dll %s (%u)\n", debugstr_w( dll ), GetLastError() ); 00566 return ERROR_SUCCESS; 00567 } 00568 00569 proc = strdupWtoA( function ); 00570 fn = (MsiCustomActionEntryPoint) GetProcAddress( hModule, proc ); 00571 msi_free( proc ); 00572 if (fn) 00573 { 00574 hPackage = alloc_msi_remote_handle( (IUnknown *)remote_package ); 00575 if (hPackage) 00576 { 00577 IWineMsiRemotePackage_SetMsiHandle( remote_package, handle ); 00578 TRACE("calling %s\n", debugstr_w( function ) ); 00579 handle_msi_break( function ); 00580 00581 __TRY 00582 { 00583 r = CUSTOMPROC_wrapper( fn, hPackage ); 00584 } 00585 __EXCEPT_PAGE_FAULT 00586 { 00587 ERR("Custom action (%s:%s) caused a page fault: %08x\n", 00588 debugstr_w(dll), debugstr_w(function), GetExceptionCode()); 00589 r = ERROR_SUCCESS; 00590 } 00591 __ENDTRY; 00592 00593 MsiCloseHandle( hPackage ); 00594 } 00595 else 00596 ERR("failed to create handle for %p\n", remote_package ); 00597 } 00598 else 00599 ERR("GetProcAddress(%s) failed\n", debugstr_w( function ) ); 00600 00601 FreeLibrary(hModule); 00602 00603 IWineMsiRemotePackage_Release( remote_package ); 00604 SysFreeString( dll ); 00605 SysFreeString( function ); 00606 MsiCloseHandle( handle ); 00607 00608 return r; 00609 } 00610 00611 static DWORD WINAPI DllThread( LPVOID arg ) 00612 { 00613 LPGUID guid = arg; 00614 DWORD rc = 0; 00615 00616 TRACE("custom action (%x) started\n", GetCurrentThreadId() ); 00617 00618 rc = ACTION_CallDllFunction( guid ); 00619 00620 TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc ); 00621 00622 MsiCloseAllHandles(); 00623 return rc; 00624 } 00625 00626 static DWORD ACTION_CAInstallPackage(const GUID *guid) 00627 { 00628 msi_custom_action_info *info; 00629 UINT r = ERROR_FUNCTION_FAILED; 00630 INSTALLUILEVEL old_level; 00631 00632 info = find_action_by_guid(guid); 00633 if (!info) 00634 { 00635 ERR("failed to find action %s\n", debugstr_guid(guid)); 00636 return r; 00637 } 00638 00639 old_level = MsiSetInternalUI(INSTALLUILEVEL_BASIC, NULL); 00640 r = MsiInstallProductW(info->source, info->target); 00641 MsiSetInternalUI(old_level, NULL); 00642 00643 release_custom_action_data(info); 00644 00645 return r; 00646 } 00647 00648 static DWORD WINAPI ConcurrentInstallThread(LPVOID arg) 00649 { 00650 LPGUID guid = arg; 00651 DWORD rc; 00652 00653 TRACE("concurrent installation (%x) started\n", GetCurrentThreadId()); 00654 00655 rc = ACTION_CAInstallPackage(guid); 00656 00657 TRACE("concurrent installation (%x) returned %i\n", GetCurrentThreadId(), rc); 00658 00659 MsiCloseAllHandles(); 00660 return rc; 00661 } 00662 00663 static msi_custom_action_info *do_msidbCustomActionTypeDll( 00664 MSIPACKAGE *package, INT type, LPCWSTR source, LPCWSTR target, LPCWSTR action ) 00665 { 00666 msi_custom_action_info *info; 00667 00668 info = msi_alloc( sizeof *info ); 00669 if (!info) 00670 return NULL; 00671 00672 msiobj_addref( &package->hdr ); 00673 info->refs = 2; /* 1 for our caller and 1 for thread we created */ 00674 info->package = package; 00675 info->type = type; 00676 info->target = strdupW( target ); 00677 info->source = strdupW( source ); 00678 info->action = strdupW( action ); 00679 CoCreateGuid( &info->guid ); 00680 00681 EnterCriticalSection( &msi_custom_action_cs ); 00682 list_add_tail( &msi_pending_custom_actions, &info->entry ); 00683 LeaveCriticalSection( &msi_custom_action_cs ); 00684 00685 info->handle = CreateThread( NULL, 0, DllThread, &info->guid, 0, NULL ); 00686 if (!info->handle) 00687 { 00688 /* release both references */ 00689 release_custom_action_data( info ); 00690 release_custom_action_data( info ); 00691 return NULL; 00692 } 00693 00694 return info; 00695 } 00696 00697 static msi_custom_action_info *do_msidbCAConcurrentInstall( 00698 MSIPACKAGE *package, INT type, LPCWSTR source, LPCWSTR target, LPCWSTR action) 00699 { 00700 msi_custom_action_info *info; 00701 00702 info = msi_alloc( sizeof *info ); 00703 if (!info) 00704 return NULL; 00705 00706 msiobj_addref( &package->hdr ); 00707 info->refs = 2; /* 1 for our caller and 1 for thread we created */ 00708 info->package = package; 00709 info->type = type; 00710 info->target = strdupW( target ); 00711 info->source = strdupW( source ); 00712 info->action = strdupW( action ); 00713 CoCreateGuid( &info->guid ); 00714 00715 EnterCriticalSection( &msi_custom_action_cs ); 00716 list_add_tail( &msi_pending_custom_actions, &info->entry ); 00717 LeaveCriticalSection( &msi_custom_action_cs ); 00718 00719 info->handle = CreateThread( NULL, 0, ConcurrentInstallThread, &info->guid, 0, NULL ); 00720 if (!info->handle) 00721 { 00722 /* release both references */ 00723 release_custom_action_data( info ); 00724 release_custom_action_data( info ); 00725 return NULL; 00726 } 00727 00728 return info; 00729 } 00730 00731 static UINT HANDLE_CustomType23(MSIPACKAGE *package, LPCWSTR source, 00732 LPCWSTR target, const INT type, LPCWSTR action) 00733 { 00734 msi_custom_action_info *info; 00735 WCHAR package_path[MAX_PATH]; 00736 DWORD size; 00737 00738 size = MAX_PATH; 00739 msi_get_property(package->db, szSourceDir, package_path, &size); 00740 lstrcatW(package_path, szBackSlash); 00741 lstrcatW(package_path, source); 00742 00743 TRACE("Installing package %s concurrently\n", debugstr_w(package_path)); 00744 00745 info = do_msidbCAConcurrentInstall(package, type, package_path, target, action); 00746 return wait_thread_handle(info); 00747 } 00748 00749 static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, 00750 LPCWSTR target, const INT type, LPCWSTR action) 00751 { 00752 msi_custom_action_info *info; 00753 MSIBINARY *binary; 00754 00755 if (!(binary = get_temp_binary( package, source, TRUE ))) 00756 return ERROR_FUNCTION_FAILED; 00757 00758 TRACE("Calling function %s from %s\n", debugstr_w(target), debugstr_w(binary->tmpfile)); 00759 00760 info = do_msidbCustomActionTypeDll( package, type, binary->tmpfile, target, action ); 00761 return wait_thread_handle( info ); 00762 } 00763 00764 static HANDLE execute_command( const WCHAR *app, WCHAR *arg, const WCHAR *dir ) 00765 { 00766 static const WCHAR dotexeW[] = {'.','e','x','e',0}; 00767 STARTUPINFOW si; 00768 PROCESS_INFORMATION info; 00769 WCHAR *exe = NULL, *cmd = NULL, *p; 00770 BOOL ret; 00771 00772 if (app) 00773 { 00774 int len_arg = 0; 00775 DWORD len_exe; 00776 00777 if (!(exe = msi_alloc( MAX_PATH * sizeof(WCHAR) ))) return INVALID_HANDLE_VALUE; 00778 len_exe = SearchPathW( NULL, app, dotexeW, MAX_PATH, exe, NULL ); 00779 if (len_exe >= MAX_PATH) 00780 { 00781 msi_free( exe ); 00782 if (!(exe = msi_alloc( len_exe * sizeof(WCHAR) ))) return INVALID_HANDLE_VALUE; 00783 len_exe = SearchPathW( NULL, app, dotexeW, len_exe, exe, NULL ); 00784 } 00785 if (!len_exe) 00786 { 00787 WARN("can't find executable %u\n", GetLastError()); 00788 msi_free( exe ); 00789 return INVALID_HANDLE_VALUE; 00790 } 00791 00792 if (arg) len_arg = strlenW( arg ); 00793 if (!(cmd = msi_alloc( (len_exe + len_arg + 4) * sizeof(WCHAR) ))) 00794 { 00795 msi_free( exe ); 00796 return INVALID_HANDLE_VALUE; 00797 } 00798 p = cmd; 00799 if (strchrW( exe, ' ' )) 00800 { 00801 *p++ = '\"'; 00802 memcpy( p, exe, len_exe * sizeof(WCHAR) ); 00803 p += len_exe; 00804 *p++ = '\"'; 00805 *p = 0; 00806 } 00807 else 00808 { 00809 strcpyW( p, exe ); 00810 p += len_exe; 00811 } 00812 if (arg) 00813 { 00814 *p++ = ' '; 00815 memcpy( p, arg, len_arg * sizeof(WCHAR) ); 00816 p[len_arg] = 0; 00817 } 00818 } 00819 memset( &si, 0, sizeof(STARTUPINFOW) ); 00820 ret = CreateProcessW( exe, exe ? cmd : arg, NULL, NULL, FALSE, 0, NULL, dir, &si, &info ); 00821 msi_free( cmd ); 00822 msi_free( exe ); 00823 if (!ret) 00824 { 00825 WARN("unable to execute command %u\n", GetLastError()); 00826 return INVALID_HANDLE_VALUE; 00827 } 00828 CloseHandle( info.hThread ); 00829 return info.hProcess; 00830 } 00831 00832 static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, 00833 LPCWSTR target, const INT type, LPCWSTR action) 00834 { 00835 MSIBINARY *binary; 00836 HANDLE handle; 00837 WCHAR *arg; 00838 00839 if (!(binary = get_temp_binary( package, source, FALSE ))) return ERROR_FUNCTION_FAILED; 00840 00841 deformat_string( package, target, &arg ); 00842 TRACE("exe %s arg %s\n", debugstr_w(binary->tmpfile), debugstr_w(arg)); 00843 00844 handle = execute_command( binary->tmpfile, arg, szCRoot ); 00845 msi_free( arg ); 00846 if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; 00847 return wait_process_handle( package, type, handle, action ); 00848 } 00849 00850 static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source, 00851 LPCWSTR target, const INT type, LPCWSTR action) 00852 { 00853 msi_custom_action_info *info; 00854 MSIFILE *file; 00855 00856 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); 00857 00858 file = msi_get_loaded_file( package, source ); 00859 if (!file) 00860 { 00861 ERR("invalid file key %s\n", debugstr_w( source )); 00862 return ERROR_FUNCTION_FAILED; 00863 } 00864 00865 info = do_msidbCustomActionTypeDll( package, type, file->TargetPath, target, action ); 00866 return wait_thread_handle( info ); 00867 } 00868 00869 static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source, 00870 LPCWSTR target, const INT type, LPCWSTR action) 00871 { 00872 MSIFILE *file; 00873 HANDLE handle; 00874 WCHAR *arg; 00875 00876 if (!(file = msi_get_loaded_file( package, source ))) return ERROR_FUNCTION_FAILED; 00877 00878 deformat_string( package, target, &arg ); 00879 TRACE("exe %s arg %s\n", debugstr_w(file->TargetPath), debugstr_w(arg)); 00880 00881 handle = execute_command( file->TargetPath, arg, szCRoot ); 00882 msi_free( arg ); 00883 if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; 00884 return wait_process_handle( package, type, handle, action ); 00885 } 00886 00887 static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, 00888 LPCWSTR target, const INT type, LPCWSTR action) 00889 { 00890 static const WCHAR query[] = { 00891 'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ', 00892 'F','R','O','M',' ','`','E','r','r','o','r','`',' ', 00893 'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ', 00894 '%','s',0 00895 }; 00896 MSIRECORD *row = 0; 00897 LPWSTR deformated = NULL; 00898 00899 deformat_string( package, target, &deformated ); 00900 00901 /* first try treat the error as a number */ 00902 row = MSI_QueryGetRecord( package->db, query, deformated ); 00903 if( row ) 00904 { 00905 LPCWSTR error = MSI_RecordGetString( row, 1 ); 00906 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) 00907 MessageBoxW( NULL, error, NULL, MB_OK ); 00908 msiobj_release( &row->hdr ); 00909 } 00910 else if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) 00911 MessageBoxW( NULL, deformated, NULL, MB_OK ); 00912 00913 msi_free( deformated ); 00914 00915 return ERROR_INSTALL_FAILURE; 00916 } 00917 00918 static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, 00919 LPCWSTR target, const INT type, LPCWSTR action) 00920 { 00921 WCHAR *exe, *arg; 00922 HANDLE handle; 00923 00924 if (!(exe = msi_dup_property( package->db, source ))) return ERROR_SUCCESS; 00925 00926 deformat_string( package, target, &arg ); 00927 TRACE("exe %s arg %s\n", debugstr_w(exe), debugstr_w(arg)); 00928 00929 handle = execute_command( exe, arg, szCRoot ); 00930 msi_free( arg ); 00931 if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; 00932 return wait_process_handle( package, type, handle, action ); 00933 } 00934 00935 static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, 00936 LPCWSTR target, const INT type, LPCWSTR action) 00937 { 00938 const WCHAR *workingdir; 00939 HANDLE handle; 00940 WCHAR *cmd; 00941 00942 workingdir = msi_get_target_folder( package, source ); 00943 if (!workingdir) return ERROR_FUNCTION_FAILED; 00944 00945 deformat_string( package, target, &cmd ); 00946 if (!cmd) return ERROR_FUNCTION_FAILED; 00947 00948 TRACE("cmd %s dir %s\n", debugstr_w(cmd), debugstr_w(workingdir)); 00949 00950 handle = execute_command( NULL, cmd, workingdir ); 00951 msi_free( cmd ); 00952 if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; 00953 return wait_process_handle( package, type, handle, action ); 00954 } 00955 00956 static DWORD ACTION_CallScript( const GUID *guid ) 00957 { 00958 msi_custom_action_info *info; 00959 MSIHANDLE hPackage; 00960 UINT r; 00961 00962 info = find_action_by_guid( guid ); 00963 if (!info) 00964 { 00965 ERR("failed to find action %s\n", debugstr_guid( guid) ); 00966 return ERROR_FUNCTION_FAILED; 00967 } 00968 00969 TRACE("function %s, script %s\n", debugstr_w( info->target ), debugstr_w( info->source ) ); 00970 00971 hPackage = alloc_msihandle( &info->package->hdr ); 00972 if (hPackage) 00973 { 00974 r = call_script( hPackage, info->type, info->source, info->target, info->action ); 00975 TRACE("script returned %u\n", r); 00976 MsiCloseHandle( hPackage ); 00977 } 00978 else 00979 ERR("failed to create handle for %p\n", info->package ); 00980 00981 release_custom_action_data( info ); 00982 return S_OK; 00983 } 00984 00985 static DWORD WINAPI ScriptThread( LPVOID arg ) 00986 { 00987 LPGUID guid = arg; 00988 DWORD rc = 0; 00989 00990 TRACE("custom action (%x) started\n", GetCurrentThreadId() ); 00991 00992 rc = ACTION_CallScript( guid ); 00993 00994 TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc ); 00995 00996 MsiCloseAllHandles(); 00997 return rc; 00998 } 00999 01000 static msi_custom_action_info *do_msidbCustomActionTypeScript( 01001 MSIPACKAGE *package, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action ) 01002 { 01003 msi_custom_action_info *info; 01004 01005 info = msi_alloc( sizeof *info ); 01006 if (!info) 01007 return NULL; 01008 01009 msiobj_addref( &package->hdr ); 01010 info->refs = 2; /* 1 for our caller and 1 for thread we created */ 01011 info->package = package; 01012 info->type = type; 01013 info->target = strdupW( function ); 01014 info->source = strdupW( script ); 01015 info->action = strdupW( action ); 01016 CoCreateGuid( &info->guid ); 01017 01018 EnterCriticalSection( &msi_custom_action_cs ); 01019 list_add_tail( &msi_pending_custom_actions, &info->entry ); 01020 LeaveCriticalSection( &msi_custom_action_cs ); 01021 01022 info->handle = CreateThread( NULL, 0, ScriptThread, &info->guid, 0, NULL ); 01023 if (!info->handle) 01024 { 01025 /* release both references */ 01026 release_custom_action_data( info ); 01027 release_custom_action_data( info ); 01028 return NULL; 01029 } 01030 01031 return info; 01032 } 01033 01034 static UINT HANDLE_CustomType37_38(MSIPACKAGE *package, LPCWSTR source, 01035 LPCWSTR target, const INT type, LPCWSTR action) 01036 { 01037 msi_custom_action_info *info; 01038 01039 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); 01040 01041 info = do_msidbCustomActionTypeScript( package, type, target, NULL, action ); 01042 return wait_thread_handle( info ); 01043 } 01044 01045 static UINT HANDLE_CustomType5_6(MSIPACKAGE *package, LPCWSTR source, 01046 LPCWSTR target, const INT type, LPCWSTR action) 01047 { 01048 static const WCHAR query[] = { 01049 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 01050 '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ', 01051 '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0}; 01052 MSIRECORD *row = 0; 01053 msi_custom_action_info *info; 01054 CHAR *buffer = NULL; 01055 WCHAR *bufferw = NULL; 01056 DWORD sz = 0; 01057 UINT r; 01058 01059 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); 01060 01061 row = MSI_QueryGetRecord(package->db, query, source); 01062 if (!row) 01063 return ERROR_FUNCTION_FAILED; 01064 01065 r = MSI_RecordReadStream(row, 2, NULL, &sz); 01066 if (r != ERROR_SUCCESS) return r; 01067 01068 buffer = msi_alloc( sz + 1 ); 01069 if (!buffer) return ERROR_FUNCTION_FAILED; 01070 01071 r = MSI_RecordReadStream(row, 2, buffer, &sz); 01072 if (r != ERROR_SUCCESS) 01073 goto done; 01074 01075 buffer[sz] = 0; 01076 bufferw = strdupAtoW(buffer); 01077 if (!bufferw) 01078 { 01079 r = ERROR_FUNCTION_FAILED; 01080 goto done; 01081 } 01082 01083 info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action ); 01084 r = wait_thread_handle( info ); 01085 01086 done: 01087 msi_free(bufferw); 01088 msi_free(buffer); 01089 return r; 01090 } 01091 01092 static UINT HANDLE_CustomType21_22(MSIPACKAGE *package, LPCWSTR source, 01093 LPCWSTR target, const INT type, LPCWSTR action) 01094 { 01095 msi_custom_action_info *info; 01096 MSIFILE *file; 01097 HANDLE hFile; 01098 DWORD sz, szHighWord = 0, read; 01099 CHAR *buffer=NULL; 01100 WCHAR *bufferw=NULL; 01101 BOOL bRet; 01102 UINT r; 01103 01104 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); 01105 01106 file = msi_get_loaded_file(package, source); 01107 if (!file) 01108 { 01109 ERR("invalid file key %s\n", debugstr_w(source)); 01110 return ERROR_FUNCTION_FAILED; 01111 } 01112 01113 hFile = CreateFileW(file->TargetPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 01114 if (hFile == INVALID_HANDLE_VALUE) return ERROR_FUNCTION_FAILED; 01115 01116 sz = GetFileSize(hFile, &szHighWord); 01117 if (sz == INVALID_FILE_SIZE || szHighWord != 0) 01118 { 01119 CloseHandle(hFile); 01120 return ERROR_FUNCTION_FAILED; 01121 } 01122 buffer = msi_alloc( sz + 1 ); 01123 if (!buffer) 01124 { 01125 CloseHandle(hFile); 01126 return ERROR_FUNCTION_FAILED; 01127 } 01128 bRet = ReadFile(hFile, buffer, sz, &read, NULL); 01129 CloseHandle(hFile); 01130 if (!bRet) 01131 { 01132 r = ERROR_FUNCTION_FAILED; 01133 goto done; 01134 } 01135 buffer[read] = 0; 01136 bufferw = strdupAtoW(buffer); 01137 if (!bufferw) 01138 { 01139 r = ERROR_FUNCTION_FAILED; 01140 goto done; 01141 } 01142 info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action ); 01143 r = wait_thread_handle( info ); 01144 01145 done: 01146 msi_free(bufferw); 01147 msi_free(buffer); 01148 return r; 01149 } 01150 01151 static UINT HANDLE_CustomType53_54(MSIPACKAGE *package, LPCWSTR source, 01152 LPCWSTR target, const INT type, LPCWSTR action) 01153 { 01154 msi_custom_action_info *info; 01155 WCHAR *prop; 01156 01157 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); 01158 01159 prop = msi_dup_property( package->db, source ); 01160 if (!prop) return ERROR_SUCCESS; 01161 01162 info = do_msidbCustomActionTypeScript( package, type, prop, NULL, action ); 01163 msi_free(prop); 01164 return wait_thread_handle( info ); 01165 } 01166 01167 static BOOL action_type_matches_script( MSIPACKAGE *package, UINT type, UINT script ) 01168 { 01169 switch (script) 01170 { 01171 case SCRIPT_NONE: 01172 case SCRIPT_INSTALL: 01173 return !(type & msidbCustomActionTypeCommit) && !(type & msidbCustomActionTypeRollback); 01174 case SCRIPT_COMMIT: 01175 return (type & msidbCustomActionTypeCommit); 01176 case SCRIPT_ROLLBACK: 01177 return (type & msidbCustomActionTypeRollback); 01178 default: 01179 ERR("unhandled script %u\n", script); 01180 } 01181 return FALSE; 01182 } 01183 01184 static UINT defer_custom_action( MSIPACKAGE *package, const WCHAR *action, UINT type ) 01185 { 01186 WCHAR *actiondata = msi_dup_property( package->db, action ); 01187 WCHAR *usersid = msi_dup_property( package->db, szUserSID ); 01188 WCHAR *prodcode = msi_dup_property( package->db, szProductCode ); 01189 WCHAR *deferred = msi_get_deferred_action( action, actiondata, usersid, prodcode ); 01190 01191 if (!deferred) 01192 { 01193 msi_free( actiondata ); 01194 msi_free( usersid ); 01195 msi_free( prodcode ); 01196 return ERROR_OUTOFMEMORY; 01197 } 01198 if (type & msidbCustomActionTypeCommit) 01199 { 01200 TRACE("deferring commit action\n"); 01201 msi_schedule_action( package, SCRIPT_COMMIT, deferred ); 01202 } 01203 else if (type & msidbCustomActionTypeRollback) 01204 { 01205 TRACE("deferring rollback action\n"); 01206 msi_schedule_action( package, SCRIPT_ROLLBACK, deferred ); 01207 } 01208 else 01209 { 01210 TRACE("deferring install action\n"); 01211 msi_schedule_action( package, SCRIPT_INSTALL, deferred ); 01212 } 01213 01214 msi_free( actiondata ); 01215 msi_free( usersid ); 01216 msi_free( prodcode ); 01217 msi_free( deferred ); 01218 return ERROR_SUCCESS; 01219 } 01220 01221 UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL execute) 01222 { 01223 static const WCHAR query[] = { 01224 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 01225 '`','C','u','s','t','o','m','A','c','t','i','o','n','`',' ','W','H','E','R','E',' ', 01226 '`','A','c','t','i' ,'o','n','`',' ','=',' ','\'','%','s','\'',0}; 01227 UINT rc = ERROR_SUCCESS; 01228 MSIRECORD *row; 01229 UINT type; 01230 LPCWSTR source, target; 01231 LPWSTR ptr, deferred_data = NULL; 01232 LPWSTR deformated = NULL, action_copy = strdupW(action); 01233 01234 /* deferred action: [properties]Action */ 01235 if ((ptr = strrchrW(action_copy, ']'))) 01236 { 01237 deferred_data = action_copy; 01238 action = ptr + 1; 01239 } 01240 01241 row = MSI_QueryGetRecord( package->db, query, action ); 01242 if (!row) 01243 { 01244 msi_free(action_copy); 01245 return ERROR_CALL_NOT_IMPLEMENTED; 01246 } 01247 01248 type = MSI_RecordGetInteger(row,2); 01249 source = MSI_RecordGetString(row,3); 01250 target = MSI_RecordGetString(row,4); 01251 01252 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type, 01253 debugstr_w(source), debugstr_w(target)); 01254 01255 /* handle some of the deferred actions */ 01256 if (type & msidbCustomActionTypeTSAware) 01257 FIXME("msidbCustomActionTypeTSAware not handled\n"); 01258 01259 if (type & msidbCustomActionTypeInScript) 01260 { 01261 if (type & msidbCustomActionTypeNoImpersonate) 01262 WARN("msidbCustomActionTypeNoImpersonate not handled\n"); 01263 01264 if (!execute || !action_type_matches_script( package, type, script )) 01265 { 01266 rc = defer_custom_action( package, action, type ); 01267 goto end; 01268 } 01269 else 01270 { 01271 LPWSTR actiondata = msi_dup_property( package->db, action ); 01272 01273 if (type & msidbCustomActionTypeInScript) 01274 package->scheduled_action_running = TRUE; 01275 01276 if (type & msidbCustomActionTypeCommit) 01277 package->commit_action_running = TRUE; 01278 01279 if (type & msidbCustomActionTypeRollback) 01280 package->rollback_action_running = TRUE; 01281 01282 if (deferred_data) 01283 set_deferred_action_props(package, deferred_data); 01284 else if (actiondata) 01285 msi_set_property(package->db, szCustomActionData, actiondata); 01286 else 01287 msi_set_property(package->db, szCustomActionData, szEmpty); 01288 01289 msi_free(actiondata); 01290 } 01291 } 01292 else if (!check_execution_scheduling_options(package,action,type)) 01293 { 01294 rc = ERROR_SUCCESS; 01295 goto end; 01296 } 01297 01298 switch (type & CUSTOM_ACTION_TYPE_MASK) 01299 { 01300 case 1: /* DLL file stored in a Binary table stream */ 01301 rc = HANDLE_CustomType1(package,source,target,type,action); 01302 break; 01303 case 2: /* EXE file stored in a Binary table stream */ 01304 rc = HANDLE_CustomType2(package,source,target,type,action); 01305 break; 01306 case 18: /*EXE file installed with package */ 01307 rc = HANDLE_CustomType18(package,source,target,type,action); 01308 break; 01309 case 19: /* Error that halts install */ 01310 rc = HANDLE_CustomType19(package,source,target,type,action); 01311 break; 01312 case 17: 01313 rc = HANDLE_CustomType17(package,source,target,type,action); 01314 break; 01315 case 23: /* installs another package in the source tree */ 01316 deformat_string(package,target,&deformated); 01317 rc = HANDLE_CustomType23(package,source,deformated,type,action); 01318 msi_free(deformated); 01319 break; 01320 case 50: /*EXE file specified by a property value */ 01321 rc = HANDLE_CustomType50(package,source,target,type,action); 01322 break; 01323 case 34: /*EXE to be run in specified directory */ 01324 rc = HANDLE_CustomType34(package,source,target,type,action); 01325 break; 01326 case 35: /* Directory set with formatted text. */ 01327 deformat_string(package,target,&deformated); 01328 MSI_SetTargetPathW(package, source, deformated); 01329 msi_free(deformated); 01330 break; 01331 case 51: /* Property set with formatted text. */ 01332 if (!source) 01333 break; 01334 01335 deformat_string(package,target,&deformated); 01336 rc = msi_set_property( package->db, source, deformated ); 01337 if (rc == ERROR_SUCCESS && !strcmpW( source, szSourceDir )) 01338 msi_reset_folders( package, TRUE ); 01339 msi_free(deformated); 01340 break; 01341 case 37: /* JScript/VBScript text stored in target column. */ 01342 case 38: 01343 rc = HANDLE_CustomType37_38(package,source,target,type,action); 01344 break; 01345 case 5: 01346 case 6: /* JScript/VBScript file stored in a Binary table stream. */ 01347 rc = HANDLE_CustomType5_6(package,source,target,type,action); 01348 break; 01349 case 21: /* JScript/VBScript file installed with the product. */ 01350 case 22: 01351 rc = HANDLE_CustomType21_22(package,source,target,type,action); 01352 break; 01353 case 53: /* JScript/VBScript text specified by a property value. */ 01354 case 54: 01355 rc = HANDLE_CustomType53_54(package,source,target,type,action); 01356 break; 01357 default: 01358 FIXME("unhandled action type %u (%s %s)\n", type & CUSTOM_ACTION_TYPE_MASK, 01359 debugstr_w(source), debugstr_w(target)); 01360 } 01361 01362 end: 01363 package->scheduled_action_running = FALSE; 01364 package->commit_action_running = FALSE; 01365 package->rollback_action_running = FALSE; 01366 msi_free(action_copy); 01367 msiobj_release(&row->hdr); 01368 return rc; 01369 } 01370 01371 void ACTION_FinishCustomActions(const MSIPACKAGE* package) 01372 { 01373 struct list *item; 01374 HANDLE *wait_handles; 01375 unsigned int handle_count, i; 01376 msi_custom_action_info *info, *cursor; 01377 01378 while ((item = list_head( &package->RunningActions ))) 01379 { 01380 MSIRUNNINGACTION *action = LIST_ENTRY( item, MSIRUNNINGACTION, entry ); 01381 01382 list_remove( &action->entry ); 01383 01384 TRACE("waiting for %s\n", debugstr_w( action->name ) ); 01385 msi_dialog_check_messages( action->handle ); 01386 01387 CloseHandle( action->handle ); 01388 msi_free( action->name ); 01389 msi_free( action ); 01390 } 01391 01392 EnterCriticalSection( &msi_custom_action_cs ); 01393 01394 handle_count = list_count( &msi_pending_custom_actions ); 01395 wait_handles = msi_alloc( handle_count * sizeof(HANDLE) ); 01396 01397 handle_count = 0; 01398 LIST_FOR_EACH_ENTRY_SAFE( info, cursor, &msi_pending_custom_actions, msi_custom_action_info, entry ) 01399 { 01400 if (info->package == package ) 01401 { 01402 if (DuplicateHandle(GetCurrentProcess(), info->handle, GetCurrentProcess(), &wait_handles[handle_count], SYNCHRONIZE, FALSE, 0)) 01403 handle_count++; 01404 } 01405 } 01406 01407 LeaveCriticalSection( &msi_custom_action_cs ); 01408 01409 for (i = 0; i < handle_count; i++) 01410 { 01411 msi_dialog_check_messages( wait_handles[i] ); 01412 CloseHandle( wait_handles[i] ); 01413 } 01414 msi_free( wait_handles ); 01415 01416 EnterCriticalSection( &msi_custom_action_cs ); 01417 LIST_FOR_EACH_ENTRY_SAFE( info, cursor, &msi_pending_custom_actions, msi_custom_action_info, entry ) 01418 { 01419 if (info->package == package) release_custom_action_data( info ); 01420 } 01421 LeaveCriticalSection( &msi_custom_action_cs ); 01422 } 01423 01424 typedef struct _msi_custom_remote_impl { 01425 IWineMsiRemoteCustomAction IWineMsiRemoteCustomAction_iface; 01426 LONG refs; 01427 } msi_custom_remote_impl; 01428 01429 static inline msi_custom_remote_impl *impl_from_IWineMsiRemoteCustomAction( IWineMsiRemoteCustomAction *iface ) 01430 { 01431 return CONTAINING_RECORD(iface, msi_custom_remote_impl, IWineMsiRemoteCustomAction_iface); 01432 } 01433 01434 static HRESULT WINAPI mcr_QueryInterface( IWineMsiRemoteCustomAction *iface, 01435 REFIID riid,LPVOID *ppobj) 01436 { 01437 if( IsEqualCLSID( riid, &IID_IUnknown ) || 01438 IsEqualCLSID( riid, &IID_IWineMsiRemoteCustomAction ) ) 01439 { 01440 IUnknown_AddRef( iface ); 01441 *ppobj = iface; 01442 return S_OK; 01443 } 01444 01445 return E_NOINTERFACE; 01446 } 01447 01448 static ULONG WINAPI mcr_AddRef( IWineMsiRemoteCustomAction *iface ) 01449 { 01450 msi_custom_remote_impl* This = impl_from_IWineMsiRemoteCustomAction( iface ); 01451 01452 return InterlockedIncrement( &This->refs ); 01453 } 01454 01455 static ULONG WINAPI mcr_Release( IWineMsiRemoteCustomAction *iface ) 01456 { 01457 msi_custom_remote_impl* This = impl_from_IWineMsiRemoteCustomAction( iface ); 01458 ULONG r; 01459 01460 r = InterlockedDecrement( &This->refs ); 01461 if (r == 0) 01462 msi_free( This ); 01463 return r; 01464 } 01465 01466 static HRESULT WINAPI mcr_GetActionInfo( IWineMsiRemoteCustomAction *iface, LPCGUID custom_action_guid, 01467 INT *type, MSIHANDLE *handle, BSTR *dll, BSTR *func, IWineMsiRemotePackage **remote_package ) 01468 { 01469 msi_custom_action_info *info; 01470 01471 info = find_action_by_guid( custom_action_guid ); 01472 if (!info) 01473 return E_FAIL; 01474 01475 *type = info->type; 01476 *handle = alloc_msihandle( &info->package->hdr ); 01477 *dll = SysAllocString( info->source ); 01478 *func = SysAllocString( info->target ); 01479 01480 release_custom_action_data( info ); 01481 return create_msi_remote_package( NULL, (LPVOID *)remote_package ); 01482 } 01483 01484 static const IWineMsiRemoteCustomActionVtbl msi_custom_remote_vtbl = 01485 { 01486 mcr_QueryInterface, 01487 mcr_AddRef, 01488 mcr_Release, 01489 mcr_GetActionInfo, 01490 }; 01491 01492 HRESULT create_msi_custom_remote( IUnknown *pOuter, LPVOID *ppObj ) 01493 { 01494 msi_custom_remote_impl* This; 01495 01496 This = msi_alloc( sizeof *This ); 01497 if (!This) 01498 return E_OUTOFMEMORY; 01499 01500 This->IWineMsiRemoteCustomAction_iface.lpVtbl = &msi_custom_remote_vtbl; 01501 This->refs = 1; 01502 01503 *ppObj = This; 01504 01505 return S_OK; 01506 } Generated on Sun May 27 2012 04:19:07 for ReactOS by
1.7.6.1
|