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

custom.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 doxygen 1.7.6.1

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