2 * Custom Action processing for the Microsoft Installer (msi.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msi);
35 #define CUSTOM_ACTION_TYPE_MASK 0x3F
36 static const WCHAR c_collen[] = {'C',':','\\',0};
37 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
39 typedef struct tagMSIRUNNINGACTION
47 static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
48 LPCWSTR target, const INT type, LPCWSTR action);
49 static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
50 LPCWSTR target, const INT type, LPCWSTR action);
51 static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source,
52 LPCWSTR target, const INT type, LPCWSTR action);
53 static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
54 LPCWSTR target, const INT type, LPCWSTR action);
55 static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source,
56 LPCWSTR target, const INT type, LPCWSTR action);
57 static UINT HANDLE_CustomType23(MSIPACKAGE *package, LPCWSTR source,
58 LPCWSTR target, const INT type, LPCWSTR action);
59 static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
60 LPCWSTR target, const INT type, LPCWSTR action);
61 static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
62 LPCWSTR target, const INT type, LPCWSTR action);
63 static UINT HANDLE_CustomType37_38(MSIPACKAGE *package, LPCWSTR source,
64 LPCWSTR target, const INT type, LPCWSTR action);
65 static UINT HANDLE_CustomType5_6(MSIPACKAGE *package, LPCWSTR source,
66 LPCWSTR target, const INT type, LPCWSTR action);
67 static UINT HANDLE_CustomType21_22(MSIPACKAGE *package, LPCWSTR source,
68 LPCWSTR target, const INT type, LPCWSTR action);
69 static UINT HANDLE_CustomType53_54(MSIPACKAGE *package, LPCWSTR source,
70 LPCWSTR target, const INT type, LPCWSTR action);
72 typedef UINT (WINAPI *MsiCustomActionEntryPoint)( MSIHANDLE );
74 static CRITICAL_SECTION msi_custom_action_cs;
75 static CRITICAL_SECTION_DEBUG msi_custom_action_cs_debug =
77 0, 0, &msi_custom_action_cs,
78 { &msi_custom_action_cs_debug.ProcessLocksList,
79 &msi_custom_action_cs_debug.ProcessLocksList },
80 0, 0, { (DWORD_PTR)(__FILE__ ": msi_custom_action_cs") }
82 static CRITICAL_SECTION msi_custom_action_cs = { &msi_custom_action_cs_debug, -1, 0, 0, 0, 0 };
84 static struct list msi_pending_custom_actions = LIST_INIT( msi_pending_custom_actions );
86 static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR action, UINT options)
91 if ((options & msidbCustomActionTypeClientRepeat) ==
92 msidbCustomActionTypeClientRepeat)
94 if (!(package->script->InWhatSequence & SEQUENCE_UI &&
95 package->script->InWhatSequence & SEQUENCE_EXEC))
97 TRACE("Skipping action due to dbCustomActionTypeClientRepeat option.\n");
101 else if (options & msidbCustomActionTypeFirstSequence)
103 if (package->script->InWhatSequence & SEQUENCE_UI &&
104 package->script->InWhatSequence & SEQUENCE_EXEC )
106 TRACE("Skipping action due to msidbCustomActionTypeFirstSequence option.\n");
110 else if (options & msidbCustomActionTypeOncePerProcess)
112 if (check_unique_action(package,action))
114 TRACE("Skipping action due to msidbCustomActionTypeOncePerProcess option.\n");
118 register_unique_action(package,action);
124 /* stores the CustomActionData before the action:
125 * [CustomActionData]Action
127 static LPWSTR msi_get_deferred_action(LPCWSTR action, LPWSTR actiondata)
132 static const WCHAR begin[] = {'[',0};
133 static const WCHAR end[] = {']',0};
136 return strdupW(action);
138 len = lstrlenW(action) + lstrlenW(actiondata) + 3;
139 deferred = msi_alloc(len * sizeof(WCHAR));
141 lstrcpyW(deferred, begin);
142 lstrcatW(deferred, actiondata);
143 lstrcatW(deferred, end);
144 lstrcatW(deferred, action);
149 UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
151 UINT rc = ERROR_SUCCESS;
153 static const WCHAR ExecSeqQuery[] =
154 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
155 '`','C','u','s','t','o' ,'m','A','c','t','i','o','n','`',
156 ' ','W','H','E','R','E',' ','`','A','c','t','i' ,'o','n','`',' ',
157 '=',' ','\'','%','s','\'',0};
159 LPCWSTR source, target;
160 LPWSTR ptr, deferred_data = NULL;
161 LPWSTR action_copy = strdupW(action);
162 WCHAR *deformated=NULL;
164 /* deferred action: [CustomActionData]Action */
165 if ((ptr = strchrW(action_copy, ']')))
167 deferred_data = action_copy + 1;
172 row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action );
175 msi_free(action_copy);
176 return ERROR_CALL_NOT_IMPLEMENTED;
179 type = MSI_RecordGetInteger(row,2);
181 source = MSI_RecordGetString(row,3);
182 target = MSI_RecordGetString(row,4);
184 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
185 debugstr_w(source), debugstr_w(target));
187 /* handle some of the deferred actions */
188 if (type & msidbCustomActionTypeTSAware)
189 FIXME("msidbCustomActionTypeTSAware not handled\n");
191 if (type & msidbCustomActionTypeInScript)
193 if (type & msidbCustomActionTypeNoImpersonate)
194 FIXME("msidbCustomActionTypeNoImpersonate not handled\n");
196 if (type & msidbCustomActionTypeRollback)
198 FIXME("Rollback only action... rollbacks not supported yet\n");
199 schedule_action(package, ROLLBACK_SCRIPT, action);
205 LPWSTR actiondata = msi_dup_property(package, action);
206 LPWSTR deferred = msi_get_deferred_action(action, actiondata);
208 if (type & msidbCustomActionTypeCommit)
210 TRACE("Deferring Commit Action!\n");
211 schedule_action(package, COMMIT_SCRIPT, deferred);
215 TRACE("Deferring Action!\n");
216 schedule_action(package, INSTALL_SCRIPT, deferred);
227 static const WCHAR szActionData[] = {
228 'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0};
229 static const WCHAR szBlank[] = {0};
230 LPWSTR actiondata = msi_dup_property( package, action );
232 MSI_SetPropertyW(package,szActionData,deferred_data);
234 MSI_SetPropertyW(package,szActionData,actiondata);
236 MSI_SetPropertyW(package,szActionData,szBlank);
237 msi_free(actiondata);
240 else if (!check_execution_scheduling_options(package,action,type))
246 switch (type & CUSTOM_ACTION_TYPE_MASK)
248 case 1: /* DLL file stored in a Binary table stream */
249 rc = HANDLE_CustomType1(package,source,target,type,action);
251 case 2: /* EXE file stored in a Binary table stream */
252 rc = HANDLE_CustomType2(package,source,target,type,action);
254 case 18: /*EXE file installed with package */
255 rc = HANDLE_CustomType18(package,source,target,type,action);
257 case 19: /* Error that halts install */
258 rc = HANDLE_CustomType19(package,source,target,type,action);
261 rc = HANDLE_CustomType17(package,source,target,type,action);
263 case 23: /* installs another package in the source tree */
264 deformat_string(package,target,&deformated);
265 rc = HANDLE_CustomType23(package,source,deformated,type,action);
267 case 50: /*EXE file specified by a property value */
268 rc = HANDLE_CustomType50(package,source,target,type,action);
270 case 34: /*EXE to be run in specified directory */
271 rc = HANDLE_CustomType34(package,source,target,type,action);
273 case 35: /* Directory set with formatted text. */
274 deformat_string(package,target,&deformated);
275 MSI_SetTargetPathW(package, source, deformated);
276 msi_free(deformated);
278 case 51: /* Property set with formatted text. */
279 deformat_string(package,target,&deformated);
280 rc = MSI_SetPropertyW(package,source,deformated);
281 msi_free(deformated);
283 case 37: /* JScript/VBScript text stored in target column. */
285 rc = HANDLE_CustomType37_38(package,source,target,type,action);
288 case 6: /* JScript/VBScript file stored in a Binary table stream. */
289 rc = HANDLE_CustomType5_6(package,source,target,type,action);
291 case 21: /* JScript/VBScript file installed with the product. */
293 rc = HANDLE_CustomType21_22(package,source,target,type,action);
295 case 53: /* JScript/VBScript text specified by a property value. */
297 rc = HANDLE_CustomType53_54(package,source,target,type,action);
300 FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
301 type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
306 msi_free(action_copy);
307 msiobj_release(&row->hdr);
312 static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
315 static const WCHAR query[] = {
316 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
317 '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
318 '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
322 static const WCHAR f1[] = {'m','s','i',0};
327 if (MSI_GetPropertyW(package, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
328 GetTempPathW(MAX_PATH, fmt);
330 if (GetTempFileNameW(fmt, f1, 0, tmp_file) == 0)
332 TRACE("Unable to create file\n");
333 return ERROR_FUNCTION_FAILED;
335 track_tempfile(package, tmp_file);
337 row = MSI_QueryGetRecord(package->db, query, source);
339 return ERROR_FUNCTION_FAILED;
341 /* write out the file */
342 file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
343 FILE_ATTRIBUTE_NORMAL, NULL);
344 if (file == INVALID_HANDLE_VALUE)
345 r = ERROR_FUNCTION_FAILED;
352 r = MSI_RecordReadStream(row, 2, buffer, &sz);
353 if (r != ERROR_SUCCESS)
355 ERR("Failed to get stream\n");
358 WriteFile(file, buffer, sz, &write, NULL);
359 } while (sz == sizeof buffer);
363 msiobj_release(&row->hdr);
368 static void file_running_action(MSIPACKAGE* package, HANDLE Handle,
369 BOOL process, LPCWSTR name)
371 MSIRUNNINGACTION *action;
373 action = msi_alloc( sizeof(MSIRUNNINGACTION) );
375 action->handle = Handle;
376 action->process = process;
377 action->name = strdupW(name);
379 list_add_tail( &package->RunningActions, &action->entry );
382 static UINT custom_get_process_return( HANDLE process )
386 GetExitCodeProcess( process, &rc );
388 return ERROR_FUNCTION_FAILED;
389 return ERROR_SUCCESS;
392 static UINT custom_get_thread_return( HANDLE thread )
396 GetExitCodeThread( thread, &rc );
400 case ERROR_FUNCTION_NOT_CALLED:
402 case ERROR_INSTALL_USEREXIT:
403 case ERROR_INSTALL_FAILURE:
405 case ERROR_NO_MORE_ITEMS:
406 return ERROR_SUCCESS;
408 ERR("Invalid Return Code %d\n",rc);
409 return ERROR_INSTALL_FAILURE;
413 static UINT wait_process_handle(MSIPACKAGE* package, UINT type,
414 HANDLE ProcessHandle, LPCWSTR name)
416 UINT rc = ERROR_SUCCESS;
418 if (!(type & msidbCustomActionTypeAsync))
420 TRACE("waiting for %s\n", debugstr_w(name));
422 msi_dialog_check_messages(ProcessHandle);
424 if (!(type & msidbCustomActionTypeContinue))
425 rc = custom_get_process_return(ProcessHandle);
427 CloseHandle(ProcessHandle);
431 TRACE("%s running in background\n", debugstr_w(name));
433 if (!(type & msidbCustomActionTypeContinue))
434 file_running_action(package, ProcessHandle, TRUE, name);
436 CloseHandle(ProcessHandle);
442 typedef struct _msi_custom_action_info {
451 } msi_custom_action_info;
453 static void free_custom_action_data( msi_custom_action_info *info )
455 EnterCriticalSection( &msi_custom_action_cs );
456 list_remove( &info->entry );
457 LeaveCriticalSection( &msi_custom_action_cs );
459 CloseHandle( info->handle );
460 msi_free( info->action );
461 msi_free( info->source );
462 msi_free( info->target );
463 msiobj_release( &info->package->hdr );
467 static UINT wait_thread_handle( msi_custom_action_info *info )
469 UINT rc = ERROR_SUCCESS;
471 if (!(info->type & msidbCustomActionTypeAsync))
473 TRACE("waiting for %s\n", debugstr_w( info->action ));
475 msi_dialog_check_messages( info->handle );
477 if (!(info->type & msidbCustomActionTypeContinue))
478 rc = custom_get_thread_return( info->handle );
480 free_custom_action_data( info );
484 TRACE("%s running in background\n", debugstr_w( info->action ));
490 static msi_custom_action_info *find_action_by_guid( const GUID *guid )
492 msi_custom_action_info *info;
495 EnterCriticalSection( &msi_custom_action_cs );
497 LIST_FOR_EACH_ENTRY( info, &msi_pending_custom_actions, msi_custom_action_info, entry )
499 if (IsEqualGUID( &info->guid, guid ))
506 LeaveCriticalSection( &msi_custom_action_cs );
514 static DWORD WINAPI ACTION_CallDllFunction( const GUID *guid )
516 msi_custom_action_info *info;
517 MsiCustomActionEntryPoint fn;
521 UINT r = ERROR_FUNCTION_FAILED;
523 info = find_action_by_guid( guid );
526 ERR("failed to find action %s\n", debugstr_guid( guid) );
530 TRACE("%s %s\n", debugstr_w( info->source ), debugstr_w( info->target ) );
532 hModule = LoadLibraryW( info->source );
535 ERR("failed to load dll %s\n", debugstr_w( info->source ) );
539 proc = strdupWtoA( info->target );
540 fn = (MsiCustomActionEntryPoint) GetProcAddress( hModule, proc );
544 hPackage = alloc_msihandle( &info->package->hdr );
547 TRACE("calling %s\n", debugstr_w( info->target ) );
549 MsiCloseHandle( hPackage );
552 ERR("failed to create handle for %p\n", info->package );
555 ERR("GetProcAddress(%s) failed\n", debugstr_w( info->target ) );
557 FreeLibrary(hModule);
559 if (info->type & msidbCustomActionTypeAsync &&
560 info->type & msidbCustomActionTypeContinue)
561 free_custom_action_data( info );
566 static DWORD WINAPI DllThread( LPVOID arg )
571 TRACE("custom action (%x) started\n", GetCurrentThreadId() );
573 rc = ACTION_CallDllFunction( guid );
575 TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc );
577 MsiCloseAllHandles();
581 static DWORD WINAPI ACTION_CAInstallPackage(const GUID *guid)
583 msi_custom_action_info *info;
584 UINT r = ERROR_FUNCTION_FAILED;
585 INSTALLUILEVEL old_level;
587 info = find_action_by_guid(guid);
590 ERR("failed to find action %s\n", debugstr_guid(guid));
594 old_level = MsiSetInternalUI(INSTALLUILEVEL_BASIC, NULL);
595 r = MsiInstallProductW(info->source, info->target);
596 MsiSetInternalUI(old_level, NULL);
601 static DWORD WINAPI ConcurrentInstallThread(LPVOID arg)
606 TRACE("concurrent installation (%x) started\n", GetCurrentThreadId());
608 rc = ACTION_CAInstallPackage(guid);
610 TRACE("concurrent installation (%x) returned %i\n", GetCurrentThreadId(), rc);
612 MsiCloseAllHandles();
616 static msi_custom_action_info *do_msidbCustomActionTypeDll(
617 MSIPACKAGE *package, INT type, LPCWSTR source, LPCWSTR target, LPCWSTR action )
619 msi_custom_action_info *info;
621 info = msi_alloc( sizeof *info );
625 msiobj_addref( &package->hdr );
626 info->package = package;
628 info->target = strdupW( target );
629 info->source = strdupW( source );
630 info->action = strdupW( action );
631 CoCreateGuid( &info->guid );
633 EnterCriticalSection( &msi_custom_action_cs );
634 list_add_tail( &msi_pending_custom_actions, &info->entry );
635 LeaveCriticalSection( &msi_custom_action_cs );
637 info->handle = CreateThread( NULL, 0, DllThread, &info->guid, 0, NULL );
640 free_custom_action_data( info );
647 static msi_custom_action_info *do_msidbCAConcurrentInstall(
648 MSIPACKAGE *package, INT type, LPCWSTR source, LPCWSTR target, LPCWSTR action)
650 msi_custom_action_info *info;
652 info = msi_alloc( sizeof *info );
656 msiobj_addref( &package->hdr );
657 info->package = package;
659 info->target = strdupW( target );
660 info->source = strdupW( source );
661 info->action = strdupW( action );
662 CoCreateGuid( &info->guid );
664 EnterCriticalSection( &msi_custom_action_cs );
665 list_add_tail( &msi_pending_custom_actions, &info->entry );
666 LeaveCriticalSection( &msi_custom_action_cs );
668 info->handle = CreateThread( NULL, 0, ConcurrentInstallThread, &info->guid, 0, NULL );
671 free_custom_action_data( info );
678 static UINT HANDLE_CustomType23(MSIPACKAGE *package, LPCWSTR source,
679 LPCWSTR target, const INT type, LPCWSTR action)
681 msi_custom_action_info *info;
682 WCHAR package_path[MAX_PATH];
685 static const WCHAR backslash[] = {'\\',0};
687 MSI_GetPropertyW(package, cszSourceDir, package_path, &size);
688 lstrcatW(package_path, backslash);
689 lstrcatW(package_path, source);
691 if (GetFileAttributesW(package_path) == INVALID_FILE_ATTRIBUTES)
693 ERR("Source package does not exist: %s\n", debugstr_w(package_path));
694 return ERROR_FUNCTION_FAILED;
697 TRACE("Installing package %s concurrently\n", debugstr_w(package_path));
699 info = do_msidbCAConcurrentInstall(package, type, package_path, target, action);
701 return wait_thread_handle(info);
704 static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
705 LPCWSTR target, const INT type, LPCWSTR action)
707 msi_custom_action_info *info;
708 WCHAR tmp_file[MAX_PATH];
711 r = store_binary_to_temp(package, source, tmp_file);
712 if (r != ERROR_SUCCESS)
715 TRACE("Calling function %s from %s\n",debugstr_w(target),
716 debugstr_w(tmp_file));
718 if (!strchrW(tmp_file,'.'))
720 static const WCHAR dot[]={'.',0};
721 strcatW(tmp_file,dot);
724 info = do_msidbCustomActionTypeDll( package, type, tmp_file, target, action );
726 return wait_thread_handle( info );
729 static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
730 LPCWSTR target, const INT type, LPCWSTR action)
732 WCHAR tmp_file[MAX_PATH];
734 PROCESS_INFORMATION info;
737 WCHAR *deformated = NULL;
739 static const WCHAR spc[] = {' ',0};
742 memset(&si,0,sizeof(STARTUPINFOW));
744 r = store_binary_to_temp(package, source, tmp_file);
745 if (r != ERROR_SUCCESS)
748 deformat_string(package,target,&deformated);
750 len = strlenW(tmp_file)+2;
753 len += strlenW(deformated);
755 cmd = msi_alloc(sizeof(WCHAR)*len);
757 strcpyW(cmd,tmp_file);
761 strcatW(cmd,deformated);
763 msi_free(deformated);
766 TRACE("executing exe %s\n", debugstr_w(cmd));
768 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
769 c_collen, &si, &info);
774 ERR("Unable to execute command %s\n", debugstr_w(cmd));
775 return ERROR_SUCCESS;
777 CloseHandle( info.hThread );
779 r = wait_process_handle(package, type, info.hProcess, action);
784 static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source,
785 LPCWSTR target, const INT type, LPCWSTR action)
787 msi_custom_action_info *info;
790 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
792 file = get_loaded_file( package, source );
795 ERR("invalid file key %s\n", debugstr_w( source ));
796 return ERROR_FUNCTION_FAILED;
799 info = do_msidbCustomActionTypeDll( package, type, file->TargetPath, target, action );
801 return wait_thread_handle( info );
804 static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
805 LPCWSTR target, const INT type, LPCWSTR action)
808 PROCESS_INFORMATION info;
813 static const WCHAR spc[] = {' ',0};
816 memset(&si,0,sizeof(STARTUPINFOW));
818 file = get_loaded_file(package,source);
820 return ERROR_FUNCTION_FAILED;
822 len = lstrlenW( file->TargetPath );
824 deformat_string(package,target,&deformated);
826 len += strlenW(deformated);
829 cmd = msi_alloc(len * sizeof(WCHAR));
831 lstrcpyW( cmd, file->TargetPath);
835 strcatW(cmd, deformated);
837 msi_free(deformated);
840 TRACE("executing exe %s\n", debugstr_w(cmd));
842 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
843 c_collen, &si, &info);
847 ERR("Unable to execute command %s\n", debugstr_w(cmd));
849 return ERROR_SUCCESS;
852 CloseHandle( info.hThread );
854 return wait_process_handle(package, type, info.hProcess, action);
857 static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source,
858 LPCWSTR target, const INT type, LPCWSTR action)
860 static const WCHAR query[] = {
861 'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
862 'F','R','O','M',' ','`','E','r','r','o','r','`',' ',
863 'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ',
867 LPWSTR deformated = NULL;
869 deformat_string( package, target, &deformated );
871 /* first try treat the error as a number */
872 row = MSI_QueryGetRecord( package->db, query, deformated );
875 LPCWSTR error = MSI_RecordGetString( row, 1 );
876 MessageBoxW( NULL, error, NULL, MB_OK );
877 msiobj_release( &row->hdr );
880 MessageBoxW( NULL, deformated, NULL, MB_OK );
882 msi_free( deformated );
884 return ERROR_FUNCTION_FAILED;
887 static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
888 LPCWSTR target, const INT type, LPCWSTR action)
891 PROCESS_INFORMATION info;
897 static const WCHAR spc[] = {' ',0};
899 memset(&si,0,sizeof(STARTUPINFOW));
900 memset(&info,0,sizeof(PROCESS_INFORMATION));
902 prop = msi_dup_property( package, source );
904 return ERROR_SUCCESS;
906 deformat_string(package,target,&deformated);
907 len = strlenW(prop) + 2;
909 len += strlenW(deformated);
911 cmd = msi_alloc(sizeof(WCHAR)*len);
917 strcatW(cmd,deformated);
919 msi_free(deformated);
923 TRACE("executing exe %s\n", debugstr_w(cmd));
925 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
926 c_collen, &si, &info);
930 ERR("Unable to execute command %s\n", debugstr_w(cmd));
932 return ERROR_SUCCESS;
936 CloseHandle( info.hThread );
938 return wait_process_handle(package, type, info.hProcess, action);
941 static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
942 LPCWSTR target, const INT type, LPCWSTR action)
944 LPWSTR filename, deformated;
946 PROCESS_INFORMATION info;
949 memset(&si,0,sizeof(STARTUPINFOW));
951 filename = resolve_folder(package, source, FALSE, FALSE, TRUE, NULL);
954 return ERROR_FUNCTION_FAILED;
956 SetCurrentDirectoryW(filename);
959 deformat_string(package,target,&deformated);
962 return ERROR_FUNCTION_FAILED;
964 TRACE("executing exe %s\n", debugstr_w(deformated));
966 rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
967 c_collen, &si, &info);
971 ERR("Unable to execute command %s\n", debugstr_w(deformated));
972 msi_free(deformated);
973 return ERROR_SUCCESS;
975 msi_free(deformated);
976 CloseHandle( info.hThread );
978 return wait_process_handle(package, type, info.hProcess, action);
981 static DWORD WINAPI ACTION_CallScript( const LPGUID guid )
983 msi_custom_action_info *info;
985 UINT r = ERROR_FUNCTION_FAILED;
987 info = find_action_by_guid( guid );
990 ERR("failed to find action %s\n", debugstr_guid( guid) );
994 TRACE("function %s, script %s\n", debugstr_w( info->target ), debugstr_w( info->source ) );
996 hPackage = alloc_msihandle( &info->package->hdr );
999 r = call_script( hPackage, info->type, info->source, info->target, info->action );
1000 MsiCloseHandle( hPackage );
1003 ERR("failed to create handle for %p\n", info->package );
1005 if (info->type & msidbCustomActionTypeAsync &&
1006 info->type & msidbCustomActionTypeContinue)
1007 free_custom_action_data( info );
1012 static DWORD WINAPI ScriptThread( LPVOID arg )
1017 TRACE("custom action (%x) started\n", GetCurrentThreadId() );
1019 rc = ACTION_CallScript( guid );
1021 TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc );
1023 MsiCloseAllHandles();
1027 static msi_custom_action_info *do_msidbCustomActionTypeScript(
1028 MSIPACKAGE *package, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action )
1030 msi_custom_action_info *info;
1032 info = msi_alloc( sizeof *info );
1036 msiobj_addref( &package->hdr );
1037 info->package = package;
1039 info->target = strdupW( function );
1040 info->source = strdupW( script );
1041 info->action = strdupW( action );
1042 CoCreateGuid( &info->guid );
1044 EnterCriticalSection( &msi_custom_action_cs );
1045 list_add_tail( &msi_pending_custom_actions, &info->entry );
1046 LeaveCriticalSection( &msi_custom_action_cs );
1048 info->handle = CreateThread( NULL, 0, ScriptThread, &info->guid, 0, NULL );
1051 free_custom_action_data( info );
1058 static UINT HANDLE_CustomType37_38(MSIPACKAGE *package, LPCWSTR source,
1059 LPCWSTR target, const INT type, LPCWSTR action)
1061 msi_custom_action_info *info;
1063 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
1065 info = do_msidbCustomActionTypeScript( package, type, target, NULL, action );
1067 return wait_thread_handle( info );
1070 static UINT HANDLE_CustomType5_6(MSIPACKAGE *package, LPCWSTR source,
1071 LPCWSTR target, const INT type, LPCWSTR action)
1073 static const WCHAR query[] = {
1074 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1075 '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
1076 '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
1078 msi_custom_action_info *info;
1079 CHAR *buffer = NULL;
1080 WCHAR *bufferw = NULL;
1084 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
1086 row = MSI_QueryGetRecord(package->db, query, source);
1088 return ERROR_FUNCTION_FAILED;
1090 r = MSI_RecordReadStream(row, 2, NULL, &sz);
1091 if (r != ERROR_SUCCESS)
1094 buffer = msi_alloc(sizeof(CHAR)*(sz+1));
1096 return ERROR_FUNCTION_FAILED;
1098 r = MSI_RecordReadStream(row, 2, buffer, &sz);
1099 if (r != ERROR_SUCCESS)
1103 bufferw = strdupAtoW(buffer);
1106 r = ERROR_FUNCTION_FAILED;
1110 info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action );
1111 r = wait_thread_handle( info );
1119 static UINT HANDLE_CustomType21_22(MSIPACKAGE *package, LPCWSTR source,
1120 LPCWSTR target, const INT type, LPCWSTR action)
1122 msi_custom_action_info *info;
1125 DWORD sz, szHighWord = 0, read;
1127 WCHAR *bufferw=NULL;
1131 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
1133 file = get_loaded_file(package,source);
1136 ERR("invalid file key %s\n", debugstr_w(source));
1137 return ERROR_FUNCTION_FAILED;
1140 hFile = CreateFileW(file->TargetPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
1141 if (hFile == INVALID_HANDLE_VALUE)
1142 return ERROR_FUNCTION_FAILED;
1144 sz = GetFileSize(hFile, &szHighWord);
1145 if (sz == INVALID_FILE_SIZE || szHighWord != 0)
1148 return ERROR_FUNCTION_FAILED;
1151 buffer = msi_alloc(sizeof(CHAR)*(sz+1));
1155 return ERROR_FUNCTION_FAILED;
1158 bRet = ReadFile(hFile, buffer, sz, &read, NULL);
1162 r = ERROR_FUNCTION_FAILED;
1167 bufferw = strdupAtoW(buffer);
1170 r = ERROR_FUNCTION_FAILED;
1174 info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action );
1175 r = wait_thread_handle( info );
1183 static UINT HANDLE_CustomType53_54(MSIPACKAGE *package, LPCWSTR source,
1184 LPCWSTR target, const INT type, LPCWSTR action)
1186 msi_custom_action_info *info;
1189 TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
1191 prop = msi_dup_property(package,source);
1193 return ERROR_SUCCESS;
1195 info = do_msidbCustomActionTypeScript( package, type, prop, NULL, action );
1197 return wait_thread_handle( info );
1200 void ACTION_FinishCustomActions(MSIPACKAGE* package)
1203 HANDLE *wait_handles;
1204 unsigned int handle_count, i;
1205 msi_custom_action_info *info, *cursor;
1207 while ((item = list_head( &package->RunningActions )))
1209 MSIRUNNINGACTION *action = LIST_ENTRY( item, MSIRUNNINGACTION, entry );
1211 list_remove( &action->entry );
1213 TRACE("waiting for %s\n", debugstr_w( action->name ) );
1214 msi_dialog_check_messages( action->handle );
1216 CloseHandle( action->handle );
1217 msi_free( action->name );
1221 EnterCriticalSection( &msi_custom_action_cs );
1223 handle_count = list_count( &msi_pending_custom_actions );
1224 wait_handles = HeapAlloc( GetProcessHeap(), 0, handle_count * sizeof(HANDLE) );
1227 LIST_FOR_EACH_ENTRY_SAFE( info, cursor, &msi_pending_custom_actions, msi_custom_action_info, entry )
1229 if (info->package == package )
1231 if (DuplicateHandle(GetCurrentProcess(), info->handle, GetCurrentProcess(), &wait_handles[handle_count], SYNCHRONIZE, FALSE, 0))
1233 free_custom_action_data( info );
1237 LeaveCriticalSection( &msi_custom_action_cs );
1239 for (i = 0; i < handle_count; i++)
1241 msi_dialog_check_messages( wait_handles[i] );
1242 CloseHandle( wait_handles[i] );
1245 HeapFree( GetProcessHeap(), 0, wait_handles );