windows.media: Partially implement IClosedCaptionPropertiesStatics_get_FontSize.
[wine.git] / dlls / msi / action.c
blob06cd582a389e0f53e8ff3782aef1504324166ffa
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "winsvc.h"
30 #include "odbcinst.h"
31 #include "wine/debug.h"
32 #include "msidefs.h"
33 #include "winuser.h"
34 #include "shlobj.h"
35 #include "objbase.h"
36 #include "mscoree.h"
37 #include "shlwapi.h"
38 #include "imagehlp.h"
39 #include "winver.h"
41 #include "msipriv.h"
42 #include "resource.h"
44 #define REG_PROGRESS_VALUE 13200
45 #define COMPONENT_PROGRESS_VALUE 24000
47 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 static INT ui_actionstart(MSIPACKAGE *package, LPCWSTR action, LPCWSTR description, LPCWSTR template)
51 MSIRECORD *row, *textrow;
52 INT rc;
54 textrow = MSI_QueryGetRecord(package->db, L"SELECT * FROM `ActionText` WHERE `Action` = '%s'", action);
55 if (textrow)
57 description = MSI_RecordGetString(textrow, 2);
58 template = MSI_RecordGetString(textrow, 3);
61 row = MSI_CreateRecord(3);
62 if (!row) return -1;
63 MSI_RecordSetStringW(row, 1, action);
64 MSI_RecordSetStringW(row, 2, description);
65 MSI_RecordSetStringW(row, 3, template);
66 rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
67 if (textrow) msiobj_release(&textrow->hdr);
68 msiobj_release(&row->hdr);
69 return rc;
72 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
73 INT rc)
75 MSIRECORD *row;
76 WCHAR *template;
78 template = msi_get_error_message(package->db, start ? MSIERR_INFO_ACTIONSTART : MSIERR_INFO_ACTIONENDED);
80 row = MSI_CreateRecord(2);
81 if (!row)
83 msi_free(template);
84 return;
86 MSI_RecordSetStringW(row, 0, template);
87 MSI_RecordSetStringW(row, 1, action);
88 MSI_RecordSetInteger(row, 2, start ? package->LastActionResult : rc);
89 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
90 msiobj_release(&row->hdr);
91 msi_free(template);
92 if (!start) package->LastActionResult = rc;
95 enum parse_state
97 state_whitespace,
98 state_token,
99 state_quote
102 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
104 enum parse_state state = state_quote;
105 const WCHAR *p;
106 WCHAR *out = value;
107 BOOL ignore, in_quotes = FALSE;
108 int count = 0, len = 0;
110 for (p = str; *p; p++)
112 ignore = FALSE;
113 switch (state)
115 case state_whitespace:
116 switch (*p)
118 case ' ':
119 in_quotes = TRUE;
120 ignore = TRUE;
121 len++;
122 break;
123 case '"':
124 state = state_quote;
125 if (in_quotes && p[1] != '\"') count--;
126 else count++;
127 break;
128 default:
129 state = state_token;
130 in_quotes = TRUE;
131 len++;
132 break;
134 break;
136 case state_token:
137 switch (*p)
139 case '"':
140 state = state_quote;
141 if (in_quotes) count--;
142 else count++;
143 break;
144 case ' ':
145 state = state_whitespace;
146 if (!count) goto done;
147 in_quotes = TRUE;
148 len++;
149 break;
150 default:
151 if (count) in_quotes = TRUE;
152 len++;
153 break;
155 break;
157 case state_quote:
158 switch (*p)
160 case '"':
161 if (in_quotes && p[1] != '\"') count--;
162 else count++;
163 break;
164 case ' ':
165 state = state_whitespace;
166 if (!count || (count > 1 && !len)) goto done;
167 in_quotes = TRUE;
168 len++;
169 break;
170 default:
171 state = state_token;
172 if (count) in_quotes = TRUE;
173 len++;
174 break;
176 break;
178 default: break;
180 if (!ignore && value) *out++ = *p;
181 if (!count) in_quotes = FALSE;
184 done:
185 if (value)
187 if (!len) *value = 0;
188 else *out = 0;
191 if(quotes) *quotes = count;
192 return p - str;
195 static void remove_quotes( WCHAR *str )
197 WCHAR *p = str;
198 int len = lstrlenW( str );
200 while ((p = wcschr( p, '"' )))
202 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
203 p++;
207 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
208 BOOL preserve_case )
210 LPCWSTR ptr, ptr2;
211 int num_quotes;
212 DWORD len;
213 WCHAR *prop, *val;
214 UINT r;
216 if (!szCommandLine)
217 return ERROR_SUCCESS;
219 ptr = szCommandLine;
220 while (*ptr)
222 while (*ptr == ' ') ptr++;
223 if (!*ptr) break;
225 ptr2 = wcschr( ptr, '=' );
226 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
228 len = ptr2 - ptr;
229 if (!len) return ERROR_INVALID_COMMAND_LINE;
231 while (ptr[len - 1] == ' ') len--;
233 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
234 memcpy( prop, ptr, len * sizeof(WCHAR) );
235 prop[len] = 0;
236 if (!preserve_case) wcsupr( prop );
238 ptr2++;
239 while (*ptr2 == ' ') ptr2++;
241 num_quotes = 0;
242 val = msi_alloc( (lstrlenW( ptr2 ) + 1) * sizeof(WCHAR) );
243 len = parse_prop( ptr2, val, &num_quotes );
244 if (num_quotes % 2)
246 WARN("unbalanced quotes\n");
247 msi_free( val );
248 msi_free( prop );
249 return ERROR_INVALID_COMMAND_LINE;
251 remove_quotes( val );
252 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
254 r = msi_set_property( package->db, prop, val, -1 );
255 if (r == ERROR_SUCCESS && !wcscmp( prop, L"SourceDir" ))
256 msi_reset_source_folders( package );
258 msi_free( val );
259 msi_free( prop );
261 ptr = ptr2 + len;
264 return ERROR_SUCCESS;
267 const WCHAR *msi_get_command_line_option(const WCHAR *cmd, const WCHAR *option, UINT *len)
269 DWORD opt_len = lstrlenW(option);
271 if (!cmd)
272 return NULL;
274 while (*cmd)
276 BOOL found = FALSE;
278 while (*cmd == ' ') cmd++;
279 if (!*cmd) break;
281 if(!wcsnicmp(cmd, option, opt_len))
282 found = TRUE;
284 cmd = wcschr( cmd, '=' );
285 if(!cmd) break;
286 cmd++;
287 while (*cmd == ' ') cmd++;
288 if (!*cmd) break;
290 *len = parse_prop( cmd, NULL, NULL);
291 if (found) return cmd;
292 cmd += *len;
295 return NULL;
298 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
300 LPCWSTR pc;
301 LPWSTR p, *ret = NULL;
302 UINT count = 0;
304 if (!str)
305 return ret;
307 /* count the number of substrings */
308 for ( pc = str, count = 0; pc; count++ )
310 pc = wcschr( pc, sep );
311 if (pc)
312 pc++;
315 /* allocate space for an array of substring pointers and the substrings */
316 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
317 (lstrlenW(str)+1) * sizeof(WCHAR) );
318 if (!ret)
319 return ret;
321 /* copy the string and set the pointers */
322 p = (LPWSTR) &ret[count+1];
323 lstrcpyW( p, str );
324 for( count = 0; (ret[count] = p); count++ )
326 p = wcschr( p, sep );
327 if (p)
328 *p++ = 0;
331 return ret;
334 static BOOL ui_sequence_exists( MSIPACKAGE *package )
336 MSIQUERY *view;
337 DWORD count = 0;
339 if (!(MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0", &view )))
341 MSI_IterateRecords( view, &count, NULL, package );
342 msiobj_release( &view->hdr );
344 return count != 0;
347 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
349 WCHAR *source, *check, *p, *db;
350 DWORD len;
352 if (!(db = msi_dup_property( package->db, L"OriginalDatabase" )))
353 return ERROR_OUTOFMEMORY;
355 if (!(p = wcsrchr( db, '\\' )) && !(p = wcsrchr( db, '/' )))
357 msi_free(db);
358 return ERROR_SUCCESS;
360 len = p - db + 2;
361 source = msi_alloc( len * sizeof(WCHAR) );
362 lstrcpynW( source, db, len );
363 msi_free( db );
365 check = msi_dup_property( package->db, L"SourceDir" );
366 if (!check || replace)
368 UINT r = msi_set_property( package->db, L"SourceDir", source, -1 );
369 if (r == ERROR_SUCCESS)
370 msi_reset_source_folders( package );
372 msi_free( check );
374 check = msi_dup_property( package->db, L"SOURCEDIR" );
375 if (!check || replace)
376 msi_set_property( package->db, L"SOURCEDIR", source, -1 );
378 msi_free( check );
379 msi_free( source );
381 return ERROR_SUCCESS;
384 static BOOL needs_ui_sequence(MSIPACKAGE *package)
386 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
389 UINT msi_set_context(MSIPACKAGE *package)
391 UINT r = msi_locate_product( package->ProductCode, &package->Context );
392 if (r != ERROR_SUCCESS)
394 int num = msi_get_property_int( package->db, L"ALLUSERS", 0 );
395 if (num == 1 || num == 2)
396 package->Context = MSIINSTALLCONTEXT_MACHINE;
397 else
398 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
400 return ERROR_SUCCESS;
403 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
405 UINT rc;
406 LPCWSTR cond, action;
407 MSIPACKAGE *package = param;
409 action = MSI_RecordGetString(row,1);
410 if (!action)
412 ERR("Error is retrieving action name\n");
413 return ERROR_FUNCTION_FAILED;
416 /* check conditions */
417 cond = MSI_RecordGetString(row,2);
419 /* this is a hack to skip errors in the condition code */
420 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
422 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
423 return ERROR_SUCCESS;
426 rc = ACTION_PerformAction(package, action);
428 msi_dialog_check_messages( NULL );
430 if (rc == ERROR_FUNCTION_NOT_CALLED)
431 rc = ERROR_SUCCESS;
433 if (rc != ERROR_SUCCESS)
434 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
436 if (package->need_reboot_now)
438 TRACE("action %s asked for immediate reboot, suspending installation\n",
439 debugstr_w(action));
440 rc = ACTION_ForceReboot( package );
442 return rc;
445 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
447 MSIQUERY *view;
448 UINT r;
450 TRACE("%p %s\n", package, debugstr_w(table));
452 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `%s` WHERE `Sequence` > 0 ORDER BY `Sequence`", table );
453 if (r == ERROR_SUCCESS)
455 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
456 msiobj_release(&view->hdr);
458 return r;
461 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package)
463 MSIQUERY *view;
464 UINT rc;
466 if (package->ExecuteSequenceRun)
468 TRACE("Execute Sequence already Run\n");
469 return ERROR_SUCCESS;
472 package->ExecuteSequenceRun = TRUE;
474 rc = MSI_OpenQuery(package->db, &view,
475 L"SELECT * FROM `InstallExecuteSequence` WHERE `Sequence` > 0 ORDER BY `Sequence`");
476 if (rc == ERROR_SUCCESS)
478 TRACE("Running the actions\n");
480 msi_set_property( package->db, L"SourceDir", NULL, -1 );
481 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
482 msiobj_release(&view->hdr);
484 return rc;
487 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
489 MSIQUERY *view;
490 UINT rc;
492 rc = MSI_DatabaseOpenViewW(package->db,
493 L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0 ORDER BY `Sequence`",
494 &view);
495 if (rc == ERROR_SUCCESS)
497 TRACE("Running the actions\n");
498 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
499 msiobj_release(&view->hdr);
501 return rc;
504 /********************************************************
505 * ACTION helper functions and functions that perform the actions
506 *******************************************************/
507 static UINT ACTION_HandleCustomAction(MSIPACKAGE *package, LPCWSTR action)
509 UINT arc;
510 INT uirc;
512 uirc = ui_actionstart(package, action, NULL, NULL);
513 if (uirc == IDCANCEL)
514 return ERROR_INSTALL_USEREXIT;
515 ui_actioninfo(package, action, TRUE, 0);
516 arc = ACTION_CustomAction(package, action);
517 uirc = !arc;
519 if (arc == ERROR_FUNCTION_NOT_CALLED && needs_ui_sequence(package))
521 uirc = ACTION_ShowDialog(package, action);
522 switch (uirc)
524 case -1:
525 return ERROR_SUCCESS; /* stop immediately */
526 case 0: arc = ERROR_FUNCTION_NOT_CALLED; break;
527 case 1: arc = ERROR_SUCCESS; break;
528 case 2: arc = ERROR_INSTALL_USEREXIT; break;
529 case 3: arc = ERROR_INSTALL_FAILURE; break;
530 case 4: arc = ERROR_INSTALL_SUSPEND; break;
531 case 5: arc = ERROR_MORE_DATA; break;
532 case 6: arc = ERROR_INVALID_HANDLE_STATE; break;
533 case 7: arc = ERROR_INVALID_DATA; break;
534 case 8: arc = ERROR_INSTALL_ALREADY_RUNNING; break;
535 case 9: arc = ERROR_INSTALL_PACKAGE_REJECTED; break;
536 default: arc = ERROR_FUNCTION_FAILED; break;
540 ui_actioninfo(package, action, FALSE, uirc);
542 return arc;
545 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
547 MSICOMPONENT *comp;
549 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
551 if (!wcscmp( Component, comp->Component )) return comp;
553 return NULL;
556 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
558 MSIFEATURE *feature;
560 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
562 if (!wcscmp( Feature, feature->Feature )) return feature;
564 return NULL;
567 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
569 MSIFILE *file;
571 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
573 if (!wcscmp( key, file->File )) return file;
575 return NULL;
578 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
580 MSIFOLDER *folder;
582 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
584 if (!wcscmp( dir, folder->Directory )) return folder;
586 return NULL;
589 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
591 MSIRECORD *row;
593 row = MSI_CreateRecord( 4 );
594 MSI_RecordSetInteger( row, 1, a );
595 MSI_RecordSetInteger( row, 2, b );
596 MSI_RecordSetInteger( row, 3, c );
597 MSI_RecordSetInteger( row, 4, d );
598 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
599 msiobj_release( &row->hdr );
601 msi_dialog_check_messages( NULL );
604 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
606 if (!comp->Enabled)
608 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
609 return INSTALLSTATE_UNKNOWN;
611 if (package->need_rollback) return comp->Installed;
612 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
614 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
615 return INSTALLSTATE_UNKNOWN;
617 return comp->ActionRequest;
620 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
622 if (package->need_rollback) return feature->Installed;
623 return feature->ActionRequest;
626 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
628 MSIPACKAGE *package = param;
629 LPCWSTR dir, component, full_path;
630 MSIRECORD *uirow;
631 MSIFOLDER *folder;
632 MSICOMPONENT *comp;
634 component = MSI_RecordGetString(row, 2);
635 if (!component)
636 return ERROR_SUCCESS;
638 comp = msi_get_loaded_component(package, component);
639 if (!comp)
640 return ERROR_SUCCESS;
642 comp->Action = msi_get_component_action( package, comp );
643 if (comp->Action != INSTALLSTATE_LOCAL)
645 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
646 return ERROR_SUCCESS;
649 dir = MSI_RecordGetString(row,1);
650 if (!dir)
652 ERR("Unable to get folder id\n");
653 return ERROR_SUCCESS;
656 uirow = MSI_CreateRecord(1);
657 MSI_RecordSetStringW(uirow, 1, dir);
658 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
659 msiobj_release(&uirow->hdr);
661 full_path = msi_get_target_folder( package, dir );
662 if (!full_path)
664 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
665 return ERROR_SUCCESS;
667 TRACE("folder is %s\n", debugstr_w(full_path));
669 folder = msi_get_loaded_folder( package, dir );
670 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( package, full_path );
671 folder->State = FOLDER_STATE_CREATED;
673 return ERROR_SUCCESS;
676 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
678 MSIQUERY *view;
679 UINT rc;
681 if (package->script == SCRIPT_NONE)
682 return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateFolders");
684 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view );
685 if (rc != ERROR_SUCCESS)
686 return ERROR_SUCCESS;
688 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
689 msiobj_release(&view->hdr);
690 return rc;
693 static void remove_persistent_folder( MSIFOLDER *folder )
695 FolderList *fl;
697 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
699 remove_persistent_folder( fl->folder );
701 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
703 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
707 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
709 MSIPACKAGE *package = param;
710 LPCWSTR dir, component, full_path;
711 MSIRECORD *uirow;
712 MSIFOLDER *folder;
713 MSICOMPONENT *comp;
715 component = MSI_RecordGetString(row, 2);
716 if (!component)
717 return ERROR_SUCCESS;
719 comp = msi_get_loaded_component(package, component);
720 if (!comp)
721 return ERROR_SUCCESS;
723 comp->Action = msi_get_component_action( package, comp );
724 if (comp->Action != INSTALLSTATE_ABSENT)
726 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
727 return ERROR_SUCCESS;
730 dir = MSI_RecordGetString( row, 1 );
731 if (!dir)
733 ERR("Unable to get folder id\n");
734 return ERROR_SUCCESS;
737 full_path = msi_get_target_folder( package, dir );
738 if (!full_path)
740 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
741 return ERROR_SUCCESS;
743 TRACE("folder is %s\n", debugstr_w(full_path));
745 uirow = MSI_CreateRecord( 1 );
746 MSI_RecordSetStringW( uirow, 1, dir );
747 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
748 msiobj_release( &uirow->hdr );
750 folder = msi_get_loaded_folder( package, dir );
751 remove_persistent_folder( folder );
752 return ERROR_SUCCESS;
755 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
757 MSIQUERY *view;
758 UINT rc;
760 if (package->script == SCRIPT_NONE)
761 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveFolders");
763 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view );
764 if (rc != ERROR_SUCCESS)
765 return ERROR_SUCCESS;
767 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
768 msiobj_release( &view->hdr );
769 return rc;
772 static UINT load_component( MSIRECORD *row, LPVOID param )
774 MSIPACKAGE *package = param;
775 MSICOMPONENT *comp;
777 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
778 if (!comp)
779 return ERROR_FUNCTION_FAILED;
781 list_add_tail( &package->components, &comp->entry );
783 /* fill in the data */
784 comp->Component = msi_dup_record_field( row, 1 );
786 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
788 comp->ComponentId = msi_dup_record_field( row, 2 );
789 comp->Directory = msi_dup_record_field( row, 3 );
790 comp->Attributes = MSI_RecordGetInteger(row,4);
791 comp->Condition = msi_dup_record_field( row, 5 );
792 comp->KeyPath = msi_dup_record_field( row, 6 );
794 comp->Installed = INSTALLSTATE_UNKNOWN;
795 comp->Action = INSTALLSTATE_UNKNOWN;
796 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
798 comp->assembly = msi_load_assembly( package, comp );
799 return ERROR_SUCCESS;
802 UINT msi_load_all_components( MSIPACKAGE *package )
804 MSIQUERY *view;
805 UINT r;
807 if (!list_empty(&package->components))
808 return ERROR_SUCCESS;
810 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Component`", &view );
811 if (r != ERROR_SUCCESS)
812 return r;
814 r = MSI_IterateRecords(view, NULL, load_component, package);
815 msiobj_release(&view->hdr);
816 return r;
819 typedef struct {
820 MSIPACKAGE *package;
821 MSIFEATURE *feature;
822 } _ilfs;
824 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
826 ComponentList *cl;
828 cl = msi_alloc( sizeof (*cl) );
829 if ( !cl )
830 return ERROR_NOT_ENOUGH_MEMORY;
831 cl->component = comp;
832 list_add_tail( &feature->Components, &cl->entry );
834 return ERROR_SUCCESS;
837 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
839 FeatureList *fl;
841 fl = msi_alloc( sizeof(*fl) );
842 if ( !fl )
843 return ERROR_NOT_ENOUGH_MEMORY;
844 fl->feature = child;
845 list_add_tail( &parent->Children, &fl->entry );
847 return ERROR_SUCCESS;
850 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
852 _ilfs* ilfs = param;
853 LPCWSTR component;
854 MSICOMPONENT *comp;
856 component = MSI_RecordGetString(row,1);
858 /* check to see if the component is already loaded */
859 comp = msi_get_loaded_component( ilfs->package, component );
860 if (!comp)
862 WARN("ignoring unknown component %s\n", debugstr_w(component));
863 return ERROR_SUCCESS;
865 add_feature_component( ilfs->feature, comp );
866 comp->Enabled = TRUE;
868 return ERROR_SUCCESS;
871 static UINT load_feature(MSIRECORD *row, LPVOID param)
873 MSIPACKAGE *package = param;
874 MSIFEATURE *feature;
875 MSIQUERY *view;
876 _ilfs ilfs;
877 UINT rc;
879 /* fill in the data */
881 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
882 if (!feature)
883 return ERROR_NOT_ENOUGH_MEMORY;
885 list_init( &feature->Children );
886 list_init( &feature->Components );
888 feature->Feature = msi_dup_record_field( row, 1 );
890 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
892 feature->Feature_Parent = msi_dup_record_field( row, 2 );
893 feature->Title = msi_dup_record_field( row, 3 );
894 feature->Description = msi_dup_record_field( row, 4 );
896 if (!MSI_RecordIsNull(row,5))
897 feature->Display = MSI_RecordGetInteger(row,5);
899 feature->Level= MSI_RecordGetInteger(row,6);
900 feature->Directory = msi_dup_record_field( row, 7 );
901 feature->Attributes = MSI_RecordGetInteger(row,8);
903 feature->Installed = INSTALLSTATE_UNKNOWN;
904 feature->Action = INSTALLSTATE_UNKNOWN;
905 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
907 list_add_tail( &package->features, &feature->entry );
909 /* load feature components */
911 rc = MSI_OpenQuery( package->db, &view, L"SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = '%s'",
912 feature->Feature );
913 if (rc != ERROR_SUCCESS)
914 return ERROR_SUCCESS;
916 ilfs.package = package;
917 ilfs.feature = feature;
919 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
920 msiobj_release(&view->hdr);
921 return rc;
924 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
926 MSIPACKAGE *package = param;
927 MSIFEATURE *parent, *child;
929 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
930 if (!child)
931 return ERROR_FUNCTION_FAILED;
933 if (!child->Feature_Parent)
934 return ERROR_SUCCESS;
936 parent = msi_get_loaded_feature( package, child->Feature_Parent );
937 if (!parent)
938 return ERROR_FUNCTION_FAILED;
940 add_feature_child( parent, child );
941 return ERROR_SUCCESS;
944 UINT msi_load_all_features( MSIPACKAGE *package )
946 MSIQUERY *view;
947 UINT r;
949 if (!list_empty(&package->features))
950 return ERROR_SUCCESS;
952 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Feature` ORDER BY `Display`", &view );
953 if (r != ERROR_SUCCESS)
954 return r;
956 r = MSI_IterateRecords( view, NULL, load_feature, package );
957 if (r != ERROR_SUCCESS)
959 msiobj_release( &view->hdr );
960 return r;
962 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
963 msiobj_release( &view->hdr );
964 return r;
967 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
969 if (!p)
970 return p;
971 p = wcschr(p, ch);
972 if (!p)
973 return p;
974 *p = 0;
975 return p+1;
978 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
980 MSIQUERY *view = NULL;
981 MSIRECORD *row = NULL;
982 UINT r;
984 TRACE("%s\n", debugstr_w(file->File));
986 r = MSI_OpenQuery(package->db, &view, L"SELECT * FROM `MsiFileHash` WHERE `File_` = '%s'", file->File);
987 if (r != ERROR_SUCCESS)
988 goto done;
990 r = MSI_ViewExecute(view, NULL);
991 if (r != ERROR_SUCCESS)
992 goto done;
994 r = MSI_ViewFetch(view, &row);
995 if (r != ERROR_SUCCESS)
996 goto done;
998 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
999 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1000 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1001 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1002 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1004 done:
1005 if (view) msiobj_release(&view->hdr);
1006 if (row) msiobj_release(&row->hdr);
1007 return r;
1010 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1012 MSIRECORD *row = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %d",
1013 file->Sequence );
1014 if (!row)
1016 WARN("query failed\n");
1017 return ERROR_FUNCTION_FAILED;
1020 file->disk_id = MSI_RecordGetInteger( row, 1 );
1021 msiobj_release( &row->hdr );
1022 return ERROR_SUCCESS;
1025 static UINT load_file(MSIRECORD *row, LPVOID param)
1027 MSIPACKAGE* package = param;
1028 LPCWSTR component;
1029 MSIFILE *file;
1031 /* fill in the data */
1033 file = msi_alloc_zero( sizeof (MSIFILE) );
1034 if (!file)
1035 return ERROR_NOT_ENOUGH_MEMORY;
1037 file->File = msi_dup_record_field( row, 1 );
1039 component = MSI_RecordGetString( row, 2 );
1040 file->Component = msi_get_loaded_component( package, component );
1042 if (!file->Component)
1044 WARN("Component not found: %s\n", debugstr_w(component));
1045 msi_free(file->File);
1046 msi_free(file);
1047 return ERROR_SUCCESS;
1050 file->FileName = msi_dup_record_field( row, 3 );
1051 msi_reduce_to_long_filename( file->FileName );
1053 file->ShortName = msi_dup_record_field( row, 3 );
1054 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1056 file->FileSize = MSI_RecordGetInteger( row, 4 );
1057 file->Version = msi_dup_record_field( row, 5 );
1058 file->Language = msi_dup_record_field( row, 6 );
1059 file->Attributes = MSI_RecordGetInteger( row, 7 );
1060 file->Sequence = MSI_RecordGetInteger( row, 8 );
1062 file->state = msifs_invalid;
1064 /* if the compressed bits are not set in the file attributes,
1065 * then read the information from the package word count property
1067 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1069 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1071 else if (file->Attributes & (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1073 file->IsCompressed = TRUE;
1075 else if (file->Attributes & msidbFileAttributesNoncompressed)
1077 file->IsCompressed = FALSE;
1079 else file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1081 load_file_hash(package, file);
1082 load_file_disk_id(package, file);
1084 TRACE("File loaded (file %s sequence %u)\n", debugstr_w(file->File), file->Sequence);
1086 list_add_tail( &package->files, &file->entry );
1087 return ERROR_SUCCESS;
1090 static UINT load_all_files(MSIPACKAGE *package)
1092 MSIQUERY *view;
1093 UINT rc;
1095 if (!list_empty(&package->files))
1096 return ERROR_SUCCESS;
1098 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `File` ORDER BY `Sequence`", &view);
1099 if (rc != ERROR_SUCCESS)
1100 return ERROR_SUCCESS;
1102 rc = MSI_IterateRecords(view, NULL, load_file, package);
1103 msiobj_release(&view->hdr);
1104 return rc;
1107 static UINT load_media( MSIRECORD *row, LPVOID param )
1109 MSIPACKAGE *package = param;
1110 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1111 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1113 /* FIXME: load external cabinets and directory sources too */
1114 if (!cabinet || cabinet[0] != '#' || disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
1115 return ERROR_SUCCESS;
1117 return msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1120 static UINT load_all_media( MSIPACKAGE *package )
1122 MSIQUERY *view;
1123 UINT r;
1125 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Media` ORDER BY `DiskId`", &view );
1126 if (r != ERROR_SUCCESS)
1127 return ERROR_SUCCESS;
1129 r = MSI_IterateRecords( view, NULL, load_media, package );
1130 msiobj_release( &view->hdr );
1131 return r;
1134 static UINT load_patch_disk_id( MSIPACKAGE *package, MSIFILEPATCH *patch )
1136 MSIRECORD *rec = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %u",
1137 patch->Sequence );
1138 if (!rec)
1140 WARN("query failed\n");
1141 return ERROR_FUNCTION_FAILED;
1144 patch->disk_id = MSI_RecordGetInteger( rec, 1 );
1145 msiobj_release( &rec->hdr );
1146 return ERROR_SUCCESS;
1149 static UINT load_patch(MSIRECORD *row, LPVOID param)
1151 MSIPACKAGE *package = param;
1152 MSIFILEPATCH *patch;
1153 const WCHAR *file_key;
1155 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1156 if (!patch)
1157 return ERROR_NOT_ENOUGH_MEMORY;
1159 file_key = MSI_RecordGetString( row, 1 );
1160 patch->File = msi_get_loaded_file( package, file_key );
1161 if (!patch->File)
1163 ERR("Failed to find target for patch in File table\n");
1164 msi_free(patch);
1165 return ERROR_FUNCTION_FAILED;
1168 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1169 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1170 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1172 /* FIXME:
1173 * Header field - for patch validation.
1174 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1177 load_patch_disk_id( package, patch );
1179 TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence);
1181 list_add_tail( &package->filepatches, &patch->entry );
1183 return ERROR_SUCCESS;
1186 static UINT load_all_patches(MSIPACKAGE *package)
1188 MSIQUERY *view;
1189 UINT rc;
1191 if (!list_empty(&package->filepatches))
1192 return ERROR_SUCCESS;
1194 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Patch` ORDER BY `Sequence`", &view);
1195 if (rc != ERROR_SUCCESS)
1196 return ERROR_SUCCESS;
1198 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1199 msiobj_release(&view->hdr);
1200 return rc;
1203 static UINT iterate_patched_component( MSIRECORD *row, LPVOID param )
1205 MSIPACKAGE *package = param;
1206 const WCHAR *name;
1207 MSICOMPONENT *c;
1209 name = MSI_RecordGetString( row, 1 );
1210 TRACE( "found patched component: %s\n", wine_dbgstr_w(name) );
1211 c = msi_get_loaded_component( package, name );
1212 if (!c)
1213 return ERROR_SUCCESS;
1215 c->updated = 1;
1216 if (!wcscmp( MSI_RecordGetString( row, 2 ), L"INSERT" ))
1217 c->added = 1;
1218 return ERROR_SUCCESS;
1221 static void mark_patched_components( MSIPACKAGE *package )
1223 static const WCHAR select[] = L"SELECT `Row`, `Column` FROM `_TransformView` WHERE `Table`='Component'";
1224 MSIQUERY *q;
1225 UINT r;
1227 r = MSI_OpenQuery( package->db, &q, select );
1228 if (r != ERROR_SUCCESS)
1229 return;
1231 MSI_IterateRecords( q, NULL, iterate_patched_component, package );
1232 msiobj_release( &q->hdr );
1234 while (1)
1236 r = MSI_OpenQuery( package->db, &q, L"ALTER TABLE `_TransformView` FREE" );
1237 if (r != ERROR_SUCCESS)
1238 return;
1239 r = MSI_ViewExecute( q, NULL );
1240 msiobj_release( &q->hdr );
1241 if (r != ERROR_SUCCESS)
1242 return;
1246 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1248 MSIQUERY *view;
1250 folder->persistent = FALSE;
1251 if (!MSI_OpenQuery( package->db, &view, L"SELECT * FROM `CreateFolder` WHERE `Directory_` = '%s'",
1252 folder->Directory ))
1254 if (!MSI_ViewExecute( view, NULL ))
1256 MSIRECORD *rec;
1257 if (!MSI_ViewFetch( view, &rec ))
1259 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1260 folder->persistent = TRUE;
1261 msiobj_release( &rec->hdr );
1264 msiobj_release( &view->hdr );
1266 return ERROR_SUCCESS;
1269 static UINT load_folder( MSIRECORD *row, LPVOID param )
1271 MSIPACKAGE *package = param;
1272 static WCHAR szEmpty[] = L"";
1273 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1274 MSIFOLDER *folder;
1276 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1277 list_init( &folder->children );
1278 folder->Directory = msi_dup_record_field( row, 1 );
1279 folder->Parent = msi_dup_record_field( row, 2 );
1280 p = msi_dup_record_field(row, 3);
1282 TRACE("%s\n", debugstr_w(folder->Directory));
1284 /* split src and target dir */
1285 tgt_short = p;
1286 src_short = folder_split_path( p, ':' );
1288 /* split the long and short paths */
1289 tgt_long = folder_split_path( tgt_short, '|' );
1290 src_long = folder_split_path( src_short, '|' );
1292 /* check for no-op dirs */
1293 if (tgt_short && !wcscmp( L".", tgt_short ))
1294 tgt_short = szEmpty;
1295 if (src_short && !wcscmp( L".", src_short ))
1296 src_short = szEmpty;
1298 if (!tgt_long)
1299 tgt_long = tgt_short;
1301 if (!src_short) {
1302 src_short = tgt_short;
1303 src_long = tgt_long;
1306 if (!src_long)
1307 src_long = src_short;
1309 /* FIXME: use the target short path too */
1310 folder->TargetDefault = strdupW(tgt_long);
1311 folder->SourceShortPath = strdupW(src_short);
1312 folder->SourceLongPath = strdupW(src_long);
1313 msi_free(p);
1315 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1316 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1317 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1319 load_folder_persistence( package, folder );
1321 list_add_tail( &package->folders, &folder->entry );
1322 return ERROR_SUCCESS;
1325 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1327 FolderList *fl;
1329 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1330 fl->folder = child;
1331 list_add_tail( &parent->children, &fl->entry );
1332 return ERROR_SUCCESS;
1335 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1337 MSIPACKAGE *package = param;
1338 MSIFOLDER *parent, *child;
1340 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1341 return ERROR_FUNCTION_FAILED;
1343 if (!child->Parent) return ERROR_SUCCESS;
1345 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1346 return ERROR_FUNCTION_FAILED;
1348 return add_folder_child( parent, child );
1351 static UINT load_all_folders( MSIPACKAGE *package )
1353 MSIQUERY *view;
1354 UINT r;
1356 if (!list_empty(&package->folders))
1357 return ERROR_SUCCESS;
1359 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Directory`", &view );
1360 if (r != ERROR_SUCCESS)
1361 return r;
1363 r = MSI_IterateRecords( view, NULL, load_folder, package );
1364 if (r != ERROR_SUCCESS)
1366 msiobj_release( &view->hdr );
1367 return r;
1369 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1370 msiobj_release( &view->hdr );
1371 return r;
1374 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1376 msi_set_property( package->db, L"CostingComplete", L"0", -1 );
1377 msi_set_property( package->db, L"ROOTDRIVE", L"C:\\", -1 );
1379 load_all_folders( package );
1380 msi_load_all_components( package );
1381 msi_load_all_features( package );
1382 load_all_files( package );
1383 load_all_patches( package );
1384 mark_patched_components( package );
1385 load_all_media( package );
1387 return ERROR_SUCCESS;
1390 static UINT execute_script( MSIPACKAGE *package, UINT script )
1392 UINT i, rc = ERROR_SUCCESS;
1394 TRACE("executing script %u\n", script);
1396 package->script = script;
1398 if (script == SCRIPT_ROLLBACK)
1400 for (i = package->script_actions_count[script]; i > 0; i--)
1402 rc = ACTION_PerformAction(package, package->script_actions[script][i-1]);
1403 if (rc != ERROR_SUCCESS)
1405 ERR("Execution of script %i halted; action %s returned %u\n",
1406 script, debugstr_w(package->script_actions[script][i-1]), rc);
1407 break;
1411 else
1413 for (i = 0; i < package->script_actions_count[script]; i++)
1415 rc = ACTION_PerformAction(package, package->script_actions[script][i]);
1416 if (rc != ERROR_SUCCESS)
1418 ERR("Execution of script %i halted; action %s returned %u\n",
1419 script, debugstr_w(package->script_actions[script][i]), rc);
1420 break;
1425 package->script = SCRIPT_NONE;
1427 msi_free_action_script(package, script);
1428 return rc;
1431 static UINT ACTION_FileCost(MSIPACKAGE *package)
1433 return ERROR_SUCCESS;
1436 static void get_client_counts( MSIPACKAGE *package )
1438 MSICOMPONENT *comp;
1439 HKEY hkey;
1441 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1443 if (!comp->ComponentId) continue;
1445 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE ) &&
1446 MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ))
1448 comp->num_clients = 0;
1449 continue;
1451 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
1452 NULL, NULL, NULL, NULL );
1453 RegCloseKey( hkey );
1457 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1459 MSICOMPONENT *comp;
1460 UINT r;
1462 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1464 if (!comp->ComponentId) continue;
1466 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1467 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1468 &comp->Installed );
1469 if (r == ERROR_SUCCESS) continue;
1471 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1472 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1473 &comp->Installed );
1474 if (r == ERROR_SUCCESS) continue;
1476 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1477 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1478 &comp->Installed );
1479 if (r == ERROR_SUCCESS) continue;
1481 comp->Installed = INSTALLSTATE_ABSENT;
1485 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1487 MSIFEATURE *feature;
1489 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1491 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1493 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1494 feature->Installed = INSTALLSTATE_ABSENT;
1495 else
1496 feature->Installed = state;
1500 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1502 return (feature->Level > 0 && feature->Level <= level);
1505 static BOOL process_state_property(MSIPACKAGE* package, int level,
1506 LPCWSTR property, INSTALLSTATE state)
1508 LPWSTR override;
1509 MSIFEATURE *feature;
1510 BOOL remove = !wcscmp(property, L"REMOVE");
1511 BOOL reinstall = !wcscmp(property, L"REINSTALL");
1513 override = msi_dup_property( package->db, property );
1514 if (!override)
1515 return FALSE;
1517 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1519 if (feature->Level <= 0)
1520 continue;
1522 if (reinstall)
1523 state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : feature->Installed);
1524 else if (remove)
1525 state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : INSTALLSTATE_ABSENT);
1527 if (!wcsicmp( override, L"ALL" ))
1529 feature->Action = state;
1530 feature->ActionRequest = state;
1532 else
1534 LPWSTR ptr = override;
1535 LPWSTR ptr2 = wcschr(override,',');
1537 while (ptr)
1539 int len = ptr2 - ptr;
1541 if ((ptr2 && lstrlenW(feature->Feature) == len && !wcsncmp(ptr, feature->Feature, len))
1542 || (!ptr2 && !wcscmp(ptr, feature->Feature)))
1544 feature->Action = state;
1545 feature->ActionRequest = state;
1546 break;
1548 if (ptr2)
1550 ptr=ptr2+1;
1551 ptr2 = wcschr(ptr,',');
1553 else
1554 break;
1558 msi_free(override);
1559 return TRUE;
1562 static BOOL process_overrides( MSIPACKAGE *package, int level )
1564 BOOL ret = FALSE;
1566 /* all these activation/deactivation things happen in order and things
1567 * later on the list override things earlier on the list.
1569 * 0 INSTALLLEVEL processing
1570 * 1 ADDLOCAL
1571 * 2 REMOVE
1572 * 3 ADDSOURCE
1573 * 4 ADDDEFAULT
1574 * 5 REINSTALL
1575 * 6 ADVERTISE
1576 * 7 COMPADDLOCAL
1577 * 8 COMPADDSOURCE
1578 * 9 FILEADDLOCAL
1579 * 10 FILEADDSOURCE
1580 * 11 FILEADDDEFAULT
1582 ret |= process_state_property( package, level, L"ADDLOCAL", INSTALLSTATE_LOCAL );
1583 ret |= process_state_property( package, level, L"REMOVE", INSTALLSTATE_ABSENT );
1584 ret |= process_state_property( package, level, L"ADDSOURCE", INSTALLSTATE_SOURCE );
1585 ret |= process_state_property( package, level, L"REINSTALL", INSTALLSTATE_UNKNOWN );
1586 ret |= process_state_property( package, level, L"ADVERTISE", INSTALLSTATE_ADVERTISED );
1588 if (ret)
1589 msi_set_property( package->db, L"Preselected", L"1", -1 );
1591 return ret;
1594 static void disable_children( MSIFEATURE *feature, int level )
1596 FeatureList *fl;
1598 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1600 if (!is_feature_selected( feature, level ))
1602 TRACE("child %s (level %d request %d) follows disabled parent %s (level %d request %d)\n",
1603 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1604 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1606 fl->feature->Level = feature->Level;
1607 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1608 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1610 disable_children( fl->feature, level );
1614 static void follow_parent( MSIFEATURE *feature )
1616 FeatureList *fl;
1618 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1620 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1622 TRACE("child %s (level %d request %d) follows parent %s (level %d request %d)\n",
1623 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1624 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1626 fl->feature->Action = feature->Action;
1627 fl->feature->ActionRequest = feature->ActionRequest;
1629 follow_parent( fl->feature );
1633 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1635 int level;
1636 MSICOMPONENT* component;
1637 MSIFEATURE *feature;
1639 TRACE("Checking Install Level\n");
1641 level = msi_get_property_int(package->db, L"INSTALLLEVEL", 1);
1643 if (msi_get_property_int( package->db, L"Preselected", 0 ))
1645 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1647 if (!is_feature_selected( feature, level )) continue;
1649 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1651 if (feature->Installed == INSTALLSTATE_ABSENT)
1653 feature->Action = INSTALLSTATE_UNKNOWN;
1654 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1656 else
1658 feature->Action = feature->Installed;
1659 feature->ActionRequest = feature->Installed;
1664 else if (!msi_get_property_int( package->db, L"Installed", 0 ))
1666 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1668 if (!is_feature_selected( feature, level )) continue;
1670 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1672 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1674 feature->Action = INSTALLSTATE_SOURCE;
1675 feature->ActionRequest = INSTALLSTATE_SOURCE;
1677 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1679 feature->Action = INSTALLSTATE_ADVERTISED;
1680 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1682 else
1684 feature->Action = INSTALLSTATE_LOCAL;
1685 feature->ActionRequest = INSTALLSTATE_LOCAL;
1690 else
1692 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1694 ComponentList *cl;
1695 MSIFEATURE *cur;
1697 if (!is_feature_selected( feature, level )) continue;
1698 if (feature->ActionRequest != INSTALLSTATE_UNKNOWN) continue;
1700 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1702 if (!cl->component->updated && !cl->component->added)
1703 continue;
1705 cur = feature;
1706 while (cur)
1708 if (cur->ActionRequest != INSTALLSTATE_UNKNOWN)
1709 break;
1711 if (cur->Installed != INSTALLSTATE_ABSENT)
1713 cur->Action = cur->Installed;
1714 cur->ActionRequest = cur->Installed;
1716 else if (!cl->component->added)
1718 break;
1720 else if (cur->Attributes & msidbFeatureAttributesFavorSource)
1722 cur->Action = INSTALLSTATE_SOURCE;
1723 cur->ActionRequest = INSTALLSTATE_SOURCE;
1725 else if (cur->Attributes & msidbFeatureAttributesFavorAdvertise)
1727 cur->Action = INSTALLSTATE_ADVERTISED;
1728 cur->ActionRequest = INSTALLSTATE_ADVERTISED;
1730 else
1732 cur->Action = INSTALLSTATE_LOCAL;
1733 cur->ActionRequest = INSTALLSTATE_LOCAL;
1736 if (!cur->Feature_Parent)
1737 break;
1738 cur = msi_get_loaded_feature(package, cur->Feature_Parent);
1744 /* disable child features of unselected parent or follow parent */
1745 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1747 if (feature->Feature_Parent) continue;
1748 disable_children( feature, level );
1749 follow_parent( feature );
1752 /* now we want to set component state based based on feature state */
1753 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1755 ComponentList *cl;
1757 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1758 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1759 feature->ActionRequest, feature->Action);
1761 /* features with components that have compressed files are made local */
1762 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1764 if (cl->component->ForceLocalState &&
1765 feature->ActionRequest == INSTALLSTATE_SOURCE)
1767 feature->Action = INSTALLSTATE_LOCAL;
1768 feature->ActionRequest = INSTALLSTATE_LOCAL;
1769 break;
1773 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1775 component = cl->component;
1777 switch (feature->ActionRequest)
1779 case INSTALLSTATE_ABSENT:
1780 component->anyAbsent = 1;
1781 break;
1782 case INSTALLSTATE_ADVERTISED:
1783 component->hasAdvertisedFeature = 1;
1784 break;
1785 case INSTALLSTATE_SOURCE:
1786 component->hasSourceFeature = 1;
1787 break;
1788 case INSTALLSTATE_LOCAL:
1789 component->hasLocalFeature = 1;
1790 break;
1791 case INSTALLSTATE_DEFAULT:
1792 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1793 component->hasAdvertisedFeature = 1;
1794 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1795 component->hasSourceFeature = 1;
1796 else
1797 component->hasLocalFeature = 1;
1798 break;
1799 case INSTALLSTATE_UNKNOWN:
1800 if (feature->Installed == INSTALLSTATE_ADVERTISED)
1801 component->hasAdvertisedFeature = 1;
1802 if (feature->Installed == INSTALLSTATE_SOURCE)
1803 component->hasSourceFeature = 1;
1804 if (feature->Installed == INSTALLSTATE_LOCAL)
1805 component->hasLocalFeature = 1;
1806 break;
1807 default:
1808 break;
1813 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1815 /* check if it's local or source */
1816 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1817 (component->hasLocalFeature || component->hasSourceFeature))
1819 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1820 !component->ForceLocalState)
1822 component->Action = INSTALLSTATE_SOURCE;
1823 component->ActionRequest = INSTALLSTATE_SOURCE;
1825 else
1827 component->Action = INSTALLSTATE_LOCAL;
1828 component->ActionRequest = INSTALLSTATE_LOCAL;
1830 continue;
1833 /* if any feature is local, the component must be local too */
1834 if (component->hasLocalFeature)
1836 component->Action = INSTALLSTATE_LOCAL;
1837 component->ActionRequest = INSTALLSTATE_LOCAL;
1838 continue;
1840 if (component->hasSourceFeature)
1842 component->Action = INSTALLSTATE_SOURCE;
1843 component->ActionRequest = INSTALLSTATE_SOURCE;
1844 continue;
1846 if (component->hasAdvertisedFeature)
1848 component->Action = INSTALLSTATE_ADVERTISED;
1849 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1850 continue;
1852 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1853 if (component->anyAbsent && component->ComponentId)
1855 component->Action = INSTALLSTATE_ABSENT;
1856 component->ActionRequest = INSTALLSTATE_ABSENT;
1860 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1862 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1864 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1865 component->Action = INSTALLSTATE_LOCAL;
1866 component->ActionRequest = INSTALLSTATE_LOCAL;
1869 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1870 component->Installed == INSTALLSTATE_SOURCE &&
1871 component->hasSourceFeature)
1873 component->Action = INSTALLSTATE_UNKNOWN;
1874 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1877 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
1878 component->num_clients++;
1879 else if (component->Action == INSTALLSTATE_ABSENT)
1881 component->num_clients--;
1883 if (component->num_clients > 0)
1885 TRACE("multiple clients uses %s - disallowing uninstallation\n", debugstr_w(component->Component));
1886 component->Action = INSTALLSTATE_UNKNOWN;
1890 TRACE("component %s (installed %d request %d action %d)\n",
1891 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1894 return ERROR_SUCCESS;
1897 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1899 MSIPACKAGE *package = param;
1900 LPCWSTR name;
1901 MSIFEATURE *feature;
1903 name = MSI_RecordGetString( row, 1 );
1905 feature = msi_get_loaded_feature( package, name );
1906 if (!feature)
1907 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1908 else
1910 LPCWSTR Condition;
1911 Condition = MSI_RecordGetString(row,3);
1913 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1915 int level = MSI_RecordGetInteger(row,2);
1916 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1917 feature->Level = level;
1920 return ERROR_SUCCESS;
1923 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
1925 DWORD ms, ls;
1927 msi_parse_version_string( version, &ms, &ls );
1929 if (fi->dwFileVersionMS > ms) return 1;
1930 else if (fi->dwFileVersionMS < ms) return -1;
1931 else if (fi->dwFileVersionLS > ls) return 1;
1932 else if (fi->dwFileVersionLS < ls) return -1;
1933 return 0;
1936 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
1938 DWORD ms1, ms2;
1940 msi_parse_version_string( ver1, &ms1, NULL );
1941 msi_parse_version_string( ver2, &ms2, NULL );
1943 if (ms1 > ms2) return 1;
1944 else if (ms1 < ms2) return -1;
1945 return 0;
1948 static WCHAR *create_temp_dir( MSIDATABASE *db )
1950 static UINT id;
1951 WCHAR *ret;
1953 if (!db->tempfolder)
1955 WCHAR tmp[MAX_PATH];
1956 DWORD len = ARRAY_SIZE( tmp );
1958 if (msi_get_property( db, L"TempFolder", tmp, &len ) ||
1959 GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY)
1961 GetTempPathW( MAX_PATH, tmp );
1963 if (!(db->tempfolder = strdupW( tmp ))) return NULL;
1966 if ((ret = msi_alloc( (lstrlenW( db->tempfolder ) + 20) * sizeof(WCHAR) )))
1968 for (;;)
1970 if (!GetTempFileNameW( db->tempfolder, L"msi", ++id, ret ))
1972 msi_free( ret );
1973 return NULL;
1975 if (CreateDirectoryW( ret, NULL )) break;
1979 return ret;
1983 * msi_build_directory_name()
1985 * This function is to save messing round with directory names
1986 * It handles adding backslashes between path segments,
1987 * and can add \ at the end of the directory name if told to.
1989 * It takes a variable number of arguments.
1990 * It always allocates a new string for the result, so make sure
1991 * to free the return value when finished with it.
1993 * The first arg is the number of path segments that follow.
1994 * The arguments following count are a list of path segments.
1995 * A path segment may be NULL.
1997 * Path segments will be added with a \ separating them.
1998 * A \ will not be added after the last segment, however if the
1999 * last segment is NULL, then the last character will be a \
2001 WCHAR * WINAPIV msi_build_directory_name( DWORD count, ... )
2003 DWORD sz = 1, i;
2004 WCHAR *dir;
2005 va_list va;
2007 va_start( va, count );
2008 for (i = 0; i < count; i++)
2010 const WCHAR *str = va_arg( va, const WCHAR * );
2011 if (str) sz += lstrlenW( str ) + 1;
2013 va_end( va );
2015 dir = msi_alloc( sz * sizeof(WCHAR) );
2016 dir[0] = 0;
2018 va_start( va, count );
2019 for (i = 0; i < count; i++)
2021 const WCHAR *str = va_arg( va, const WCHAR * );
2022 if (!str) continue;
2023 lstrcatW( dir, str );
2024 if ( i + 1 != count && dir[0] && dir[lstrlenW( dir ) - 1] != '\\') lstrcatW( dir, L"\\" );
2026 va_end( va );
2027 return dir;
2030 BOOL msi_is_global_assembly( MSICOMPONENT *comp )
2032 return comp->assembly && !comp->assembly->application;
2035 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2037 msi_free( file->TargetPath );
2038 if (msi_is_global_assembly( file->Component ))
2040 MSIASSEMBLY *assembly = file->Component->assembly;
2042 if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db );
2043 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2045 else
2047 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2048 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2051 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2054 static UINT calculate_file_cost( MSIPACKAGE *package )
2056 VS_FIXEDFILEINFO *file_version;
2057 WCHAR *font_version;
2058 MSIFILE *file;
2060 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2062 MSICOMPONENT *comp = file->Component;
2063 DWORD file_size;
2065 if (!comp->Enabled) continue;
2067 if (file->IsCompressed)
2068 comp->ForceLocalState = TRUE;
2070 set_target_path( package, file );
2072 if ((comp->assembly && !comp->assembly->installed) ||
2073 msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES)
2075 comp->Cost += file->FileSize;
2076 continue;
2078 file_size = msi_get_disk_file_size( package, file->TargetPath );
2079 TRACE("%s (size %lu)\n", debugstr_w(file->TargetPath), file_size);
2081 if (file->Version)
2083 if ((file_version = msi_get_disk_file_version( package, file->TargetPath )))
2085 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2087 comp->Cost += file->FileSize - file_size;
2089 msi_free( file_version );
2090 continue;
2092 else if ((font_version = msi_get_font_file_version( package, file->TargetPath )))
2094 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2096 comp->Cost += file->FileSize - file_size;
2098 msi_free( font_version );
2099 continue;
2102 if (file_size != file->FileSize)
2104 comp->Cost += file->FileSize - file_size;
2108 return ERROR_SUCCESS;
2111 WCHAR *msi_normalize_path( const WCHAR *in )
2113 const WCHAR *p = in;
2114 WCHAR *q, *ret;
2115 int n, len = lstrlenW( in ) + 2;
2117 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2119 len = 0;
2120 while (1)
2122 /* copy until the end of the string or a space */
2123 while (*p != ' ' && (*q = *p))
2125 p++, len++;
2126 /* reduce many backslashes to one */
2127 if (*p != '\\' || *q != '\\')
2128 q++;
2131 /* quit at the end of the string */
2132 if (!*p)
2133 break;
2135 /* count the number of spaces */
2136 n = 0;
2137 while (p[n] == ' ')
2138 n++;
2140 /* if it's leading or trailing space, skip it */
2141 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2142 p += n;
2143 else /* copy n spaces */
2144 while (n && (*q++ = *p++)) n--;
2146 while (q - ret > 0 && q[-1] == ' ') q--;
2147 if (q - ret > 0 && q[-1] != '\\')
2149 q[0] = '\\';
2150 q[1] = 0;
2152 return ret;
2155 static WCHAR *get_install_location( MSIPACKAGE *package )
2157 HKEY hkey;
2158 WCHAR *path;
2160 if (!package->ProductCode) return NULL;
2161 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE )) return NULL;
2162 if ((path = msi_reg_get_val_str( hkey, L"InstallLocation" )) && !path[0])
2164 msi_free( path );
2165 path = NULL;
2167 RegCloseKey( hkey );
2168 return path;
2171 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2173 FolderList *fl;
2174 MSIFOLDER *folder, *parent, *child;
2175 WCHAR *path, *normalized_path;
2177 TRACE("resolving %s\n", debugstr_w(name));
2179 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2181 if (!wcscmp( folder->Directory, L"TARGETDIR" )) /* special resolving for target root dir */
2183 if (!(path = get_install_location( package )) &&
2184 (!load_prop || !(path = msi_dup_property( package->db, L"TARGETDIR" ))))
2186 path = msi_dup_property( package->db, L"ROOTDRIVE" );
2189 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2191 if (folder->Parent && wcscmp( folder->Directory, folder->Parent ))
2193 parent = msi_get_loaded_folder( package, folder->Parent );
2194 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2196 else
2197 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2200 normalized_path = msi_normalize_path( path );
2201 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2202 msi_free( path );
2204 msi_free( folder->ResolvedTarget );
2205 folder->ResolvedTarget = normalized_path;
2207 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2209 child = fl->folder;
2210 msi_resolve_target_folder( package, child->Directory, load_prop );
2212 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2215 static ULONGLONG get_volume_space_required( MSIPACKAGE *package )
2217 MSICOMPONENT *comp;
2218 ULONGLONG ret = 0;
2220 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2222 if (comp->Action == INSTALLSTATE_LOCAL) ret += comp->Cost;
2224 return ret;
2227 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2229 MSICOMPONENT *comp;
2230 MSIQUERY *view;
2231 WCHAR *level, *primary_key, *primary_folder;
2232 UINT rc;
2234 TRACE("Building directory properties\n");
2235 msi_resolve_target_folder( package, L"TARGETDIR", TRUE );
2237 TRACE("Evaluating component conditions\n");
2238 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2240 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2242 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2243 comp->Enabled = FALSE;
2245 else
2246 comp->Enabled = TRUE;
2248 get_client_counts( package );
2250 /* read components states from the registry */
2251 ACTION_GetComponentInstallStates(package);
2252 ACTION_GetFeatureInstallStates(package);
2254 if (!process_overrides( package, msi_get_property_int( package->db, L"INSTALLLEVEL", 1 ) ))
2256 TRACE("Evaluating feature conditions\n");
2258 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Condition`", &view );
2259 if (rc == ERROR_SUCCESS)
2261 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2262 msiobj_release( &view->hdr );
2263 if (rc != ERROR_SUCCESS)
2264 return rc;
2268 TRACE("Calculating file cost\n");
2269 calculate_file_cost( package );
2271 msi_set_property( package->db, L"CostingComplete", L"1", -1 );
2272 /* set default run level if not set */
2273 level = msi_dup_property( package->db, L"INSTALLLEVEL" );
2274 if (!level) msi_set_property( package->db, L"INSTALLLEVEL", L"1", -1 );
2275 msi_free(level);
2277 if ((rc = MSI_SetFeatureStates( package ))) return rc;
2279 if ((primary_key = msi_dup_property( package->db, L"PRIMARYFOLDER" )))
2281 if ((primary_folder = msi_dup_property( package->db, primary_key )))
2283 if (((primary_folder[0] >= 'A' && primary_folder[0] <= 'Z') ||
2284 (primary_folder[0] >= 'a' && primary_folder[0] <= 'z')) && primary_folder[1] == ':')
2286 ULARGE_INTEGER free;
2287 ULONGLONG required;
2288 WCHAR buf[21];
2290 primary_folder[2] = 0;
2291 if (GetDiskFreeSpaceExW( primary_folder, &free, NULL, NULL ))
2293 swprintf( buf, ARRAY_SIZE(buf), L"%lu", free.QuadPart / 512 );
2294 msi_set_property( package->db, L"PrimaryVolumeSpaceAvailable", buf, -1 );
2296 required = get_volume_space_required( package );
2297 swprintf( buf, ARRAY_SIZE(buf), L"%lu", required / 512 );
2298 msi_set_property( package->db, L"PrimaryVolumeSpaceRequired", buf, -1 );
2300 swprintf( buf, ARRAY_SIZE(buf), L"%lu", (free.QuadPart - required) / 512 );
2301 msi_set_property( package->db, L"PrimaryVolumeSpaceRemaining", buf, -1 );
2302 msi_set_property( package->db, L"PrimaryVolumePath", primary_folder, 2 );
2304 msi_free( primary_folder );
2306 msi_free( primary_key );
2309 /* FIXME: check volume disk space */
2310 msi_set_property( package->db, L"OutOfDiskSpace", L"0", -1 );
2311 msi_set_property( package->db, L"OutOfNoRbDiskSpace", L"0", -1 );
2313 return ERROR_SUCCESS;
2316 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size )
2318 BYTE *data;
2320 if (!value)
2322 *size = sizeof(WCHAR);
2323 *type = REG_SZ;
2324 if ((data = msi_alloc( *size ))) *(WCHAR *)data = 0;
2325 return data;
2327 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2329 if (value[1]=='x')
2331 LPWSTR ptr;
2332 CHAR byte[5];
2333 LPWSTR deformated = NULL;
2334 int count;
2336 deformat_string(package, &value[2], &deformated);
2338 /* binary value type */
2339 ptr = deformated;
2340 *type = REG_BINARY;
2341 if (lstrlenW(ptr)%2)
2342 *size = (lstrlenW(ptr)/2)+1;
2343 else
2344 *size = lstrlenW(ptr)/2;
2346 data = msi_alloc(*size);
2348 byte[0] = '0';
2349 byte[1] = 'x';
2350 byte[4] = 0;
2351 count = 0;
2352 /* if uneven pad with a zero in front */
2353 if (lstrlenW(ptr)%2)
2355 byte[2]= '0';
2356 byte[3]= *ptr;
2357 ptr++;
2358 data[count] = (BYTE)strtol(byte,NULL,0);
2359 count ++;
2360 TRACE("Uneven byte count\n");
2362 while (*ptr)
2364 byte[2]= *ptr;
2365 ptr++;
2366 byte[3]= *ptr;
2367 ptr++;
2368 data[count] = (BYTE)strtol(byte,NULL,0);
2369 count ++;
2371 msi_free(deformated);
2373 TRACE( "data %lu bytes(%u)\n", *size, count );
2375 else
2377 LPWSTR deformated;
2378 LPWSTR p;
2379 DWORD d = 0;
2380 deformat_string(package, &value[1], &deformated);
2382 *type=REG_DWORD;
2383 *size = sizeof(DWORD);
2384 data = msi_alloc(*size);
2385 p = deformated;
2386 if (*p == '-')
2387 p++;
2388 while (*p)
2390 if ( (*p < '0') || (*p > '9') )
2391 break;
2392 d *= 10;
2393 d += (*p - '0');
2394 p++;
2396 if (deformated[0] == '-')
2397 d = -d;
2398 *(DWORD *)data = d;
2399 TRACE( "DWORD %lu\n", *(DWORD *)data);
2401 msi_free(deformated);
2404 else
2406 const WCHAR *ptr = value;
2408 *type = REG_SZ;
2409 if (value[0] == '#')
2411 ptr++; len--;
2412 if (value[1] == '%')
2414 ptr++; len--;
2415 *type = REG_EXPAND_SZ;
2418 data = (BYTE *)msi_strdupW( ptr, len );
2419 if (len > lstrlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
2420 *size = (len + 1) * sizeof(WCHAR);
2422 return data;
2425 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2427 const WCHAR *ret;
2429 switch (root)
2431 case -1:
2432 if (msi_get_property_int( package->db, L"ALLUSERS", 0 ))
2434 *root_key = HKEY_LOCAL_MACHINE;
2435 ret = L"HKEY_LOCAL_MACHINE\\";
2437 else
2439 *root_key = HKEY_CURRENT_USER;
2440 ret = L"HKEY_CURRENT_USER\\";
2442 break;
2443 case 0:
2444 *root_key = HKEY_CLASSES_ROOT;
2445 ret = L"HKEY_CLASSES_ROOT\\";
2446 break;
2447 case 1:
2448 *root_key = HKEY_CURRENT_USER;
2449 ret = L"HKEY_CURRENT_USER\\";
2450 break;
2451 case 2:
2452 *root_key = HKEY_LOCAL_MACHINE;
2453 ret = L"HKEY_LOCAL_MACHINE\\";
2454 break;
2455 case 3:
2456 *root_key = HKEY_USERS;
2457 ret = L"HKEY_USERS\\";
2458 break;
2459 default:
2460 ERR("Unknown root %i\n", root);
2461 return NULL;
2464 return ret;
2467 static inline REGSAM get_registry_view( const MSICOMPONENT *comp )
2469 REGSAM view = 0;
2470 if (is_wow64 || is_64bit)
2471 view |= (comp->Attributes & msidbComponentAttributes64bit) ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
2472 return view;
2475 static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create, REGSAM access )
2477 WCHAR *subkey, *p, *q;
2478 HKEY hkey, ret = NULL;
2479 LONG res;
2481 access |= get_registry_view( comp );
2483 if (!(subkey = strdupW( path ))) return NULL;
2484 p = subkey;
2485 if ((q = wcschr( p, '\\' ))) *q = 0;
2486 if (create)
2487 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2488 else
2489 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2490 if (res)
2492 TRACE( "failed to open key %s (%ld)\n", debugstr_w(subkey), res );
2493 msi_free( subkey );
2494 return NULL;
2496 if (q && q[1])
2498 ret = open_key( comp, hkey, q + 1, create, access );
2499 RegCloseKey( hkey );
2501 else ret = hkey;
2502 msi_free( subkey );
2503 return ret;
2506 static BOOL is_special_entry( const WCHAR *name )
2508 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2511 static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count )
2513 const WCHAR *p = str;
2514 WCHAR **ret;
2515 int i = 0;
2517 *count = 0;
2518 if (!str) return NULL;
2519 while ((p - str) < len)
2521 p += lstrlenW( p ) + 1;
2522 (*count)++;
2524 if (!(ret = msi_alloc( *count * sizeof(WCHAR *) ))) return NULL;
2525 p = str;
2526 while ((p - str) < len)
2528 if (!(ret[i] = strdupW( p )))
2530 for (; i >= 0; i--) msi_free( ret[i] );
2531 msi_free( ret );
2532 return NULL;
2534 p += lstrlenW( p ) + 1;
2535 i++;
2537 return ret;
2540 static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count,
2541 WCHAR **right, DWORD right_count, DWORD *size )
2543 WCHAR *ret, *p;
2544 unsigned int i;
2546 *size = sizeof(WCHAR);
2547 for (i = 0; i < left_count; i++) *size += (lstrlenW( left[i] ) + 1) * sizeof(WCHAR);
2548 for (i = 0; i < right_count; i++) *size += (lstrlenW( right[i] ) + 1) * sizeof(WCHAR);
2550 if (!(ret = p = msi_alloc( *size ))) return NULL;
2552 for (i = 0; i < left_count; i++)
2554 lstrcpyW( p, left[i] );
2555 p += lstrlenW( p ) + 1;
2557 for (i = 0; i < right_count; i++)
2559 lstrcpyW( p, right[i] );
2560 p += lstrlenW( p ) + 1;
2562 *p = 0;
2563 return ret;
2566 static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
2567 WCHAR **new, DWORD new_count )
2569 DWORD ret = old_count;
2570 unsigned int i, j, k;
2572 for (i = 0; i < new_count; i++)
2574 for (j = 0; j < old_count; j++)
2576 if (old[j] && !wcscmp( new[i], old[j] ))
2578 msi_free( old[j] );
2579 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
2580 old[k] = NULL;
2581 ret--;
2585 return ret;
2588 enum join_op
2590 JOIN_OP_APPEND,
2591 JOIN_OP_PREPEND,
2592 JOIN_OP_REPLACE
2595 static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
2596 WCHAR **new, DWORD new_count, DWORD *size )
2598 switch (op)
2600 case JOIN_OP_APPEND:
2601 old_count = remove_duplicate_values( old, old_count, new, new_count );
2602 return flatten_multi_string_values( old, old_count, new, new_count, size );
2604 case JOIN_OP_PREPEND:
2605 old_count = remove_duplicate_values( old, old_count, new, new_count );
2606 return flatten_multi_string_values( new, new_count, old, old_count, size );
2608 case JOIN_OP_REPLACE:
2609 return flatten_multi_string_values( new, new_count, NULL, 0, size );
2611 default:
2612 ERR("unhandled join op %u\n", op);
2613 return NULL;
2617 static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size,
2618 BYTE *new_value, DWORD new_size, DWORD *size )
2620 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
2621 const WCHAR *new_ptr = NULL, *old_ptr = NULL;
2622 enum join_op op = JOIN_OP_REPLACE;
2623 WCHAR **old = NULL, **new = NULL;
2624 BYTE *ret;
2626 if (new_size / sizeof(WCHAR) - 1 > 1)
2628 new_ptr = (const WCHAR *)new_value;
2629 new_len = new_size / sizeof(WCHAR) - 1;
2631 if (!new_ptr[0] && new_ptr[new_len - 1])
2633 op = JOIN_OP_APPEND;
2634 new_len--;
2635 new_ptr++;
2637 else if (new_ptr[0] && !new_ptr[new_len - 1])
2639 op = JOIN_OP_PREPEND;
2640 new_len--;
2642 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2644 op = JOIN_OP_REPLACE;
2645 new_len -= 2;
2646 new_ptr++;
2648 new = split_multi_string_values( new_ptr, new_len, &new_count );
2650 if (old_size / sizeof(WCHAR) - 1 > 1)
2652 old_ptr = (const WCHAR *)old_value;
2653 old_len = old_size / sizeof(WCHAR) - 1;
2654 old = split_multi_string_values( old_ptr, old_len, &old_count );
2656 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
2657 for (i = 0; i < old_count; i++) msi_free( old[i] );
2658 for (i = 0; i < new_count; i++) msi_free( new[i] );
2659 msi_free( old );
2660 msi_free( new );
2661 return ret;
2664 static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
2666 BYTE *ret;
2667 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
2668 if (!(ret = msi_alloc( *size ))) return NULL;
2669 RegQueryValueExW( hkey, name, NULL, type, ret, size );
2670 return ret;
2673 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2675 MSIPACKAGE *package = param;
2676 BYTE *new_value, *old_value = NULL;
2677 HKEY root_key, hkey;
2678 DWORD type, old_type, new_size, old_size = 0;
2679 LPWSTR deformated, uikey;
2680 const WCHAR *szRoot, *component, *name, *key, *str;
2681 MSICOMPONENT *comp;
2682 MSIRECORD * uirow;
2683 INT root;
2684 BOOL check_first = FALSE;
2685 int len;
2687 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2689 component = MSI_RecordGetString(row, 6);
2690 comp = msi_get_loaded_component(package,component);
2691 if (!comp)
2692 return ERROR_SUCCESS;
2694 comp->Action = msi_get_component_action( package, comp );
2695 if (comp->Action != INSTALLSTATE_LOCAL && comp->Action != INSTALLSTATE_SOURCE)
2697 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2698 return ERROR_SUCCESS;
2701 name = MSI_RecordGetString(row, 4);
2702 if( MSI_RecordIsNull(row,5) && name )
2704 /* null values can have special meanings */
2705 if (name[0]=='-' && name[1] == 0)
2706 return ERROR_SUCCESS;
2707 if ((name[0] == '+' || name[0] == '*') && !name[1])
2708 check_first = TRUE;
2711 root = MSI_RecordGetInteger(row,2);
2712 key = MSI_RecordGetString(row, 3);
2714 szRoot = get_root_key( package, root, &root_key );
2715 if (!szRoot)
2716 return ERROR_SUCCESS;
2718 deformat_string(package, key , &deformated);
2719 uikey = msi_alloc( (lstrlenW(deformated) + lstrlenW(szRoot) + 1) * sizeof(WCHAR) );
2720 lstrcpyW(uikey,szRoot);
2721 lstrcatW(uikey,deformated);
2723 if (!(hkey = open_key( comp, root_key, deformated, TRUE, KEY_QUERY_VALUE | KEY_SET_VALUE )))
2725 ERR("Could not create key %s\n", debugstr_w(deformated));
2726 msi_free(uikey);
2727 msi_free(deformated);
2728 return ERROR_FUNCTION_FAILED;
2730 msi_free( deformated );
2731 str = msi_record_get_string( row, 5, NULL );
2732 len = deformat_string( package, str, &deformated );
2733 new_value = parse_value( package, deformated, len, &type, &new_size );
2735 msi_free( deformated );
2736 deformat_string(package, name, &deformated);
2738 if (!is_special_entry( name ))
2740 old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
2741 if (type == REG_MULTI_SZ)
2743 BYTE *new;
2744 if (old_value && old_type != REG_MULTI_SZ)
2746 msi_free( old_value );
2747 old_value = NULL;
2748 old_size = 0;
2750 new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size );
2751 msi_free( new_value );
2752 new_value = new;
2754 if (!check_first)
2756 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type );
2757 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2759 else if (!old_value)
2761 if (deformated || new_size)
2763 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type );
2764 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2767 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
2769 RegCloseKey(hkey);
2771 uirow = MSI_CreateRecord(3);
2772 MSI_RecordSetStringW(uirow,2,deformated);
2773 MSI_RecordSetStringW(uirow,1,uikey);
2774 if (type == REG_SZ || type == REG_EXPAND_SZ)
2775 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
2776 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
2777 msiobj_release( &uirow->hdr );
2779 msi_free(new_value);
2780 msi_free(old_value);
2781 msi_free(deformated);
2782 msi_free(uikey);
2784 return ERROR_SUCCESS;
2787 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2789 MSIQUERY *view;
2790 UINT rc;
2792 if (package->script == SCRIPT_NONE)
2793 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteRegistryValues");
2795 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Registry`", &view);
2796 if (rc != ERROR_SUCCESS)
2797 return ERROR_SUCCESS;
2799 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2800 msiobj_release(&view->hdr);
2801 return rc;
2804 static int is_key_empty(const MSICOMPONENT *comp, HKEY root, const WCHAR *path)
2806 DWORD subkeys, values;
2807 HKEY key;
2808 LONG res;
2810 key = open_key(comp, root, path, FALSE, KEY_READ);
2811 if (!key) return 0;
2813 res = RegQueryInfoKeyW(key, 0, 0, 0, &subkeys, 0, 0, &values, 0, 0, 0, 0);
2814 RegCloseKey(key);
2816 return !res && !subkeys && !values;
2819 static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2821 LONG res = ERROR_SUCCESS;
2822 REGSAM access = get_registry_view( comp );
2823 WCHAR *subkey, *p;
2824 HKEY hkey;
2826 if (!(subkey = strdupW( path ))) return;
2829 if ((p = wcsrchr( subkey, '\\' )))
2831 *p = 0;
2832 if (!p[1]) continue; /* trailing backslash */
2833 hkey = open_key( comp, root, subkey, FALSE, READ_CONTROL );
2834 if (!hkey) break;
2835 if (!is_key_empty(comp, hkey, p + 1))
2837 RegCloseKey(hkey);
2838 break;
2840 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2841 RegCloseKey( hkey );
2843 else if (is_key_empty(comp, root, subkey))
2844 res = RegDeleteKeyExW( root, subkey, access, 0 );
2845 if (res)
2847 TRACE( "failed to delete key %s (%ld)\n", debugstr_w(subkey), res );
2848 break;
2850 } while (p);
2851 msi_free( subkey );
2854 static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, const WCHAR *value )
2856 LONG res;
2857 HKEY hkey;
2859 if ((hkey = open_key( comp, root, path, FALSE, KEY_SET_VALUE | KEY_QUERY_VALUE )))
2861 if ((res = RegDeleteValueW( hkey, value )))
2862 TRACE( "failed to delete value %s (%ld)\n", debugstr_w(value), res );
2864 RegCloseKey( hkey );
2865 if (is_key_empty(comp, root, path))
2867 TRACE("removing empty key %s\n", debugstr_w(path));
2868 delete_key( comp, root, path );
2873 static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2875 LONG res;
2876 HKEY hkey;
2878 if (!(hkey = open_key( comp, root, path, FALSE, KEY_ALL_ACCESS ))) return;
2879 res = RegDeleteTreeW( hkey, NULL );
2880 if (res) TRACE( "failed to delete subtree of %s (%ld)\n", debugstr_w(path), res );
2881 delete_key( comp, root, path );
2882 RegCloseKey( hkey );
2885 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2887 MSIPACKAGE *package = param;
2888 LPCWSTR component, name, key_str, root_key_str;
2889 LPWSTR deformated_key, deformated_name, ui_key_str;
2890 MSICOMPONENT *comp;
2891 MSIRECORD *uirow;
2892 BOOL delete_key = FALSE;
2893 HKEY hkey_root;
2894 UINT size;
2895 INT root;
2897 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2899 component = MSI_RecordGetString( row, 6 );
2900 comp = msi_get_loaded_component( package, component );
2901 if (!comp)
2902 return ERROR_SUCCESS;
2904 comp->Action = msi_get_component_action( package, comp );
2905 if (comp->Action != INSTALLSTATE_ABSENT)
2907 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2908 return ERROR_SUCCESS;
2911 name = MSI_RecordGetString( row, 4 );
2912 if (MSI_RecordIsNull( row, 5 ) && name )
2914 if (name[0] == '+' && !name[1])
2915 return ERROR_SUCCESS;
2916 if ((name[0] == '-' || name[0] == '*') && !name[1])
2918 delete_key = TRUE;
2919 name = NULL;
2923 root = MSI_RecordGetInteger( row, 2 );
2924 key_str = MSI_RecordGetString( row, 3 );
2926 root_key_str = get_root_key( package, root, &hkey_root );
2927 if (!root_key_str)
2928 return ERROR_SUCCESS;
2930 deformat_string( package, key_str, &deformated_key );
2931 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1;
2932 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2933 lstrcpyW( ui_key_str, root_key_str );
2934 lstrcatW( ui_key_str, deformated_key );
2936 deformat_string( package, name, &deformated_name );
2938 if (delete_key) delete_tree( comp, hkey_root, deformated_key );
2939 else delete_value( comp, hkey_root, deformated_key, deformated_name );
2940 msi_free( deformated_key );
2942 uirow = MSI_CreateRecord( 2 );
2943 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2944 MSI_RecordSetStringW( uirow, 2, deformated_name );
2945 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
2946 msiobj_release( &uirow->hdr );
2948 msi_free( ui_key_str );
2949 msi_free( deformated_name );
2950 return ERROR_SUCCESS;
2953 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2955 MSIPACKAGE *package = param;
2956 LPCWSTR component, name, key_str, root_key_str;
2957 LPWSTR deformated_key, deformated_name, ui_key_str;
2958 MSICOMPONENT *comp;
2959 MSIRECORD *uirow;
2960 BOOL delete_key = FALSE;
2961 HKEY hkey_root;
2962 UINT size;
2963 INT root;
2965 component = MSI_RecordGetString( row, 5 );
2966 comp = msi_get_loaded_component( package, component );
2967 if (!comp)
2968 return ERROR_SUCCESS;
2970 comp->Action = msi_get_component_action( package, comp );
2971 if (comp->Action != INSTALLSTATE_LOCAL)
2973 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2974 return ERROR_SUCCESS;
2977 if ((name = MSI_RecordGetString( row, 4 )))
2979 if (name[0] == '-' && !name[1])
2981 delete_key = TRUE;
2982 name = NULL;
2986 root = MSI_RecordGetInteger( row, 2 );
2987 key_str = MSI_RecordGetString( row, 3 );
2989 root_key_str = get_root_key( package, root, &hkey_root );
2990 if (!root_key_str)
2991 return ERROR_SUCCESS;
2993 deformat_string( package, key_str, &deformated_key );
2994 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1;
2995 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2996 lstrcpyW( ui_key_str, root_key_str );
2997 lstrcatW( ui_key_str, deformated_key );
2999 deformat_string( package, name, &deformated_name );
3001 if (delete_key) delete_tree( comp, hkey_root, deformated_key );
3002 else delete_value( comp, hkey_root, deformated_key, deformated_name );
3003 msi_free( deformated_key );
3005 uirow = MSI_CreateRecord( 2 );
3006 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3007 MSI_RecordSetStringW( uirow, 2, deformated_name );
3008 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
3009 msiobj_release( &uirow->hdr );
3011 msi_free( ui_key_str );
3012 msi_free( deformated_name );
3013 return ERROR_SUCCESS;
3016 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3018 MSIQUERY *view;
3019 UINT rc;
3021 if (package->script == SCRIPT_NONE)
3022 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveRegistryValues");
3024 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view );
3025 if (rc == ERROR_SUCCESS)
3027 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3028 msiobj_release( &view->hdr );
3029 if (rc != ERROR_SUCCESS)
3030 return rc;
3032 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `RemoveRegistry`", &view );
3033 if (rc == ERROR_SUCCESS)
3035 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3036 msiobj_release( &view->hdr );
3037 if (rc != ERROR_SUCCESS)
3038 return rc;
3040 return ERROR_SUCCESS;
3043 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3045 return ERROR_SUCCESS;
3049 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3051 MSICOMPONENT *comp;
3052 DWORD total = 0, count = 0;
3053 MSIQUERY *view;
3054 MSIFEATURE *feature;
3055 MSIFILE *file;
3056 UINT rc;
3058 TRACE("InstallValidate\n");
3060 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view );
3061 if (rc == ERROR_SUCCESS)
3063 rc = MSI_IterateRecords( view, &count, NULL, package );
3064 msiobj_release( &view->hdr );
3065 if (rc != ERROR_SUCCESS)
3066 return rc;
3067 total += count * REG_PROGRESS_VALUE;
3069 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3070 total += COMPONENT_PROGRESS_VALUE;
3072 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3073 total += file->FileSize;
3075 msi_ui_progress( package, 0, total, 0, 0 );
3077 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3079 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3080 debugstr_w(feature->Feature), feature->Installed,
3081 feature->ActionRequest, feature->Action);
3083 return ERROR_SUCCESS;
3086 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3088 MSIPACKAGE* package = param;
3089 const WCHAR *cond, *message;
3090 UINT r;
3092 cond = MSI_RecordGetString(row, 1);
3093 r = MSI_EvaluateConditionW(package, cond);
3094 if (r == MSICONDITION_FALSE)
3096 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3098 WCHAR *deformated;
3099 message = MSI_RecordGetString(row, 2);
3100 deformat_string(package, message, &deformated);
3101 MessageBoxW(NULL, deformated, L"Install Failed", MB_OK);
3102 msi_free(deformated);
3105 return ERROR_INSTALL_FAILURE;
3108 return ERROR_SUCCESS;
3111 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3113 MSIQUERY *view;
3114 UINT rc;
3116 TRACE("Checking launch conditions\n");
3118 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `LaunchCondition`", &view);
3119 if (rc != ERROR_SUCCESS)
3120 return ERROR_SUCCESS;
3122 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3123 msiobj_release(&view->hdr);
3124 return rc;
3127 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3130 if (!cmp->KeyPath)
3131 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3133 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3135 MSIRECORD *row;
3136 UINT root, len;
3137 LPWSTR deformated, buffer, deformated_name;
3138 LPCWSTR key, name;
3140 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Registry` WHERE `Registry` = '%s'", cmp->KeyPath);
3141 if (!row)
3142 return NULL;
3144 root = MSI_RecordGetInteger(row,2);
3145 key = MSI_RecordGetString(row, 3);
3146 name = MSI_RecordGetString(row, 4);
3147 deformat_string(package, key , &deformated);
3148 deformat_string(package, name, &deformated_name);
3150 len = lstrlenW(deformated) + 6;
3151 if (deformated_name)
3152 len+=lstrlenW(deformated_name);
3154 buffer = msi_alloc( len *sizeof(WCHAR));
3156 if (deformated_name)
3157 swprintf(buffer, len, L"%02d:\\%s\\%s", root, deformated, deformated_name);
3158 else
3159 swprintf(buffer, len, L"%02d:\\%s\\", root, deformated);
3161 msi_free(deformated);
3162 msi_free(deformated_name);
3163 msiobj_release(&row->hdr);
3165 return buffer;
3167 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3169 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3170 return NULL;
3172 else
3174 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3176 if (file)
3177 return strdupW( file->TargetPath );
3179 return NULL;
3182 static HKEY open_shared_dlls_key( MSICOMPONENT *comp, BOOL create, REGSAM access )
3184 return open_key( comp, HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs",
3185 create, access );
3188 static UINT get_shared_dlls_count( MSICOMPONENT *comp )
3190 DWORD count, type, sz = sizeof(count);
3191 HKEY hkey = open_shared_dlls_key( comp, FALSE, KEY_READ );
3192 if (RegQueryValueExW( hkey, comp->FullKeypath, NULL, &type, (BYTE *)&count, &sz )) count = 0;
3193 RegCloseKey( hkey );
3194 return count;
3197 static void write_shared_dlls_count( MSICOMPONENT *comp, const WCHAR *path, INT count )
3199 HKEY hkey = open_shared_dlls_key( comp, TRUE, KEY_SET_VALUE );
3200 if (count > 0)
3201 msi_reg_set_val_dword( hkey, path, count );
3202 else
3203 RegDeleteValueW( hkey, path );
3204 RegCloseKey(hkey);
3207 static void refcount_component( MSIPACKAGE *package, MSICOMPONENT *comp )
3209 MSIFEATURE *feature;
3210 INT count = 0;
3211 BOOL write = FALSE;
3213 /* only refcount DLLs */
3214 if (!comp->KeyPath || comp->assembly || comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3215 comp->Attributes & msidbComponentAttributesODBCDataSource)
3216 write = FALSE;
3217 else
3219 count = get_shared_dlls_count( comp );
3220 write = (count > 0);
3221 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3222 write = TRUE;
3225 /* increment counts */
3226 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3228 ComponentList *cl;
3230 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3231 continue;
3233 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3235 if ( cl->component == comp )
3236 count++;
3240 /* decrement counts */
3241 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3243 ComponentList *cl;
3245 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3246 continue;
3248 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3250 if ( cl->component == comp )
3251 count--;
3255 /* ref count all the files in the component */
3256 if (write)
3258 MSIFILE *file;
3260 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3262 if (file->Component == comp)
3263 write_shared_dlls_count( comp, file->TargetPath, count );
3267 /* add a count for permanent */
3268 if (comp->Attributes & msidbComponentAttributesPermanent)
3269 count ++;
3271 comp->RefCount = count;
3273 if (write)
3274 write_shared_dlls_count( comp, comp->FullKeypath, comp->RefCount );
3277 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3279 if (comp->assembly)
3281 DWORD len = lstrlenW( L"<\\" ) + lstrlenW( comp->assembly->display_name );
3282 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3284 if (keypath)
3286 lstrcpyW( keypath, L"<\\" );
3287 lstrcatW( keypath, comp->assembly->display_name );
3289 return keypath;
3291 return resolve_keypath( package, comp );
3294 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3296 WCHAR squashed_pc[SQUASHED_GUID_SIZE], squashed_cc[SQUASHED_GUID_SIZE];
3297 UINT rc;
3298 MSICOMPONENT *comp;
3299 HKEY hkey;
3301 TRACE("\n");
3303 msi_set_sourcedir_props(package, FALSE);
3305 if (package->script == SCRIPT_NONE)
3306 return msi_schedule_action(package, SCRIPT_INSTALL, L"ProcessComponents");
3308 squash_guid( package->ProductCode, squashed_pc );
3310 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3312 MSIRECORD *uirow;
3313 INSTALLSTATE action;
3315 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3316 if (!comp->ComponentId)
3317 continue;
3319 squash_guid( comp->ComponentId, squashed_cc );
3320 msi_free( comp->FullKeypath );
3321 comp->FullKeypath = build_full_keypath( package, comp );
3323 refcount_component( package, comp );
3325 if (package->need_rollback) action = comp->Installed;
3326 else action = comp->ActionRequest;
3328 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3329 debugstr_w(comp->Component), debugstr_w(squashed_cc),
3330 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3332 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3334 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3335 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, L"S-1-5-18", &hkey, TRUE);
3336 else
3337 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3339 if (rc != ERROR_SUCCESS)
3340 continue;
3342 if (comp->Attributes & msidbComponentAttributesPermanent)
3344 msi_reg_set_val_str(hkey, L"00000000000000000000000000000000", comp->FullKeypath);
3346 if (action == INSTALLSTATE_LOCAL)
3347 msi_reg_set_val_str( hkey, squashed_pc, comp->FullKeypath );
3348 else
3350 MSIFILE *file;
3351 MSIRECORD *row;
3352 LPWSTR ptr, ptr2;
3353 WCHAR source[MAX_PATH];
3354 WCHAR base[MAX_PATH];
3355 LPWSTR sourcepath;
3357 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3358 continue;
3360 if (!(row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Media` WHERE `LastSequence` >= %d "
3361 "ORDER BY `DiskId`", file->Sequence)))
3362 return ERROR_FUNCTION_FAILED;
3364 swprintf(source, ARRAY_SIZE(source), L"%02d\\", MSI_RecordGetInteger(row, 1));
3365 ptr2 = wcsrchr(source, '\\') + 1;
3366 msiobj_release(&row->hdr);
3368 lstrcpyW(base, package->PackagePath);
3369 ptr = wcsrchr(base, '\\');
3370 *(ptr + 1) = '\0';
3372 sourcepath = msi_resolve_file_source(package, file);
3373 ptr = sourcepath + lstrlenW(base);
3374 lstrcpyW(ptr2, ptr);
3375 msi_free(sourcepath);
3377 msi_reg_set_val_str( hkey, squashed_pc, source );
3379 RegCloseKey(hkey);
3381 else if (action == INSTALLSTATE_ABSENT)
3383 if (comp->num_clients <= 0)
3385 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3386 rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, L"S-1-5-18" );
3387 else
3388 rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
3390 if (rc != ERROR_SUCCESS) WARN( "failed to delete component key %u\n", rc );
3392 else
3394 LONG res;
3396 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3397 rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE );
3398 else
3399 rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE );
3401 if (rc != ERROR_SUCCESS)
3403 WARN( "failed to open component key %u\n", rc );
3404 continue;
3406 res = RegDeleteValueW( hkey, squashed_pc );
3407 RegCloseKey(hkey);
3408 if (res) WARN( "failed to delete component value %ld\n", res );
3412 /* UI stuff */
3413 uirow = MSI_CreateRecord(3);
3414 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3415 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3416 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3417 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
3418 msiobj_release( &uirow->hdr );
3420 return ERROR_SUCCESS;
3423 typedef struct {
3424 CLSID clsid;
3425 LPWSTR source;
3427 LPWSTR path;
3428 ITypeLib *ptLib;
3429 } typelib_struct;
3431 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3432 LPWSTR lpszName, LONG_PTR lParam)
3434 TLIBATTR *attr;
3435 typelib_struct *tl_struct = (typelib_struct*) lParam;
3436 int sz;
3437 HRESULT res;
3439 if (!IS_INTRESOURCE(lpszName))
3441 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3442 return TRUE;
3445 sz = lstrlenW(tl_struct->source)+4;
3447 if ((INT_PTR)lpszName == 1)
3448 tl_struct->path = strdupW(tl_struct->source);
3449 else
3451 tl_struct->path = msi_alloc(sz * sizeof(WCHAR));
3452 swprintf(tl_struct->path, sz, L"%s\\%d", tl_struct->source, lpszName);
3455 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3456 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3457 if (FAILED(res))
3459 msi_free(tl_struct->path);
3460 tl_struct->path = NULL;
3462 return TRUE;
3465 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3466 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3468 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3469 return FALSE;
3472 msi_free(tl_struct->path);
3473 tl_struct->path = NULL;
3475 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3476 ITypeLib_Release(tl_struct->ptLib);
3478 return TRUE;
3481 static HMODULE msi_load_library( MSIPACKAGE *package, const WCHAR *filename, DWORD flags )
3483 HMODULE module;
3484 msi_disable_fs_redirection( package );
3485 module = LoadLibraryExW( filename, NULL, flags );
3486 msi_revert_fs_redirection( package );
3487 return module;
3490 static HRESULT msi_load_typelib( MSIPACKAGE *package, const WCHAR *filename, REGKIND kind, ITypeLib **lib )
3492 HRESULT hr;
3493 msi_disable_fs_redirection( package );
3494 hr = LoadTypeLibEx( filename, kind, lib );
3495 msi_revert_fs_redirection( package );
3496 return hr;
3499 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3501 MSIPACKAGE* package = param;
3502 LPCWSTR component;
3503 MSICOMPONENT *comp;
3504 MSIFILE *file;
3505 typelib_struct tl_struct;
3506 ITypeLib *tlib;
3507 HMODULE module;
3508 HRESULT hr;
3510 component = MSI_RecordGetString(row,3);
3511 comp = msi_get_loaded_component(package,component);
3512 if (!comp)
3513 return ERROR_SUCCESS;
3515 comp->Action = msi_get_component_action( package, comp );
3516 if (comp->Action != INSTALLSTATE_LOCAL)
3518 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3519 return ERROR_SUCCESS;
3522 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3524 TRACE("component has no key path\n");
3525 return ERROR_SUCCESS;
3527 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3529 module = msi_load_library( package, file->TargetPath, LOAD_LIBRARY_AS_DATAFILE );
3530 if (module)
3532 LPCWSTR guid;
3533 guid = MSI_RecordGetString(row,1);
3534 CLSIDFromString( guid, &tl_struct.clsid);
3535 tl_struct.source = strdupW( file->TargetPath );
3536 tl_struct.path = NULL;
3538 EnumResourceNamesW(module, L"TYPELIB", Typelib_EnumResNameProc,
3539 (LONG_PTR)&tl_struct);
3541 if (tl_struct.path)
3543 LPCWSTR helpid, help_path = NULL;
3544 HRESULT res;
3546 helpid = MSI_RecordGetString(row,6);
3548 if (helpid) help_path = msi_get_target_folder( package, helpid );
3549 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3551 if (FAILED(res))
3552 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3553 else
3554 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3556 ITypeLib_Release(tl_struct.ptLib);
3557 msi_free(tl_struct.path);
3559 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3561 FreeLibrary(module);
3562 msi_free(tl_struct.source);
3564 else
3566 hr = msi_load_typelib( package, file->TargetPath, REGKIND_REGISTER, &tlib );
3567 if (FAILED(hr))
3569 ERR( "failed to load type library: %#lx\n", hr );
3570 return ERROR_INSTALL_FAILURE;
3573 ITypeLib_Release(tlib);
3576 return ERROR_SUCCESS;
3579 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3581 MSIQUERY *view;
3582 UINT rc;
3584 if (package->script == SCRIPT_NONE)
3585 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterTypeLibraries");
3587 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `TypeLib`", &view);
3588 if (rc != ERROR_SUCCESS)
3589 return ERROR_SUCCESS;
3591 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3592 msiobj_release(&view->hdr);
3593 return rc;
3596 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3598 MSIPACKAGE *package = param;
3599 LPCWSTR component, guid;
3600 MSICOMPONENT *comp;
3601 GUID libid;
3602 UINT version;
3603 LCID language;
3604 SYSKIND syskind;
3605 HRESULT hr;
3607 component = MSI_RecordGetString( row, 3 );
3608 comp = msi_get_loaded_component( package, component );
3609 if (!comp)
3610 return ERROR_SUCCESS;
3612 comp->Action = msi_get_component_action( package, comp );
3613 if (comp->Action != INSTALLSTATE_ABSENT)
3615 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3616 return ERROR_SUCCESS;
3618 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3620 guid = MSI_RecordGetString( row, 1 );
3621 CLSIDFromString( guid, &libid );
3622 version = MSI_RecordGetInteger( row, 4 );
3623 language = MSI_RecordGetInteger( row, 2 );
3625 #ifdef _WIN64
3626 syskind = SYS_WIN64;
3627 #else
3628 syskind = SYS_WIN32;
3629 #endif
3631 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3632 if (FAILED(hr))
3634 WARN( "failed to unregister typelib: %#lx\n", hr );
3637 return ERROR_SUCCESS;
3640 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3642 MSIQUERY *view;
3643 UINT rc;
3645 if (package->script == SCRIPT_NONE)
3646 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnregisterTypeLibraries");
3648 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `TypeLib`", &view );
3649 if (rc != ERROR_SUCCESS)
3650 return ERROR_SUCCESS;
3652 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3653 msiobj_release( &view->hdr );
3654 return rc;
3657 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3659 LPCWSTR directory, extension, link_folder;
3660 LPWSTR link_file, filename;
3662 directory = MSI_RecordGetString( row, 2 );
3663 link_folder = msi_get_target_folder( package, directory );
3664 if (!link_folder)
3666 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3667 return NULL;
3669 /* may be needed because of a bug somewhere else */
3670 msi_create_full_path( package, link_folder );
3672 filename = msi_dup_record_field( row, 3 );
3673 msi_reduce_to_long_filename( filename );
3675 extension = wcsrchr( filename, '.' );
3676 if (!extension || wcsicmp( extension, L".lnk" ))
3678 int len = lstrlenW( filename );
3679 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(L".lnk") );
3680 memcpy( filename + len, L".lnk", sizeof(L".lnk") );
3682 link_file = msi_build_directory_name( 2, link_folder, filename );
3683 msi_free( filename );
3685 return link_file;
3688 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3690 WCHAR *folder, *dest, *path;
3692 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3693 folder = msi_dup_property( package->db, L"WindowsFolder" );
3694 else
3696 WCHAR *appdata = msi_dup_property( package->db, L"AppDataFolder" );
3697 folder = msi_build_directory_name( 2, appdata, L"Microsoft\\" );
3698 msi_free( appdata );
3700 dest = msi_build_directory_name( 3, folder, L"Installer\\", package->ProductCode );
3701 msi_create_full_path( package, dest );
3702 path = msi_build_directory_name( 2, dest, icon_name );
3703 msi_free( folder );
3704 msi_free( dest );
3705 return path;
3708 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3710 MSIPACKAGE *package = param;
3711 LPWSTR link_file, deformated, path;
3712 LPCWSTR component, target;
3713 MSICOMPONENT *comp;
3714 IShellLinkW *sl = NULL;
3715 IPersistFile *pf = NULL;
3716 HRESULT res;
3718 component = MSI_RecordGetString(row, 4);
3719 comp = msi_get_loaded_component(package, component);
3720 if (!comp)
3721 return ERROR_SUCCESS;
3723 comp->Action = msi_get_component_action( package, comp );
3724 if (comp->Action != INSTALLSTATE_LOCAL)
3726 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3727 return ERROR_SUCCESS;
3729 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3731 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3732 &IID_IShellLinkW, (LPVOID *) &sl );
3734 if (FAILED( res ))
3736 ERR("CLSID_ShellLink not available\n");
3737 goto err;
3740 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3741 if (FAILED( res ))
3743 ERR("QueryInterface(IID_IPersistFile) failed\n");
3744 goto err;
3747 target = MSI_RecordGetString(row, 5);
3748 if (wcschr(target, '['))
3750 deformat_string( package, target, &path );
3751 TRACE("target path is %s\n", debugstr_w(path));
3752 IShellLinkW_SetPath( sl, path );
3753 msi_free( path );
3755 else
3757 FIXME("poorly handled shortcut format, advertised shortcut\n");
3758 path = resolve_keypath( package, comp );
3759 IShellLinkW_SetPath( sl, path );
3760 msi_free( path );
3763 if (!MSI_RecordIsNull(row,6))
3765 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3766 deformat_string(package, arguments, &deformated);
3767 IShellLinkW_SetArguments(sl,deformated);
3768 msi_free(deformated);
3771 if (!MSI_RecordIsNull(row,7))
3773 LPCWSTR description = MSI_RecordGetString(row, 7);
3774 IShellLinkW_SetDescription(sl, description);
3777 if (!MSI_RecordIsNull(row,8))
3778 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3780 if (!MSI_RecordIsNull(row,9))
3782 INT index;
3783 LPCWSTR icon = MSI_RecordGetString(row, 9);
3785 path = msi_build_icon_path(package, icon);
3786 index = MSI_RecordGetInteger(row,10);
3788 /* no value means 0 */
3789 if (index == MSI_NULL_INTEGER)
3790 index = 0;
3792 IShellLinkW_SetIconLocation(sl, path, index);
3793 msi_free(path);
3796 if (!MSI_RecordIsNull(row,11))
3797 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3799 if (!MSI_RecordIsNull(row,12))
3801 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3802 full_path = msi_get_target_folder( package, wkdir );
3803 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3806 link_file = get_link_file(package, row);
3807 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3809 msi_disable_fs_redirection( package );
3810 IPersistFile_Save(pf, link_file, FALSE);
3811 msi_revert_fs_redirection( package );
3813 msi_free(link_file);
3815 err:
3816 if (pf)
3817 IPersistFile_Release( pf );
3818 if (sl)
3819 IShellLinkW_Release( sl );
3821 return ERROR_SUCCESS;
3824 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3826 MSIQUERY *view;
3827 HRESULT res;
3828 UINT rc;
3830 if (package->script == SCRIPT_NONE)
3831 return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateShortcuts");
3833 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Shortcut`", &view);
3834 if (rc != ERROR_SUCCESS)
3835 return ERROR_SUCCESS;
3837 res = CoInitialize( NULL );
3839 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3840 msiobj_release(&view->hdr);
3842 if (SUCCEEDED(res)) CoUninitialize();
3843 return rc;
3846 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3848 MSIPACKAGE *package = param;
3849 LPWSTR link_file;
3850 LPCWSTR component;
3851 MSICOMPONENT *comp;
3853 component = MSI_RecordGetString( row, 4 );
3854 comp = msi_get_loaded_component( package, component );
3855 if (!comp)
3856 return ERROR_SUCCESS;
3858 comp->Action = msi_get_component_action( package, comp );
3859 if (comp->Action != INSTALLSTATE_ABSENT)
3861 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3862 return ERROR_SUCCESS;
3864 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3866 link_file = get_link_file( package, row );
3867 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3868 if (!msi_delete_file( package, link_file )) WARN( "failed to remove shortcut file %lu\n", GetLastError() );
3869 msi_free( link_file );
3871 return ERROR_SUCCESS;
3874 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3876 MSIQUERY *view;
3877 UINT rc;
3879 if (package->script == SCRIPT_NONE)
3880 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveShortcuts");
3882 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Shortcut`", &view );
3883 if (rc != ERROR_SUCCESS)
3884 return ERROR_SUCCESS;
3886 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3887 msiobj_release( &view->hdr );
3888 return rc;
3891 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3893 MSIPACKAGE *package = param;
3894 HANDLE handle;
3895 WCHAR *icon_path;
3896 const WCHAR *filename;
3897 char buffer[1024];
3898 DWORD sz;
3899 UINT rc;
3901 filename = MSI_RecordGetString( row, 1 );
3902 if (!filename)
3904 ERR("Unable to get filename\n");
3905 return ERROR_SUCCESS;
3908 icon_path = msi_build_icon_path( package, filename );
3910 TRACE("Creating icon file at %s\n", debugstr_w(icon_path));
3912 handle = msi_create_file( package, icon_path, GENERIC_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL );
3913 if (handle == INVALID_HANDLE_VALUE)
3915 ERR("Unable to create file %s\n", debugstr_w(icon_path));
3916 msi_free( icon_path );
3917 return ERROR_SUCCESS;
3922 DWORD count;
3923 sz = 1024;
3924 rc = MSI_RecordReadStream( row, 2, buffer, &sz );
3925 if (rc != ERROR_SUCCESS)
3927 ERR("Failed to get stream\n");
3928 msi_delete_file( package, icon_path );
3929 break;
3931 WriteFile( handle, buffer, sz, &count, NULL );
3932 } while (sz == 1024);
3934 msi_free( icon_path );
3935 CloseHandle( handle );
3937 return ERROR_SUCCESS;
3940 static UINT msi_publish_icons(MSIPACKAGE *package)
3942 MSIQUERY *view;
3943 UINT r;
3945 r = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Icon`", &view);
3946 if (r == ERROR_SUCCESS)
3948 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3949 msiobj_release(&view->hdr);
3950 if (r != ERROR_SUCCESS)
3951 return r;
3953 return ERROR_SUCCESS;
3956 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3958 UINT r;
3959 HKEY source;
3960 LPWSTR buffer;
3961 MSIMEDIADISK *disk;
3962 MSISOURCELISTINFO *info;
3964 r = RegCreateKeyW(hkey, L"SourceList", &source);
3965 if (r != ERROR_SUCCESS)
3966 return r;
3968 RegCloseKey(source);
3970 buffer = wcsrchr(package->PackagePath, '\\') + 1;
3971 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3972 package->Context, MSICODE_PRODUCT,
3973 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3974 if (r != ERROR_SUCCESS)
3975 return r;
3977 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3978 package->Context, MSICODE_PRODUCT,
3979 INSTALLPROPERTY_MEDIAPACKAGEPATHW, L"");
3980 if (r != ERROR_SUCCESS)
3981 return r;
3983 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3984 package->Context, MSICODE_PRODUCT,
3985 INSTALLPROPERTY_DISKPROMPTW, L"");
3986 if (r != ERROR_SUCCESS)
3987 return r;
3989 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3991 if (!wcscmp( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3992 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3993 info->options, info->value);
3994 else
3995 MsiSourceListSetInfoW(package->ProductCode, NULL,
3996 info->context, info->options,
3997 info->property, info->value);
4000 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4002 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4003 disk->context, disk->options,
4004 disk->disk_id, disk->volume_label, disk->disk_prompt);
4007 return ERROR_SUCCESS;
4010 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4012 WCHAR *buffer, *ptr, *guids, packcode[SQUASHED_GUID_SIZE];
4013 DWORD langid;
4015 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4016 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4017 msi_free(buffer);
4019 langid = msi_get_property_int(package->db, L"ProductLanguage", 0);
4020 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4022 /* FIXME */
4023 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4025 buffer = msi_dup_property(package->db, L"ARPPRODUCTICON");
4026 if (buffer)
4028 LPWSTR path = msi_build_icon_path(package, buffer);
4029 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4030 msi_free(path);
4031 msi_free(buffer);
4034 buffer = msi_dup_property(package->db, L"ProductVersion");
4035 if (buffer)
4037 DWORD verdword = msi_version_str_to_dword(buffer);
4038 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4039 msi_free(buffer);
4042 msi_reg_set_val_dword(hkey, L"Assignment", 0);
4043 msi_reg_set_val_dword(hkey, L"AdvertiseFlags", 0x184);
4044 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4045 msi_reg_set_val_multi_str(hkey, L"Clients", L":\0");
4047 if (!(guids = msi_get_package_code(package->db))) return ERROR_OUTOFMEMORY;
4048 if ((ptr = wcschr(guids, ';'))) *ptr = 0;
4049 squash_guid(guids, packcode);
4050 msi_free( guids);
4051 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4053 return ERROR_SUCCESS;
4056 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4058 UINT r;
4059 HKEY hkey;
4060 WCHAR *upgrade, squashed_pc[SQUASHED_GUID_SIZE];
4062 upgrade = msi_dup_property(package->db, L"UpgradeCode");
4063 if (!upgrade)
4064 return ERROR_SUCCESS;
4066 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4067 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4068 else
4069 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4071 if (r != ERROR_SUCCESS)
4073 WARN("failed to open upgrade code key\n");
4074 msi_free(upgrade);
4075 return ERROR_SUCCESS;
4077 squash_guid(package->ProductCode, squashed_pc);
4078 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4079 RegCloseKey(hkey);
4080 msi_free(upgrade);
4081 return ERROR_SUCCESS;
4084 static BOOL msi_check_publish(MSIPACKAGE *package)
4086 MSIFEATURE *feature;
4088 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4090 feature->Action = msi_get_feature_action( package, feature );
4091 if (feature->Action == INSTALLSTATE_LOCAL || feature->Action == INSTALLSTATE_SOURCE)
4092 return TRUE;
4095 return FALSE;
4098 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4100 MSIFEATURE *feature;
4102 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4104 feature->Action = msi_get_feature_action( package, feature );
4105 if (feature->Action != INSTALLSTATE_ABSENT)
4106 return FALSE;
4109 return TRUE;
4112 static UINT msi_publish_patches( MSIPACKAGE *package )
4114 WCHAR patch_squashed[GUID_SIZE];
4115 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4116 LONG res;
4117 MSIPATCHINFO *patch;
4118 UINT r;
4119 WCHAR *p, *all_patches = NULL;
4120 DWORD len = 0;
4122 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4123 if (r != ERROR_SUCCESS)
4124 return ERROR_FUNCTION_FAILED;
4126 res = RegCreateKeyExW( product_key, L"Patches", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4127 if (res != ERROR_SUCCESS)
4129 r = ERROR_FUNCTION_FAILED;
4130 goto done;
4133 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4134 if (r != ERROR_SUCCESS)
4135 goto done;
4137 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4139 squash_guid( patch->patchcode, patch_squashed );
4140 len += lstrlenW( patch_squashed ) + 1;
4143 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4144 if (!all_patches)
4145 goto done;
4147 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4149 HKEY patch_key;
4151 squash_guid( patch->patchcode, p );
4152 p += lstrlenW( p ) + 1;
4154 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4155 (const BYTE *)patch->transforms,
4156 (lstrlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4157 if (res != ERROR_SUCCESS)
4158 goto done;
4160 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4161 if (r != ERROR_SUCCESS)
4162 goto done;
4164 res = RegSetValueExW( patch_key, L"LocalPackage", 0, REG_SZ, (const BYTE *)patch->localfile,
4165 (lstrlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4166 RegCloseKey( patch_key );
4167 if (res != ERROR_SUCCESS)
4168 goto done;
4170 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4172 res = GetLastError();
4173 ERR( "unable to copy patch package %lu\n", res );
4174 goto done;
4176 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4177 if (res != ERROR_SUCCESS)
4178 goto done;
4180 res = RegSetValueExW( patch_key, L"State", 0, REG_DWORD, (const BYTE *)&patch->state,
4181 sizeof(patch->state) );
4182 if (res != ERROR_SUCCESS)
4184 RegCloseKey( patch_key );
4185 goto done;
4188 res = RegSetValueExW( patch_key, L"Uninstallable", 0, REG_DWORD, (const BYTE *)&patch->uninstallable,
4189 sizeof(patch->uninstallable) );
4190 RegCloseKey( patch_key );
4191 if (res != ERROR_SUCCESS)
4192 goto done;
4195 all_patches[len] = 0;
4196 res = RegSetValueExW( patches_key, L"Patches", 0, REG_MULTI_SZ,
4197 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4198 if (res != ERROR_SUCCESS)
4199 goto done;
4201 res = RegSetValueExW( product_patches_key, L"AllPatches", 0, REG_MULTI_SZ,
4202 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4203 if (res != ERROR_SUCCESS)
4204 r = ERROR_FUNCTION_FAILED;
4206 done:
4207 RegCloseKey( product_patches_key );
4208 RegCloseKey( patches_key );
4209 RegCloseKey( product_key );
4210 msi_free( all_patches );
4211 return r;
4214 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4216 UINT rc;
4217 HKEY hukey = NULL, hudkey = NULL;
4218 MSIRECORD *uirow;
4219 BOOL republish = FALSE;
4221 if (package->script == SCRIPT_NONE)
4222 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishProduct");
4224 if (!list_empty(&package->patches))
4226 rc = msi_publish_patches(package);
4227 if (rc != ERROR_SUCCESS)
4228 goto end;
4231 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4232 &hukey, FALSE);
4233 if (rc == ERROR_SUCCESS)
4235 WCHAR *package_code;
4237 package_code = msi_reg_get_val_str(hukey, INSTALLPROPERTY_PACKAGECODEW);
4238 if (package_code)
4240 WCHAR *guid;
4242 guid = msi_get_package_code(package->db);
4243 if (guid)
4245 WCHAR packed[SQUASHED_GUID_SIZE];
4247 squash_guid(guid, packed);
4248 msi_free(guid);
4249 if (!wcscmp(packed, package_code))
4251 TRACE("re-publishing product - new package\n");
4252 republish = TRUE;
4255 msi_free(package_code);
4259 /* FIXME: also need to publish if the product is in advertise mode */
4260 if (!republish && !msi_check_publish(package))
4262 if (hukey)
4263 RegCloseKey(hukey);
4264 return ERROR_SUCCESS;
4267 if (!hukey)
4269 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4270 &hukey, TRUE);
4271 if (rc != ERROR_SUCCESS)
4272 goto end;
4275 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4276 NULL, &hudkey, TRUE);
4277 if (rc != ERROR_SUCCESS)
4278 goto end;
4280 rc = msi_publish_upgrade_code(package);
4281 if (rc != ERROR_SUCCESS)
4282 goto end;
4284 rc = msi_publish_product_properties(package, hukey);
4285 if (rc != ERROR_SUCCESS)
4286 goto end;
4288 rc = msi_publish_sourcelist(package, hukey);
4289 if (rc != ERROR_SUCCESS)
4290 goto end;
4292 rc = msi_publish_icons(package);
4294 end:
4295 uirow = MSI_CreateRecord( 1 );
4296 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4297 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4298 msiobj_release( &uirow->hdr );
4300 RegCloseKey(hukey);
4301 RegCloseKey(hudkey);
4302 return rc;
4305 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4307 WCHAR *filename, *ptr, *folder, *ret;
4308 const WCHAR *dirprop;
4310 filename = msi_dup_record_field( row, 2 );
4311 if (filename && (ptr = wcschr( filename, '|' )))
4312 ptr++;
4313 else
4314 ptr = filename;
4316 dirprop = MSI_RecordGetString( row, 3 );
4317 if (dirprop)
4319 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4320 if (!folder) folder = msi_dup_property( package->db, dirprop );
4322 else
4323 folder = msi_dup_property( package->db, L"WindowsFolder" );
4325 if (!folder)
4327 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4328 msi_free( filename );
4329 return NULL;
4332 ret = msi_build_directory_name( 2, folder, ptr );
4334 msi_free( filename );
4335 msi_free( folder );
4336 return ret;
4339 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4341 MSIPACKAGE *package = param;
4342 LPCWSTR component, section, key, value, identifier;
4343 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4344 MSIRECORD * uirow;
4345 INT action;
4346 MSICOMPONENT *comp;
4348 component = MSI_RecordGetString(row, 8);
4349 comp = msi_get_loaded_component(package,component);
4350 if (!comp)
4351 return ERROR_SUCCESS;
4353 comp->Action = msi_get_component_action( package, comp );
4354 if (comp->Action != INSTALLSTATE_LOCAL)
4356 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4357 return ERROR_SUCCESS;
4360 identifier = MSI_RecordGetString(row,1);
4361 section = MSI_RecordGetString(row,4);
4362 key = MSI_RecordGetString(row,5);
4363 value = MSI_RecordGetString(row,6);
4364 action = MSI_RecordGetInteger(row,7);
4366 deformat_string(package,section,&deformated_section);
4367 deformat_string(package,key,&deformated_key);
4368 deformat_string(package,value,&deformated_value);
4370 fullname = get_ini_file_name(package, row);
4372 if (action == 0)
4374 TRACE("Adding value %s to section %s in %s\n",
4375 debugstr_w(deformated_key), debugstr_w(deformated_section),
4376 debugstr_w(fullname));
4377 WritePrivateProfileStringW(deformated_section, deformated_key,
4378 deformated_value, fullname);
4380 else if (action == 1)
4382 WCHAR returned[10];
4383 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4384 returned, 10, fullname);
4385 if (returned[0] == 0)
4387 TRACE("Adding value %s to section %s in %s\n",
4388 debugstr_w(deformated_key), debugstr_w(deformated_section),
4389 debugstr_w(fullname));
4391 WritePrivateProfileStringW(deformated_section, deformated_key,
4392 deformated_value, fullname);
4395 else if (action == 3)
4396 FIXME("Append to existing section not yet implemented\n");
4398 uirow = MSI_CreateRecord(4);
4399 MSI_RecordSetStringW(uirow,1,identifier);
4400 MSI_RecordSetStringW(uirow,2,deformated_section);
4401 MSI_RecordSetStringW(uirow,3,deformated_key);
4402 MSI_RecordSetStringW(uirow,4,deformated_value);
4403 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4404 msiobj_release( &uirow->hdr );
4406 msi_free(fullname);
4407 msi_free(deformated_key);
4408 msi_free(deformated_value);
4409 msi_free(deformated_section);
4410 return ERROR_SUCCESS;
4413 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4415 MSIQUERY *view;
4416 UINT rc;
4418 if (package->script == SCRIPT_NONE)
4419 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteIniValues");
4421 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `IniFile`", &view);
4422 if (rc != ERROR_SUCCESS)
4423 return ERROR_SUCCESS;
4425 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4426 msiobj_release(&view->hdr);
4427 return rc;
4430 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4432 MSIPACKAGE *package = param;
4433 LPCWSTR component, section, key, value, identifier;
4434 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4435 MSICOMPONENT *comp;
4436 MSIRECORD *uirow;
4437 INT action;
4439 component = MSI_RecordGetString( row, 8 );
4440 comp = msi_get_loaded_component( package, component );
4441 if (!comp)
4442 return ERROR_SUCCESS;
4444 comp->Action = msi_get_component_action( package, comp );
4445 if (comp->Action != INSTALLSTATE_ABSENT)
4447 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4448 return ERROR_SUCCESS;
4451 identifier = MSI_RecordGetString( row, 1 );
4452 section = MSI_RecordGetString( row, 4 );
4453 key = MSI_RecordGetString( row, 5 );
4454 value = MSI_RecordGetString( row, 6 );
4455 action = MSI_RecordGetInteger( row, 7 );
4457 deformat_string( package, section, &deformated_section );
4458 deformat_string( package, key, &deformated_key );
4459 deformat_string( package, value, &deformated_value );
4461 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4463 filename = get_ini_file_name( package, row );
4465 TRACE("Removing key %s from section %s in %s\n",
4466 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4468 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4470 WARN( "unable to remove key %lu\n", GetLastError() );
4472 msi_free( filename );
4474 else
4475 FIXME("Unsupported action %d\n", action);
4478 uirow = MSI_CreateRecord( 4 );
4479 MSI_RecordSetStringW( uirow, 1, identifier );
4480 MSI_RecordSetStringW( uirow, 2, deformated_section );
4481 MSI_RecordSetStringW( uirow, 3, deformated_key );
4482 MSI_RecordSetStringW( uirow, 4, deformated_value );
4483 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4484 msiobj_release( &uirow->hdr );
4486 msi_free( deformated_key );
4487 msi_free( deformated_value );
4488 msi_free( deformated_section );
4489 return ERROR_SUCCESS;
4492 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4494 MSIPACKAGE *package = param;
4495 LPCWSTR component, section, key, value, identifier;
4496 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4497 MSICOMPONENT *comp;
4498 MSIRECORD *uirow;
4499 INT action;
4501 component = MSI_RecordGetString( row, 8 );
4502 comp = msi_get_loaded_component( package, component );
4503 if (!comp)
4504 return ERROR_SUCCESS;
4506 comp->Action = msi_get_component_action( package, comp );
4507 if (comp->Action != INSTALLSTATE_LOCAL)
4509 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4510 return ERROR_SUCCESS;
4513 identifier = MSI_RecordGetString( row, 1 );
4514 section = MSI_RecordGetString( row, 4 );
4515 key = MSI_RecordGetString( row, 5 );
4516 value = MSI_RecordGetString( row, 6 );
4517 action = MSI_RecordGetInteger( row, 7 );
4519 deformat_string( package, section, &deformated_section );
4520 deformat_string( package, key, &deformated_key );
4521 deformat_string( package, value, &deformated_value );
4523 if (action == msidbIniFileActionRemoveLine)
4525 filename = get_ini_file_name( package, row );
4527 TRACE("Removing key %s from section %s in %s\n",
4528 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4530 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4532 WARN( "unable to remove key %lu\n", GetLastError() );
4534 msi_free( filename );
4536 else
4537 FIXME("Unsupported action %d\n", action);
4539 uirow = MSI_CreateRecord( 4 );
4540 MSI_RecordSetStringW( uirow, 1, identifier );
4541 MSI_RecordSetStringW( uirow, 2, deformated_section );
4542 MSI_RecordSetStringW( uirow, 3, deformated_key );
4543 MSI_RecordSetStringW( uirow, 4, deformated_value );
4544 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4545 msiobj_release( &uirow->hdr );
4547 msi_free( deformated_key );
4548 msi_free( deformated_value );
4549 msi_free( deformated_section );
4550 return ERROR_SUCCESS;
4553 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4555 MSIQUERY *view;
4556 UINT rc;
4558 if (package->script == SCRIPT_NONE)
4559 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveIniValues");
4561 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `IniFile`", &view );
4562 if (rc == ERROR_SUCCESS)
4564 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4565 msiobj_release( &view->hdr );
4566 if (rc != ERROR_SUCCESS)
4567 return rc;
4569 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `RemoveIniFile`", &view );
4570 if (rc == ERROR_SUCCESS)
4572 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4573 msiobj_release( &view->hdr );
4574 if (rc != ERROR_SUCCESS)
4575 return rc;
4577 return ERROR_SUCCESS;
4580 static void register_dll( const WCHAR *dll, BOOL unregister )
4582 static const WCHAR regW[] = L"regsvr32.exe \"%s\"";
4583 static const WCHAR unregW[] = L"regsvr32.exe /u \"%s\"";
4584 PROCESS_INFORMATION pi;
4585 STARTUPINFOW si;
4586 WCHAR *cmd;
4588 if (!(cmd = msi_alloc( lstrlenW(dll) * sizeof(WCHAR) + sizeof(unregW) ))) return;
4590 if (unregister) swprintf( cmd, lstrlenW(dll) + ARRAY_SIZE(unregW), unregW, dll );
4591 else swprintf( cmd, lstrlenW(dll) + ARRAY_SIZE(unregW), regW, dll );
4593 memset( &si, 0, sizeof(STARTUPINFOW) );
4594 if (CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
4596 CloseHandle( pi.hThread );
4597 msi_dialog_check_messages( pi.hProcess );
4598 CloseHandle( pi.hProcess );
4600 msi_free( cmd );
4603 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4605 MSIPACKAGE *package = param;
4606 LPCWSTR filename;
4607 MSIFILE *file;
4608 MSIRECORD *uirow;
4610 filename = MSI_RecordGetString( row, 1 );
4611 file = msi_get_loaded_file( package, filename );
4612 if (!file)
4614 WARN("unable to find file %s\n", debugstr_w(filename));
4615 return ERROR_SUCCESS;
4617 file->Component->Action = msi_get_component_action( package, file->Component );
4618 if (file->Component->Action != INSTALLSTATE_LOCAL)
4620 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4621 return ERROR_SUCCESS;
4624 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4625 register_dll( file->TargetPath, FALSE );
4627 uirow = MSI_CreateRecord( 2 );
4628 MSI_RecordSetStringW( uirow, 1, file->File );
4629 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4630 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4631 msiobj_release( &uirow->hdr );
4633 return ERROR_SUCCESS;
4636 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4638 MSIQUERY *view;
4639 UINT rc;
4641 if (package->script == SCRIPT_NONE)
4642 return msi_schedule_action(package, SCRIPT_INSTALL, L"SelfRegModules");
4644 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `SelfReg`", &view);
4645 if (rc != ERROR_SUCCESS)
4646 return ERROR_SUCCESS;
4648 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4649 msiobj_release(&view->hdr);
4650 return rc;
4653 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4655 MSIPACKAGE *package = param;
4656 LPCWSTR filename;
4657 MSIFILE *file;
4658 MSIRECORD *uirow;
4660 filename = MSI_RecordGetString( row, 1 );
4661 file = msi_get_loaded_file( package, filename );
4662 if (!file)
4664 WARN("unable to find file %s\n", debugstr_w(filename));
4665 return ERROR_SUCCESS;
4667 file->Component->Action = msi_get_component_action( package, file->Component );
4668 if (file->Component->Action != INSTALLSTATE_ABSENT)
4670 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4671 return ERROR_SUCCESS;
4674 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4675 register_dll( file->TargetPath, TRUE );
4677 uirow = MSI_CreateRecord( 2 );
4678 MSI_RecordSetStringW( uirow, 1, file->File );
4679 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4680 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4681 msiobj_release( &uirow->hdr );
4683 return ERROR_SUCCESS;
4686 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4688 MSIQUERY *view;
4689 UINT rc;
4691 if (package->script == SCRIPT_NONE)
4692 return msi_schedule_action(package, SCRIPT_INSTALL, L"SelfUnregModules");
4694 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `SelfReg`", &view );
4695 if (rc != ERROR_SUCCESS)
4696 return ERROR_SUCCESS;
4698 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4699 msiobj_release( &view->hdr );
4700 return rc;
4703 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4705 MSIFEATURE *feature;
4706 UINT rc;
4707 HKEY hkey = NULL, userdata = NULL;
4709 if (package->script == SCRIPT_NONE)
4710 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishFeatures");
4712 if (!msi_check_publish(package))
4713 return ERROR_SUCCESS;
4715 rc = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4716 &hkey, TRUE);
4717 if (rc != ERROR_SUCCESS)
4718 goto end;
4720 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4721 &userdata, TRUE);
4722 if (rc != ERROR_SUCCESS)
4723 goto end;
4725 /* here the guids are base 85 encoded */
4726 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4728 ComponentList *cl;
4729 LPWSTR data = NULL;
4730 GUID clsid;
4731 INT size;
4732 BOOL absent = FALSE;
4733 MSIRECORD *uirow;
4735 if (feature->Level <= 0) continue;
4736 if (feature->Action == INSTALLSTATE_UNKNOWN &&
4737 feature->Installed != INSTALLSTATE_ABSENT) continue;
4739 if (feature->Action != INSTALLSTATE_LOCAL &&
4740 feature->Action != INSTALLSTATE_SOURCE &&
4741 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4743 size = 1;
4744 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4746 size += 21;
4748 if (feature->Feature_Parent)
4749 size += lstrlenW( feature->Feature_Parent )+2;
4751 data = msi_alloc(size * sizeof(WCHAR));
4753 data[0] = 0;
4754 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4756 MSICOMPONENT* component = cl->component;
4757 WCHAR buf[21];
4759 buf[0] = 0;
4760 if (component->ComponentId)
4762 TRACE("From %s\n",debugstr_w(component->ComponentId));
4763 CLSIDFromString(component->ComponentId, &clsid);
4764 encode_base85_guid(&clsid,buf);
4765 TRACE("to %s\n",debugstr_w(buf));
4766 lstrcatW(data,buf);
4770 if (feature->Feature_Parent)
4772 lstrcatW(data, L"\2");
4773 lstrcatW(data, feature->Feature_Parent);
4776 msi_reg_set_val_str( userdata, feature->Feature, data );
4777 msi_free(data);
4779 size = 0;
4780 if (feature->Feature_Parent)
4781 size = lstrlenW(feature->Feature_Parent)*sizeof(WCHAR);
4782 if (!absent)
4784 size += sizeof(WCHAR);
4785 RegSetValueExW(hkey, feature->Feature, 0 ,REG_SZ,
4786 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : L""), size);
4788 else
4790 size += 2*sizeof(WCHAR);
4791 data = msi_alloc(size);
4792 data[0] = 0x6;
4793 data[1] = 0;
4794 if (feature->Feature_Parent)
4795 lstrcpyW( &data[1], feature->Feature_Parent );
4796 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4797 (LPBYTE)data,size);
4798 msi_free(data);
4801 /* the UI chunk */
4802 uirow = MSI_CreateRecord( 1 );
4803 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4804 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4805 msiobj_release( &uirow->hdr );
4806 /* FIXME: call msi_ui_progress? */
4809 end:
4810 RegCloseKey(hkey);
4811 RegCloseKey(userdata);
4812 return rc;
4815 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4817 UINT r;
4818 HKEY hkey;
4819 MSIRECORD *uirow;
4821 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4823 r = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4824 &hkey, FALSE);
4825 if (r == ERROR_SUCCESS)
4827 RegDeleteValueW(hkey, feature->Feature);
4828 RegCloseKey(hkey);
4831 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4832 &hkey, FALSE);
4833 if (r == ERROR_SUCCESS)
4835 RegDeleteValueW(hkey, feature->Feature);
4836 RegCloseKey(hkey);
4839 uirow = MSI_CreateRecord( 1 );
4840 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4841 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4842 msiobj_release( &uirow->hdr );
4844 return ERROR_SUCCESS;
4847 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4849 MSIFEATURE *feature;
4851 if (package->script == SCRIPT_NONE)
4852 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnpublishFeatures");
4854 if (!msi_check_unpublish(package))
4855 return ERROR_SUCCESS;
4857 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4859 msi_unpublish_feature(package, feature);
4862 return ERROR_SUCCESS;
4865 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4867 static const WCHAR *propval[] =
4869 L"ARPAUTHORIZEDCDFPREFIX", L"AuthorizedCDFPrefix",
4870 L"ARPCONTACT", L"Contact",
4871 L"ARPCOMMENTS", L"Comments",
4872 L"ProductName", L"DisplayName",
4873 L"ARPHELPLINK", L"HelpLink",
4874 L"ARPHELPTELEPHONE", L"HelpTelephone",
4875 L"ARPINSTALLLOCATION", L"InstallLocation",
4876 L"SourceDir", L"InstallSource",
4877 L"Manufacturer", L"Publisher",
4878 L"ARPREADME", L"ReadMe",
4879 L"ARPSIZE", L"Size",
4880 L"ARPURLINFOABOUT", L"URLInfoAbout",
4881 L"ARPURLUPDATEINFO", L"URLUpdateInfo",
4882 NULL
4884 const WCHAR **p = propval;
4885 SYSTEMTIME systime;
4886 DWORD size, langid;
4887 WCHAR date[9], *val, *buffer;
4888 const WCHAR *prop, *key;
4890 while (*p)
4892 prop = *p++;
4893 key = *p++;
4894 val = msi_dup_property(package->db, prop);
4895 msi_reg_set_val_str(hkey, key, val);
4896 msi_free(val);
4899 msi_reg_set_val_dword(hkey, L"WindowsInstaller", 1);
4900 if (msi_get_property_int( package->db, L"ARPSYSTEMCOMPONENT", 0 ))
4902 msi_reg_set_val_dword( hkey, L"SystemComponent", 1 );
4905 if (msi_get_property_int( package->db, L"ARPNOREMOVE", 0 ))
4906 msi_reg_set_val_dword( hkey, L"NoRemove", 1 );
4907 else
4909 static const WCHAR fmt_install[] = L"MsiExec.exe /I[ProductCode]";
4910 static const WCHAR fmt_uninstall[] = L"MsiExec.exe /X[ProductCode]";
4911 const WCHAR *fmt = fmt_install;
4913 if (msi_get_property_int( package->db, L"ARPNOREPAIR", 0 ))
4914 msi_reg_set_val_dword( hkey, L"NoRepair", 1 );
4916 if (msi_get_property_int( package->db, L"ARPNOMODIFY", 0 ))
4918 msi_reg_set_val_dword( hkey, L"NoModify", 1 );
4919 fmt = fmt_uninstall;
4922 size = deformat_string(package, fmt, &buffer) * sizeof(WCHAR);
4923 RegSetValueExW(hkey, L"ModifyPath", 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4924 RegSetValueExW(hkey, L"UninstallString", 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4925 msi_free(buffer);
4928 /* FIXME: Write real Estimated Size when we have it */
4929 msi_reg_set_val_dword(hkey, L"EstimatedSize", 0);
4931 GetLocalTime(&systime);
4932 swprintf(date, ARRAY_SIZE(date), L"%d%02d%02d", systime.wYear, systime.wMonth, systime.wDay);
4933 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4935 langid = msi_get_property_int(package->db, L"ProductLanguage", 0);
4936 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4938 buffer = msi_dup_property(package->db, L"ProductVersion");
4939 msi_reg_set_val_str(hkey, L"DisplayVersion", buffer);
4940 if (buffer)
4942 DWORD verdword = msi_version_str_to_dword(buffer);
4944 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4945 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4946 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4947 msi_free(buffer);
4950 return ERROR_SUCCESS;
4953 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4955 WCHAR *upgrade_code, squashed_pc[SQUASHED_GUID_SIZE];
4956 MSIRECORD *uirow;
4957 HKEY hkey, props, upgrade_key;
4958 UINT rc;
4960 if (package->script == SCRIPT_NONE)
4961 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterProduct");
4963 /* FIXME: also need to publish if the product is in advertise mode */
4964 if (!msi_get_property_int( package->db, L"ProductToBeRegistered", 0 )
4965 && !msi_check_publish(package))
4966 return ERROR_SUCCESS;
4968 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4969 if (rc != ERROR_SUCCESS)
4970 return rc;
4972 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4973 if (rc != ERROR_SUCCESS)
4974 goto done;
4976 rc = msi_publish_install_properties(package, hkey);
4977 if (rc != ERROR_SUCCESS)
4978 goto done;
4980 rc = msi_publish_install_properties(package, props);
4981 if (rc != ERROR_SUCCESS)
4982 goto done;
4984 upgrade_code = msi_dup_property(package->db, L"UpgradeCode");
4985 if (upgrade_code)
4987 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4988 if (rc == ERROR_SUCCESS)
4990 squash_guid( package->ProductCode, squashed_pc );
4991 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4992 RegCloseKey( upgrade_key );
4994 msi_free( upgrade_code );
4996 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4997 package->delete_on_close = FALSE;
4999 done:
5000 uirow = MSI_CreateRecord( 1 );
5001 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5002 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5003 msiobj_release( &uirow->hdr );
5005 RegCloseKey(hkey);
5006 return ERROR_SUCCESS;
5009 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5011 return execute_script(package, SCRIPT_INSTALL);
5014 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5016 MSIPACKAGE *package = param;
5017 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5018 WCHAR *p, *icon_path;
5020 if (!icon) return ERROR_SUCCESS;
5021 if ((icon_path = msi_build_icon_path( package, icon )))
5023 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5024 msi_delete_file( package, icon_path );
5025 if ((p = wcsrchr( icon_path, '\\' )))
5027 *p = 0;
5028 msi_remove_directory( package, icon_path );
5030 msi_free( icon_path );
5032 return ERROR_SUCCESS;
5035 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5037 MSIQUERY *view;
5038 UINT r;
5040 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Icon`", &view );
5041 if (r == ERROR_SUCCESS)
5043 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5044 msiobj_release( &view->hdr );
5045 if (r != ERROR_SUCCESS)
5046 return r;
5048 return ERROR_SUCCESS;
5051 static void remove_product_upgrade_code( MSIPACKAGE *package )
5053 WCHAR *code, product[SQUASHED_GUID_SIZE];
5054 HKEY hkey;
5055 LONG res;
5056 DWORD count;
5058 squash_guid( package->ProductCode, product );
5059 if (!(code = msi_dup_property( package->db, L"UpgradeCode" )))
5061 WARN( "upgrade code not found\n" );
5062 return;
5064 if (!MSIREG_OpenUpgradeCodesKey( code, &hkey, FALSE ))
5066 RegDeleteValueW( hkey, product );
5067 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
5068 RegCloseKey( hkey );
5069 if (!res && !count) MSIREG_DeleteUpgradeCodesKey( code );
5071 if (!MSIREG_OpenUserUpgradeCodesKey( code, &hkey, FALSE ))
5073 RegDeleteValueW( hkey, product );
5074 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
5075 RegCloseKey( hkey );
5076 if (!res && !count) MSIREG_DeleteUserUpgradeCodesKey( code );
5078 if (!MSIREG_OpenClassesUpgradeCodesKey( code, &hkey, FALSE ))
5080 RegDeleteValueW( hkey, product );
5081 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
5082 RegCloseKey( hkey );
5083 if (!res && !count) MSIREG_DeleteClassesUpgradeCodesKey( code );
5086 msi_free( code );
5089 static UINT ACTION_UnpublishProduct(MSIPACKAGE *package)
5091 MSIPATCHINFO *patch;
5093 MSIREG_DeleteProductKey(package->ProductCode);
5094 MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context);
5095 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5097 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5098 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5099 MSIREG_DeleteUserProductKey(package->ProductCode);
5100 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5102 remove_product_upgrade_code( package );
5104 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5106 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5107 if (!wcscmp( package->ProductCode, patch->products ))
5109 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5110 patch->delete_on_close = TRUE;
5112 /* FIXME: remove local patch package if this is the last product */
5114 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5115 package->delete_on_close = TRUE;
5117 msi_unpublish_icons( package );
5118 return ERROR_SUCCESS;
5121 static BOOL is_full_uninstall( MSIPACKAGE *package )
5123 MSIFEATURE *feature;
5125 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5127 if (feature->Action != INSTALLSTATE_ABSENT &&
5128 (feature->Installed != INSTALLSTATE_ABSENT || feature->Action != INSTALLSTATE_UNKNOWN))
5129 return FALSE;
5132 return TRUE;
5135 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5137 UINT rc;
5139 /* first do the same as an InstallExecute */
5140 rc = execute_script(package, SCRIPT_INSTALL);
5141 if (rc != ERROR_SUCCESS)
5142 return rc;
5144 /* then handle commit actions */
5145 rc = execute_script(package, SCRIPT_COMMIT);
5146 if (rc != ERROR_SUCCESS)
5147 return rc;
5149 if (is_full_uninstall(package))
5150 rc = ACTION_UnpublishProduct(package);
5152 return rc;
5155 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5157 WCHAR buffer[256], sysdir[MAX_PATH], squashed_pc[SQUASHED_GUID_SIZE];
5158 HKEY hkey;
5160 squash_guid( package->ProductCode, squashed_pc );
5162 GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
5163 RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", &hkey);
5164 swprintf(buffer, ARRAY_SIZE(buffer), L"%s\\MsiExec.exe /@ \"%s\"", sysdir, squashed_pc);
5166 msi_reg_set_val_str( hkey, squashed_pc, buffer );
5167 RegCloseKey(hkey);
5169 TRACE("Reboot command %s\n",debugstr_w(buffer));
5171 RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\RunOnceEntries",
5172 &hkey);
5173 swprintf( buffer, ARRAY_SIZE(buffer), L"/I \"%s\" AFTERREBOOT=1 RUNONCEENTRY=\"%s\"", package->ProductCode,
5174 squashed_pc );
5176 msi_reg_set_val_str( hkey, squashed_pc, buffer );
5177 RegCloseKey(hkey);
5179 return ERROR_INSTALL_SUSPEND;
5182 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5184 DWORD attrib;
5185 UINT rc;
5188 * We are currently doing what should be done here in the top level Install
5189 * however for Administrative and uninstalls this step will be needed
5191 if (!package->PackagePath)
5192 return ERROR_SUCCESS;
5194 msi_set_sourcedir_props(package, TRUE);
5196 attrib = GetFileAttributesW(package->db->path);
5197 if (attrib == INVALID_FILE_ATTRIBUTES)
5199 MSIRECORD *record;
5200 LPWSTR prompt;
5201 DWORD size = 0;
5203 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5204 package->Context, MSICODE_PRODUCT,
5205 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5206 if (rc == ERROR_MORE_DATA)
5208 prompt = msi_alloc(size * sizeof(WCHAR));
5209 MsiSourceListGetInfoW(package->ProductCode, NULL,
5210 package->Context, MSICODE_PRODUCT,
5211 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5213 else
5214 prompt = strdupW(package->db->path);
5216 record = MSI_CreateRecord(2);
5217 MSI_RecordSetInteger(record, 1, MSIERR_INSERTDISK);
5218 MSI_RecordSetStringW(record, 2, prompt);
5219 msi_free(prompt);
5220 while(attrib == INVALID_FILE_ATTRIBUTES)
5222 MSI_RecordSetStringW(record, 0, NULL);
5223 rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ERROR, record);
5224 if (rc == IDCANCEL)
5225 return ERROR_INSTALL_USEREXIT;
5226 attrib = GetFileAttributesW(package->db->path);
5228 rc = ERROR_SUCCESS;
5230 else
5231 return ERROR_SUCCESS;
5233 return rc;
5236 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5238 static const WCHAR szPropKeys[][80] =
5240 L"ProductID",
5241 L"USERNAME",
5242 L"COMPANYNAME",
5243 L"",
5245 static const WCHAR szRegKeys[][80] =
5247 L"ProductID",
5248 L"RegOwner",
5249 L"RegCompany",
5250 L"",
5252 HKEY hkey = 0;
5253 LPWSTR buffer, productid = NULL;
5254 UINT i, rc = ERROR_SUCCESS;
5255 MSIRECORD *uirow;
5257 if (package->script == SCRIPT_NONE)
5258 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterUser");
5260 if (msi_check_unpublish(package))
5262 MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context);
5263 goto end;
5266 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5267 if (!productid)
5268 goto end;
5270 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5271 NULL, &hkey, TRUE);
5272 if (rc != ERROR_SUCCESS)
5273 goto end;
5275 for( i = 0; szPropKeys[i][0]; i++ )
5277 buffer = msi_dup_property( package->db, szPropKeys[i] );
5278 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5279 msi_free( buffer );
5282 end:
5283 uirow = MSI_CreateRecord( 1 );
5284 MSI_RecordSetStringW( uirow, 1, productid );
5285 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5286 msiobj_release( &uirow->hdr );
5288 msi_free(productid);
5289 RegCloseKey(hkey);
5290 return rc;
5293 static UINT iterate_properties(MSIRECORD *record, void *param)
5295 MSIRECORD *uirow;
5297 uirow = MSI_CloneRecord(record);
5298 if (!uirow) return ERROR_OUTOFMEMORY;
5299 MSI_RecordSetStringW(uirow, 0, L"Property(S): [1] = [2]");
5300 MSI_ProcessMessage(param, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow);
5301 msiobj_release(&uirow->hdr);
5303 return ERROR_SUCCESS;
5307 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5309 WCHAR *productname;
5310 WCHAR *action;
5311 WCHAR *info_template;
5312 MSIQUERY *view;
5313 MSIRECORD *uirow, *uirow_info;
5314 UINT rc;
5316 /* Send COMMONDATA and INFO messages. */
5317 /* FIXME: when should these messages be sent? [see also MsiOpenPackage()] */
5318 uirow = MSI_CreateRecord(3);
5319 if (!uirow) return ERROR_OUTOFMEMORY;
5320 MSI_RecordSetStringW(uirow, 0, NULL);
5321 MSI_RecordSetInteger(uirow, 1, 0);
5322 MSI_RecordSetInteger(uirow, 2, package->num_langids ? package->langids[0] : 0);
5323 MSI_RecordSetInteger(uirow, 3, msi_get_string_table_codepage(package->db->strings));
5324 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5325 /* FIXME: send INSTALLMESSAGE_PROGRESS */
5326 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5328 if (!(needs_ui_sequence(package) && ui_sequence_exists(package)))
5330 uirow_info = MSI_CreateRecord(0);
5331 if (!uirow_info)
5333 msiobj_release(&uirow->hdr);
5334 return ERROR_OUTOFMEMORY;
5336 info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
5337 MSI_RecordSetStringW(uirow_info, 0, info_template);
5338 msi_free(info_template);
5339 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow_info);
5340 msiobj_release(&uirow_info->hdr);
5343 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow);
5345 productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
5346 MSI_RecordSetInteger(uirow, 1, 1);
5347 MSI_RecordSetStringW(uirow, 2, productname);
5348 MSI_RecordSetStringW(uirow, 3, NULL);
5349 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow);
5350 msiobj_release(&uirow->hdr);
5352 package->LastActionResult = MSI_NULL_INTEGER;
5354 action = msi_dup_property(package->db, L"EXECUTEACTION");
5355 if (!action) action = msi_strdupW(L"INSTALL", ARRAY_SIZE(L"INSTALL") - 1);
5357 /* Perform the action. Top-level actions trigger a sequence. */
5358 if (!wcscmp(action, L"INSTALL"))
5360 /* Send ACTIONSTART/INFO and INSTALLSTART. */
5361 ui_actionstart(package, L"INSTALL", NULL, NULL);
5362 ui_actioninfo(package, L"INSTALL", TRUE, 0);
5363 uirow = MSI_CreateRecord(2);
5364 if (!uirow)
5366 rc = ERROR_OUTOFMEMORY;
5367 goto end;
5369 MSI_RecordSetStringW(uirow, 0, NULL);
5370 MSI_RecordSetStringW(uirow, 1, productname);
5371 MSI_RecordSetStringW(uirow, 2, package->ProductCode);
5372 MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLSTART, uirow);
5373 msiobj_release(&uirow->hdr);
5375 /* Perform the installation. Always use the ExecuteSequence. */
5376 package->InWhatSequence |= SEQUENCE_EXEC;
5377 rc = ACTION_ProcessExecSequence(package);
5379 /* Send return value and INSTALLEND. */
5380 ui_actioninfo(package, L"INSTALL", FALSE, !rc);
5381 uirow = MSI_CreateRecord(3);
5382 if (!uirow)
5384 rc = ERROR_OUTOFMEMORY;
5385 goto end;
5387 MSI_RecordSetStringW(uirow, 0, NULL);
5388 MSI_RecordSetStringW(uirow, 1, productname);
5389 MSI_RecordSetStringW(uirow, 2, package->ProductCode);
5390 MSI_RecordSetInteger(uirow, 3, !rc);
5391 MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLEND, uirow);
5392 msiobj_release(&uirow->hdr);
5394 else
5395 rc = ACTION_PerformAction(package, action);
5397 /* Send all set properties. */
5398 if (!MSI_OpenQuery(package->db, &view, L"SELECT * FROM `_Property`"))
5400 MSI_IterateRecords(view, NULL, iterate_properties, package);
5401 msiobj_release(&view->hdr);
5404 /* And finally, toggle the cancel off and on. */
5405 uirow = MSI_CreateRecord(2);
5406 if (!uirow)
5408 rc = ERROR_OUTOFMEMORY;
5409 goto end;
5411 MSI_RecordSetStringW(uirow, 0, NULL);
5412 MSI_RecordSetInteger(uirow, 1, 2);
5413 MSI_RecordSetInteger(uirow, 2, 0);
5414 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5415 MSI_RecordSetInteger(uirow, 2, 1);
5416 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5417 msiobj_release(&uirow->hdr);
5419 end:
5420 msi_free(productname);
5421 msi_free(action);
5422 return rc;
5425 static UINT ACTION_INSTALL(MSIPACKAGE *package)
5427 msi_set_property(package->db, L"EXECUTEACTION", L"INSTALL", -1);
5428 if (needs_ui_sequence(package) && ui_sequence_exists(package))
5430 package->InWhatSequence |= SEQUENCE_UI;
5431 return ACTION_ProcessUISequence(package);
5433 else
5434 return ACTION_ExecuteAction(package);
5437 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5439 WCHAR productid_85[21], component_85[21], *ret;
5440 GUID clsid;
5441 DWORD sz;
5443 /* > is used if there is a component GUID and < if not. */
5445 productid_85[0] = 0;
5446 component_85[0] = 0;
5447 CLSIDFromString( package->ProductCode, &clsid );
5449 encode_base85_guid( &clsid, productid_85 );
5450 if (component)
5452 CLSIDFromString( component->ComponentId, &clsid );
5453 encode_base85_guid( &clsid, component_85 );
5456 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5457 debugstr_w(component_85));
5459 sz = 20 + lstrlenW( feature ) + 20 + 3;
5460 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5461 if (ret) swprintf( ret, sz, L"%s%s%c%s", productid_85, feature, component ? '>' : '<', component_85 );
5462 return ret;
5465 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5467 MSIPACKAGE *package = param;
5468 LPCWSTR compgroupid, component, feature, qualifier, text;
5469 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5470 HKEY hkey = NULL;
5471 UINT rc;
5472 MSICOMPONENT *comp;
5473 MSIFEATURE *feat;
5474 DWORD sz;
5475 MSIRECORD *uirow;
5476 int len;
5478 feature = MSI_RecordGetString(rec, 5);
5479 feat = msi_get_loaded_feature(package, feature);
5480 if (!feat)
5481 return ERROR_SUCCESS;
5483 feat->Action = msi_get_feature_action( package, feat );
5484 if (feat->Action != INSTALLSTATE_LOCAL &&
5485 feat->Action != INSTALLSTATE_SOURCE &&
5486 feat->Action != INSTALLSTATE_ADVERTISED)
5488 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5489 return ERROR_SUCCESS;
5492 component = MSI_RecordGetString(rec, 3);
5493 comp = msi_get_loaded_component(package, component);
5494 if (!comp)
5495 return ERROR_SUCCESS;
5497 compgroupid = MSI_RecordGetString(rec,1);
5498 qualifier = MSI_RecordGetString(rec,2);
5500 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5501 if (rc != ERROR_SUCCESS)
5502 goto end;
5504 advertise = msi_create_component_advertise_string( package, comp, feature );
5505 text = MSI_RecordGetString( rec, 4 );
5506 if (text)
5508 p = msi_alloc( (lstrlenW( advertise ) + lstrlenW( text ) + 1) * sizeof(WCHAR) );
5509 lstrcpyW( p, advertise );
5510 lstrcatW( p, text );
5511 msi_free( advertise );
5512 advertise = p;
5514 existing = msi_reg_get_val_str( hkey, qualifier );
5516 sz = lstrlenW( advertise ) + 1;
5517 if (existing)
5519 for (p = existing; *p; p += len)
5521 len = lstrlenW( p ) + 1;
5522 if (wcscmp( advertise, p )) sz += len;
5525 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5527 rc = ERROR_OUTOFMEMORY;
5528 goto end;
5530 q = output;
5531 if (existing)
5533 for (p = existing; *p; p += len)
5535 len = lstrlenW( p ) + 1;
5536 if (wcscmp( advertise, p ))
5538 memcpy( q, p, len * sizeof(WCHAR) );
5539 q += len;
5543 lstrcpyW( q, advertise );
5544 q[lstrlenW( q ) + 1] = 0;
5546 msi_reg_set_val_multi_str( hkey, qualifier, output );
5548 end:
5549 RegCloseKey(hkey);
5550 msi_free( output );
5551 msi_free( advertise );
5552 msi_free( existing );
5554 /* the UI chunk */
5555 uirow = MSI_CreateRecord( 2 );
5556 MSI_RecordSetStringW( uirow, 1, compgroupid );
5557 MSI_RecordSetStringW( uirow, 2, qualifier);
5558 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5559 msiobj_release( &uirow->hdr );
5560 /* FIXME: call ui_progress? */
5562 return rc;
5566 * At present I am ignoring the advertised components part of this and only
5567 * focusing on the qualified component sets
5569 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5571 MSIQUERY *view;
5572 UINT rc;
5574 if (package->script == SCRIPT_NONE)
5575 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishComponents");
5577 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `PublishComponent`", &view);
5578 if (rc != ERROR_SUCCESS)
5579 return ERROR_SUCCESS;
5581 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5582 msiobj_release(&view->hdr);
5583 return rc;
5586 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5588 MSIPACKAGE *package = param;
5589 LPCWSTR compgroupid, component, feature, qualifier;
5590 MSICOMPONENT *comp;
5591 MSIFEATURE *feat;
5592 MSIRECORD *uirow;
5593 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5594 LONG res;
5596 feature = MSI_RecordGetString( rec, 5 );
5597 feat = msi_get_loaded_feature( package, feature );
5598 if (!feat)
5599 return ERROR_SUCCESS;
5601 feat->Action = msi_get_feature_action( package, feat );
5602 if (feat->Action != INSTALLSTATE_ABSENT)
5604 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5605 return ERROR_SUCCESS;
5608 component = MSI_RecordGetString( rec, 3 );
5609 comp = msi_get_loaded_component( package, component );
5610 if (!comp)
5611 return ERROR_SUCCESS;
5613 compgroupid = MSI_RecordGetString( rec, 1 );
5614 qualifier = MSI_RecordGetString( rec, 2 );
5616 squash_guid( compgroupid, squashed );
5617 lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Components\\" );
5618 lstrcatW( keypath, squashed );
5620 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5621 if (res != ERROR_SUCCESS)
5623 WARN( "unable to delete component key %ld\n", res );
5626 uirow = MSI_CreateRecord( 2 );
5627 MSI_RecordSetStringW( uirow, 1, compgroupid );
5628 MSI_RecordSetStringW( uirow, 2, qualifier );
5629 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5630 msiobj_release( &uirow->hdr );
5632 return ERROR_SUCCESS;
5635 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5637 MSIQUERY *view;
5638 UINT rc;
5640 if (package->script == SCRIPT_NONE)
5641 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnpublishComponents");
5643 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `PublishComponent`", &view );
5644 if (rc != ERROR_SUCCESS)
5645 return ERROR_SUCCESS;
5647 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5648 msiobj_release( &view->hdr );
5649 return rc;
5652 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5654 MSIPACKAGE *package = param;
5655 MSICOMPONENT *component;
5656 MSIRECORD *row;
5657 MSIFILE *file;
5658 SC_HANDLE hscm = NULL, service = NULL;
5659 LPCWSTR comp, key;
5660 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5661 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5662 DWORD serv_type, start_type, err_control;
5663 BOOL is_vital;
5664 SERVICE_DESCRIPTIONW sd = {NULL};
5665 UINT ret = ERROR_SUCCESS;
5667 comp = MSI_RecordGetString( rec, 12 );
5668 component = msi_get_loaded_component( package, comp );
5669 if (!component)
5671 WARN("service component not found\n");
5672 goto done;
5674 component->Action = msi_get_component_action( package, component );
5675 if (component->Action != INSTALLSTATE_LOCAL)
5677 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5678 goto done;
5680 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5681 if (!hscm)
5683 ERR("Failed to open the SC Manager!\n");
5684 goto done;
5687 start_type = MSI_RecordGetInteger(rec, 5);
5688 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5689 goto done;
5691 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5692 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5693 serv_type = MSI_RecordGetInteger(rec, 4);
5694 err_control = MSI_RecordGetInteger(rec, 6);
5695 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5696 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5697 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5698 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5699 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5700 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5702 /* Should the complete install fail if CreateService fails? */
5703 is_vital = (err_control & msidbServiceInstallErrorControlVital);
5705 /* Remove the msidbServiceInstallErrorControlVital-flag from err_control.
5706 CreateService (under Windows) would fail if not. */
5707 err_control &= ~msidbServiceInstallErrorControlVital;
5709 /* fetch the service path */
5710 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Component` WHERE `Component` = '%s'", comp);
5711 if (!row)
5713 ERR("Query failed\n");
5714 goto done;
5716 if (!(key = MSI_RecordGetString(row, 6)))
5718 msiobj_release(&row->hdr);
5719 goto done;
5721 file = msi_get_loaded_file(package, key);
5722 msiobj_release(&row->hdr);
5723 if (!file)
5725 ERR("Failed to load the service file\n");
5726 goto done;
5729 if (!args || !args[0]) image_path = file->TargetPath;
5730 else
5732 int len = lstrlenW(file->TargetPath) + lstrlenW(args) + 2;
5733 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5735 ret = ERROR_OUTOFMEMORY;
5736 goto done;
5739 lstrcpyW(image_path, file->TargetPath);
5740 lstrcatW(image_path, L" ");
5741 lstrcatW(image_path, args);
5743 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5744 start_type, err_control, image_path, load_order,
5745 NULL, depends, serv_name, pass);
5747 if (!service)
5749 if (GetLastError() != ERROR_SERVICE_EXISTS)
5751 WARN( "failed to create service %s (%lu)\n", debugstr_w(name), GetLastError() );
5752 if (is_vital)
5753 ret = ERROR_INSTALL_FAILURE;
5757 else if (sd.lpDescription)
5759 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5760 WARN( "failed to set service description %lu\n", GetLastError() );
5763 if (image_path != file->TargetPath) msi_free(image_path);
5764 done:
5765 if (service) CloseServiceHandle(service);
5766 if (hscm) CloseServiceHandle(hscm);
5767 msi_free(name);
5768 msi_free(disp);
5769 msi_free(sd.lpDescription);
5770 msi_free(load_order);
5771 msi_free(serv_name);
5772 msi_free(pass);
5773 msi_free(depends);
5774 msi_free(args);
5776 return ret;
5779 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5781 MSIQUERY *view;
5782 UINT rc;
5784 if (package->script == SCRIPT_NONE)
5785 return msi_schedule_action(package, SCRIPT_INSTALL, L"InstallServices");
5787 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceInstall`", &view);
5788 if (rc != ERROR_SUCCESS)
5789 return ERROR_SUCCESS;
5791 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5792 msiobj_release(&view->hdr);
5793 return rc;
5796 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5797 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5799 LPCWSTR *vector, *temp_vector;
5800 LPWSTR p, q;
5801 DWORD sep_len;
5803 *numargs = 0;
5804 sep_len = ARRAY_SIZE(L"[~]") - 1;
5806 if (!args)
5807 return NULL;
5809 vector = msi_alloc(sizeof(LPWSTR));
5810 if (!vector)
5811 return NULL;
5813 p = args;
5816 (*numargs)++;
5817 vector[*numargs - 1] = p;
5819 if ((q = wcsstr(p, L"[~]")))
5821 *q = '\0';
5823 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5824 if (!temp_vector)
5826 msi_free(vector);
5827 return NULL;
5829 vector = temp_vector;
5831 p = q + sep_len;
5833 } while (q);
5835 return vector;
5838 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5840 MSIPACKAGE *package = param;
5841 MSICOMPONENT *comp;
5842 MSIRECORD *uirow;
5843 SC_HANDLE scm = NULL, service = NULL;
5844 LPCWSTR component, *vector = NULL;
5845 LPWSTR name, args, display_name = NULL;
5846 DWORD event, numargs, len, wait, dummy;
5847 UINT r = ERROR_FUNCTION_FAILED;
5848 SERVICE_STATUS_PROCESS status;
5849 ULONGLONG start_time;
5851 component = MSI_RecordGetString(rec, 6);
5852 comp = msi_get_loaded_component(package, component);
5853 if (!comp)
5854 return ERROR_SUCCESS;
5856 event = MSI_RecordGetInteger( rec, 3 );
5857 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5859 comp->Action = msi_get_component_action( package, comp );
5860 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStart)) &&
5861 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStart)))
5863 TRACE("not starting %s\n", debugstr_w(name));
5864 msi_free( name );
5865 return ERROR_SUCCESS;
5868 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5869 wait = MSI_RecordGetInteger(rec, 5);
5871 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5872 if (!scm)
5874 ERR("Failed to open the service control manager\n");
5875 goto done;
5878 len = 0;
5879 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5880 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5882 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5883 GetServiceDisplayNameW( scm, name, display_name, &len );
5886 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5887 if (!service)
5889 ERR( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() );
5890 goto done;
5893 vector = msi_service_args_to_vector(args, &numargs);
5895 if (!StartServiceW(service, numargs, vector) &&
5896 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5898 ERR( "failed to start service %s (%lu)\n", debugstr_w(name), GetLastError() );
5899 goto done;
5902 r = ERROR_SUCCESS;
5903 if (wait)
5905 /* wait for at most 30 seconds for the service to be up and running */
5906 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5907 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5909 TRACE( "failed to query service status (%lu)\n", GetLastError() );
5910 goto done;
5912 start_time = GetTickCount64();
5913 while (status.dwCurrentState == SERVICE_START_PENDING)
5915 if (GetTickCount64() - start_time > 30000) break;
5916 Sleep(1000);
5917 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5918 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5920 TRACE( "failed to query service status (%lu)\n", GetLastError() );
5921 goto done;
5924 if (status.dwCurrentState != SERVICE_RUNNING)
5926 WARN( "service failed to start %lu\n", status.dwCurrentState );
5927 r = ERROR_FUNCTION_FAILED;
5931 done:
5932 uirow = MSI_CreateRecord( 2 );
5933 MSI_RecordSetStringW( uirow, 1, display_name );
5934 MSI_RecordSetStringW( uirow, 2, name );
5935 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5936 msiobj_release( &uirow->hdr );
5938 if (service) CloseServiceHandle(service);
5939 if (scm) CloseServiceHandle(scm);
5941 msi_free(name);
5942 msi_free(args);
5943 msi_free(vector);
5944 msi_free(display_name);
5945 return r;
5948 static UINT ACTION_StartServices( MSIPACKAGE *package )
5950 MSIQUERY *view;
5951 UINT rc;
5953 if (package->script == SCRIPT_NONE)
5954 return msi_schedule_action(package, SCRIPT_INSTALL, L"StartServices");
5956 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceControl`", &view);
5957 if (rc != ERROR_SUCCESS)
5958 return ERROR_SUCCESS;
5960 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5961 msiobj_release(&view->hdr);
5962 return rc;
5965 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5967 DWORD i, needed, count;
5968 ENUM_SERVICE_STATUSW *dependencies;
5969 SERVICE_STATUS ss;
5970 SC_HANDLE depserv;
5971 BOOL stopped, ret = FALSE;
5973 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5974 0, &needed, &count))
5975 return TRUE;
5977 if (GetLastError() != ERROR_MORE_DATA)
5978 return FALSE;
5980 dependencies = msi_alloc(needed);
5981 if (!dependencies)
5982 return FALSE;
5984 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5985 needed, &needed, &count))
5986 goto done;
5988 for (i = 0; i < count; i++)
5990 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5991 SERVICE_STOP | SERVICE_QUERY_STATUS);
5992 if (!depserv)
5993 goto done;
5995 stopped = ControlService(depserv, SERVICE_CONTROL_STOP, &ss);
5996 CloseServiceHandle(depserv);
5997 if (!stopped)
5998 goto done;
6001 ret = TRUE;
6003 done:
6004 msi_free(dependencies);
6005 return ret;
6008 static UINT stop_service( LPCWSTR name )
6010 SC_HANDLE scm = NULL, service = NULL;
6011 SERVICE_STATUS status;
6012 SERVICE_STATUS_PROCESS ssp;
6013 DWORD needed;
6015 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6016 if (!scm)
6018 WARN( "failed to open the SCM (%lu)\n", GetLastError() );
6019 goto done;
6022 service = OpenServiceW(scm, name, SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
6023 if (!service)
6025 WARN( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() );
6026 goto done;
6029 if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&ssp, sizeof(ssp), &needed) )
6031 WARN( "failed to query service status %s (%lu)\n", debugstr_w(name), GetLastError() );
6032 goto done;
6035 if (ssp.dwCurrentState == SERVICE_STOPPED)
6036 goto done;
6038 stop_service_dependents(scm, service);
6040 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6041 WARN( "failed to stop service %s (%lu)\n", debugstr_w(name), GetLastError() );
6043 done:
6044 if (service) CloseServiceHandle(service);
6045 if (scm) CloseServiceHandle(scm);
6047 return ERROR_SUCCESS;
6050 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6052 MSIPACKAGE *package = param;
6053 MSICOMPONENT *comp;
6054 MSIRECORD *uirow;
6055 LPCWSTR component;
6056 WCHAR *name, *display_name = NULL;
6057 DWORD event, len;
6058 SC_HANDLE scm;
6060 component = MSI_RecordGetString( rec, 6 );
6061 comp = msi_get_loaded_component( package, component );
6062 if (!comp)
6063 return ERROR_SUCCESS;
6065 event = MSI_RecordGetInteger( rec, 3 );
6066 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6068 comp->Action = msi_get_component_action( package, comp );
6069 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStop)) &&
6070 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStop)))
6072 TRACE("not stopping %s\n", debugstr_w(name));
6073 msi_free( name );
6074 return ERROR_SUCCESS;
6077 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6078 if (!scm)
6080 ERR("Failed to open the service control manager\n");
6081 goto done;
6084 len = 0;
6085 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6086 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6088 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6089 GetServiceDisplayNameW( scm, name, display_name, &len );
6091 CloseServiceHandle( scm );
6093 stop_service( name );
6095 done:
6096 uirow = MSI_CreateRecord( 2 );
6097 MSI_RecordSetStringW( uirow, 1, display_name );
6098 MSI_RecordSetStringW( uirow, 2, name );
6099 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6100 msiobj_release( &uirow->hdr );
6102 msi_free( name );
6103 msi_free( display_name );
6104 return ERROR_SUCCESS;
6107 static UINT ACTION_StopServices( MSIPACKAGE *package )
6109 MSIQUERY *view;
6110 UINT rc;
6112 if (package->script == SCRIPT_NONE)
6113 return msi_schedule_action(package, SCRIPT_INSTALL, L"StopServices");
6115 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceControl`", &view);
6116 if (rc != ERROR_SUCCESS)
6117 return ERROR_SUCCESS;
6119 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6120 msiobj_release(&view->hdr);
6121 return rc;
6124 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6126 MSIPACKAGE *package = param;
6127 MSICOMPONENT *comp;
6128 MSIRECORD *uirow;
6129 LPWSTR name = NULL, display_name = NULL;
6130 DWORD event, len;
6131 SC_HANDLE scm = NULL, service = NULL;
6133 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6134 if (!comp)
6135 return ERROR_SUCCESS;
6137 event = MSI_RecordGetInteger( rec, 3 );
6138 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6140 comp->Action = msi_get_component_action( package, comp );
6141 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6142 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6144 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6145 msi_free( name );
6146 return ERROR_SUCCESS;
6148 stop_service( name );
6150 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6151 if (!scm)
6153 WARN( "failed to open the SCM (%lu)\n", GetLastError() );
6154 goto done;
6157 len = 0;
6158 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6159 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6161 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6162 GetServiceDisplayNameW( scm, name, display_name, &len );
6165 service = OpenServiceW( scm, name, DELETE );
6166 if (!service)
6168 WARN( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() );
6169 goto done;
6172 if (!DeleteService( service ))
6173 WARN( "failed to delete service %s (%lu)\n", debugstr_w(name), GetLastError() );
6175 done:
6176 uirow = MSI_CreateRecord( 2 );
6177 MSI_RecordSetStringW( uirow, 1, display_name );
6178 MSI_RecordSetStringW( uirow, 2, name );
6179 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6180 msiobj_release( &uirow->hdr );
6182 if (service) CloseServiceHandle( service );
6183 if (scm) CloseServiceHandle( scm );
6184 msi_free( name );
6185 msi_free( display_name );
6187 return ERROR_SUCCESS;
6190 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6192 MSIQUERY *view;
6193 UINT rc;
6195 if (package->script == SCRIPT_NONE)
6196 return msi_schedule_action(package, SCRIPT_INSTALL, L"DeleteServices");
6198 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ServiceControl`", &view );
6199 if (rc != ERROR_SUCCESS)
6200 return ERROR_SUCCESS;
6202 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6203 msiobj_release( &view->hdr );
6204 return rc;
6207 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6209 MSIPACKAGE *package = param;
6210 LPWSTR driver, driver_path, ptr;
6211 WCHAR outpath[MAX_PATH];
6212 MSIFILE *driver_file = NULL, *setup_file = NULL;
6213 MSICOMPONENT *comp;
6214 MSIRECORD *uirow;
6215 LPCWSTR desc, file_key, component;
6216 DWORD len, usage;
6217 UINT r = ERROR_SUCCESS;
6219 component = MSI_RecordGetString( rec, 2 );
6220 comp = msi_get_loaded_component( package, component );
6221 if (!comp)
6222 return ERROR_SUCCESS;
6224 comp->Action = msi_get_component_action( package, comp );
6225 if (comp->Action != INSTALLSTATE_LOCAL)
6227 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6228 return ERROR_SUCCESS;
6230 desc = MSI_RecordGetString(rec, 3);
6232 file_key = MSI_RecordGetString( rec, 4 );
6233 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6235 file_key = MSI_RecordGetString( rec, 5 );
6236 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6238 if (!driver_file)
6240 ERR("ODBC Driver entry not found!\n");
6241 return ERROR_FUNCTION_FAILED;
6244 len = lstrlenW(desc) + lstrlenW(L"Driver=%s") + lstrlenW(driver_file->FileName);
6245 if (setup_file)
6246 len += lstrlenW(L"Setup=%s") + lstrlenW(setup_file->FileName);
6247 len += lstrlenW(L"FileUsage=1") + 2; /* \0\0 */
6249 driver = msi_alloc(len * sizeof(WCHAR));
6250 if (!driver)
6251 return ERROR_OUTOFMEMORY;
6253 ptr = driver;
6254 lstrcpyW(ptr, desc);
6255 ptr += lstrlenW(ptr) + 1;
6257 len = swprintf(ptr, len - (ptr - driver), L"Driver=%s", driver_file->FileName);
6258 ptr += len + 1;
6260 if (setup_file)
6262 len = swprintf(ptr, len - (ptr - driver), L"Setup=%s", setup_file->FileName);
6263 ptr += len + 1;
6266 lstrcpyW(ptr, L"FileUsage=1");
6267 ptr += lstrlenW(ptr) + 1;
6268 *ptr = '\0';
6270 if (!driver_file->TargetPath)
6272 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6273 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6275 driver_path = strdupW(driver_file->TargetPath);
6276 ptr = wcsrchr(driver_path, '\\');
6277 if (ptr) *ptr = '\0';
6279 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6280 NULL, ODBC_INSTALL_COMPLETE, &usage))
6282 ERR("Failed to install SQL driver!\n");
6283 r = ERROR_FUNCTION_FAILED;
6286 uirow = MSI_CreateRecord( 5 );
6287 MSI_RecordSetStringW( uirow, 1, desc );
6288 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6289 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6290 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6291 msiobj_release( &uirow->hdr );
6293 msi_free(driver);
6294 msi_free(driver_path);
6296 return r;
6299 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6301 MSIPACKAGE *package = param;
6302 LPWSTR translator, translator_path, ptr;
6303 WCHAR outpath[MAX_PATH];
6304 MSIFILE *translator_file = NULL, *setup_file = NULL;
6305 MSICOMPONENT *comp;
6306 MSIRECORD *uirow;
6307 LPCWSTR desc, file_key, component;
6308 DWORD len, usage;
6309 UINT r = ERROR_SUCCESS;
6311 component = MSI_RecordGetString( rec, 2 );
6312 comp = msi_get_loaded_component( package, component );
6313 if (!comp)
6314 return ERROR_SUCCESS;
6316 comp->Action = msi_get_component_action( package, comp );
6317 if (comp->Action != INSTALLSTATE_LOCAL)
6319 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6320 return ERROR_SUCCESS;
6322 desc = MSI_RecordGetString(rec, 3);
6324 file_key = MSI_RecordGetString( rec, 4 );
6325 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6327 file_key = MSI_RecordGetString( rec, 5 );
6328 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6330 if (!translator_file)
6332 ERR("ODBC Translator entry not found!\n");
6333 return ERROR_FUNCTION_FAILED;
6336 len = lstrlenW(desc) + lstrlenW(L"Translator=%s") + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6337 if (setup_file)
6338 len += lstrlenW(L"Setup=%s") + lstrlenW(setup_file->FileName);
6340 translator = msi_alloc(len * sizeof(WCHAR));
6341 if (!translator)
6342 return ERROR_OUTOFMEMORY;
6344 ptr = translator;
6345 lstrcpyW(ptr, desc);
6346 ptr += lstrlenW(ptr) + 1;
6348 len = swprintf(ptr, len - (ptr - translator), L"Translator=%s", translator_file->FileName);
6349 ptr += len + 1;
6351 if (setup_file)
6353 len = swprintf(ptr, len - (ptr - translator), L"Setup=%s", setup_file->FileName);
6354 ptr += len + 1;
6356 *ptr = '\0';
6358 translator_path = strdupW(translator_file->TargetPath);
6359 ptr = wcsrchr(translator_path, '\\');
6360 if (ptr) *ptr = '\0';
6362 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6363 NULL, ODBC_INSTALL_COMPLETE, &usage))
6365 ERR("Failed to install SQL translator!\n");
6366 r = ERROR_FUNCTION_FAILED;
6369 uirow = MSI_CreateRecord( 5 );
6370 MSI_RecordSetStringW( uirow, 1, desc );
6371 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6372 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6373 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6374 msiobj_release( &uirow->hdr );
6376 msi_free(translator);
6377 msi_free(translator_path);
6379 return r;
6382 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6384 MSIPACKAGE *package = param;
6385 MSICOMPONENT *comp;
6386 LPWSTR attrs;
6387 LPCWSTR desc, driver, component;
6388 WORD request = ODBC_ADD_SYS_DSN;
6389 INT registration;
6390 DWORD len;
6391 UINT r = ERROR_SUCCESS;
6392 MSIRECORD *uirow;
6394 component = MSI_RecordGetString( rec, 2 );
6395 comp = msi_get_loaded_component( package, component );
6396 if (!comp)
6397 return ERROR_SUCCESS;
6399 comp->Action = msi_get_component_action( package, comp );
6400 if (comp->Action != INSTALLSTATE_LOCAL)
6402 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6403 return ERROR_SUCCESS;
6406 desc = MSI_RecordGetString(rec, 3);
6407 driver = MSI_RecordGetString(rec, 4);
6408 registration = MSI_RecordGetInteger(rec, 5);
6410 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6411 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6413 len = lstrlenW(L"DSN=%s") + lstrlenW(desc) + 2; /* \0\0 */
6414 attrs = msi_alloc(len * sizeof(WCHAR));
6415 if (!attrs)
6416 return ERROR_OUTOFMEMORY;
6418 len = swprintf(attrs, len, L"DSN=%s", desc);
6419 attrs[len + 1] = 0;
6421 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6422 WARN("Failed to install SQL data source!\n");
6424 uirow = MSI_CreateRecord( 5 );
6425 MSI_RecordSetStringW( uirow, 1, desc );
6426 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6427 MSI_RecordSetInteger( uirow, 3, request );
6428 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6429 msiobj_release( &uirow->hdr );
6431 msi_free(attrs);
6433 return r;
6436 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6438 MSIQUERY *view;
6439 UINT rc;
6441 if (package->script == SCRIPT_NONE)
6442 return msi_schedule_action(package, SCRIPT_INSTALL, L"InstallODBC");
6444 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCDriver`", &view);
6445 if (rc == ERROR_SUCCESS)
6447 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6448 msiobj_release(&view->hdr);
6449 if (rc != ERROR_SUCCESS)
6450 return rc;
6452 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCTranslator`", &view);
6453 if (rc == ERROR_SUCCESS)
6455 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6456 msiobj_release(&view->hdr);
6457 if (rc != ERROR_SUCCESS)
6458 return rc;
6460 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCDataSource`", &view);
6461 if (rc == ERROR_SUCCESS)
6463 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6464 msiobj_release(&view->hdr);
6465 if (rc != ERROR_SUCCESS)
6466 return rc;
6468 return ERROR_SUCCESS;
6471 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6473 MSIPACKAGE *package = param;
6474 MSICOMPONENT *comp;
6475 MSIRECORD *uirow;
6476 DWORD usage;
6477 LPCWSTR desc, component;
6479 component = MSI_RecordGetString( rec, 2 );
6480 comp = msi_get_loaded_component( package, component );
6481 if (!comp)
6482 return ERROR_SUCCESS;
6484 comp->Action = msi_get_component_action( package, comp );
6485 if (comp->Action != INSTALLSTATE_ABSENT)
6487 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6488 return ERROR_SUCCESS;
6491 desc = MSI_RecordGetString( rec, 3 );
6492 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6494 WARN("Failed to remove ODBC driver\n");
6496 else if (!usage)
6498 FIXME("Usage count reached 0\n");
6501 uirow = MSI_CreateRecord( 2 );
6502 MSI_RecordSetStringW( uirow, 1, desc );
6503 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6504 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6505 msiobj_release( &uirow->hdr );
6507 return ERROR_SUCCESS;
6510 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6512 MSIPACKAGE *package = param;
6513 MSICOMPONENT *comp;
6514 MSIRECORD *uirow;
6515 DWORD usage;
6516 LPCWSTR desc, component;
6518 component = MSI_RecordGetString( rec, 2 );
6519 comp = msi_get_loaded_component( package, component );
6520 if (!comp)
6521 return ERROR_SUCCESS;
6523 comp->Action = msi_get_component_action( package, comp );
6524 if (comp->Action != INSTALLSTATE_ABSENT)
6526 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6527 return ERROR_SUCCESS;
6530 desc = MSI_RecordGetString( rec, 3 );
6531 if (!SQLRemoveTranslatorW( desc, &usage ))
6533 WARN("Failed to remove ODBC translator\n");
6535 else if (!usage)
6537 FIXME("Usage count reached 0\n");
6540 uirow = MSI_CreateRecord( 2 );
6541 MSI_RecordSetStringW( uirow, 1, desc );
6542 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6543 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6544 msiobj_release( &uirow->hdr );
6546 return ERROR_SUCCESS;
6549 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6551 MSIPACKAGE *package = param;
6552 MSICOMPONENT *comp;
6553 MSIRECORD *uirow;
6554 LPWSTR attrs;
6555 LPCWSTR desc, driver, component;
6556 WORD request = ODBC_REMOVE_SYS_DSN;
6557 INT registration;
6558 DWORD len;
6560 component = MSI_RecordGetString( rec, 2 );
6561 comp = msi_get_loaded_component( package, component );
6562 if (!comp)
6563 return ERROR_SUCCESS;
6565 comp->Action = msi_get_component_action( package, comp );
6566 if (comp->Action != INSTALLSTATE_ABSENT)
6568 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6569 return ERROR_SUCCESS;
6572 desc = MSI_RecordGetString( rec, 3 );
6573 driver = MSI_RecordGetString( rec, 4 );
6574 registration = MSI_RecordGetInteger( rec, 5 );
6576 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6577 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6579 len = lstrlenW( L"DSN=%s" ) + lstrlenW( desc ) + 2; /* \0\0 */
6580 attrs = msi_alloc( len * sizeof(WCHAR) );
6581 if (!attrs)
6582 return ERROR_OUTOFMEMORY;
6584 FIXME("Use ODBCSourceAttribute table\n");
6586 len = swprintf( attrs, len, L"DSN=%s", desc );
6587 attrs[len + 1] = 0;
6589 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6591 WARN("Failed to remove ODBC data source\n");
6593 msi_free( attrs );
6595 uirow = MSI_CreateRecord( 3 );
6596 MSI_RecordSetStringW( uirow, 1, desc );
6597 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6598 MSI_RecordSetInteger( uirow, 3, request );
6599 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6600 msiobj_release( &uirow->hdr );
6602 return ERROR_SUCCESS;
6605 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6607 MSIQUERY *view;
6608 UINT rc;
6610 if (package->script == SCRIPT_NONE)
6611 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveODBC");
6613 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDriver`", &view );
6614 if (rc == ERROR_SUCCESS)
6616 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6617 msiobj_release( &view->hdr );
6618 if (rc != ERROR_SUCCESS)
6619 return rc;
6621 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCTranslator`", &view );
6622 if (rc == ERROR_SUCCESS)
6624 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6625 msiobj_release( &view->hdr );
6626 if (rc != ERROR_SUCCESS)
6627 return rc;
6629 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDataSource`", &view );
6630 if (rc == ERROR_SUCCESS)
6632 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6633 msiobj_release( &view->hdr );
6634 if (rc != ERROR_SUCCESS)
6635 return rc;
6637 return ERROR_SUCCESS;
6640 #define ENV_ACT_SETALWAYS 0x1
6641 #define ENV_ACT_SETABSENT 0x2
6642 #define ENV_ACT_REMOVE 0x4
6643 #define ENV_ACT_REMOVEMATCH 0x8
6645 #define ENV_MOD_MACHINE 0x20000000
6646 #define ENV_MOD_APPEND 0x40000000
6647 #define ENV_MOD_PREFIX 0x80000000
6648 #define ENV_MOD_MASK 0xC0000000
6650 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6652 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6654 const WCHAR *cptr = *name;
6656 *flags = 0;
6657 while (*cptr)
6659 if (*cptr == '=')
6660 *flags |= ENV_ACT_SETALWAYS;
6661 else if (*cptr == '+')
6662 *flags |= ENV_ACT_SETABSENT;
6663 else if (*cptr == '-')
6664 *flags |= ENV_ACT_REMOVE;
6665 else if (*cptr == '!')
6666 *flags |= ENV_ACT_REMOVEMATCH;
6667 else if (*cptr == '*')
6668 *flags |= ENV_MOD_MACHINE | ENV_ACT_REMOVE;
6669 else
6670 break;
6672 cptr++;
6673 (*name)++;
6676 if (!*cptr)
6678 ERR("Missing environment variable\n");
6679 return ERROR_FUNCTION_FAILED;
6682 if (*value)
6684 LPCWSTR ptr = *value;
6685 if (!wcsncmp(ptr, L"[~]", 3))
6687 if (ptr[3] == ';')
6689 *flags |= ENV_MOD_APPEND;
6690 *value += 3;
6692 else
6694 *value = NULL;
6697 else if (lstrlenW(*value) >= 3)
6699 ptr += lstrlenW(ptr) - 3;
6700 if (!wcscmp( ptr, L"[~]" ))
6702 if ((ptr-1) > *value && *(ptr-1) == ';')
6704 *flags |= ENV_MOD_PREFIX;
6705 /* the "[~]" will be removed by deformat_string */;
6707 else
6709 *value = NULL;
6715 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6716 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6717 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6718 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6720 ERR( "invalid flags: %#lx\n", *flags );
6721 return ERROR_FUNCTION_FAILED;
6724 if (!*flags)
6725 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6727 return ERROR_SUCCESS;
6730 static UINT open_env_key( DWORD flags, HKEY *key )
6732 const WCHAR *env;
6733 HKEY root;
6734 LONG res;
6736 if (flags & ENV_MOD_MACHINE)
6738 env = L"System\\CurrentControlSet\\Control\\Session Manager\\Environment";
6739 root = HKEY_LOCAL_MACHINE;
6741 else
6743 env = L"Environment";
6744 root = HKEY_CURRENT_USER;
6747 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6748 if (res != ERROR_SUCCESS)
6750 WARN( "failed to open key %s (%ld)\n", debugstr_w(env), res );
6751 return ERROR_FUNCTION_FAILED;
6754 return ERROR_SUCCESS;
6757 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6759 MSIPACKAGE *package = param;
6760 LPCWSTR name, value, component;
6761 WCHAR *data = NULL, *newval = NULL, *deformatted = NULL, *p, *q;
6762 DWORD flags, type, size, len, len_value = 0;
6763 UINT res;
6764 HKEY env = NULL;
6765 MSICOMPONENT *comp;
6766 MSIRECORD *uirow;
6767 int action = 0, found = 0;
6769 component = MSI_RecordGetString(rec, 4);
6770 comp = msi_get_loaded_component(package, component);
6771 if (!comp)
6772 return ERROR_SUCCESS;
6774 comp->Action = msi_get_component_action( package, comp );
6775 if (comp->Action != INSTALLSTATE_LOCAL)
6777 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6778 return ERROR_SUCCESS;
6780 name = MSI_RecordGetString(rec, 2);
6781 value = MSI_RecordGetString(rec, 3);
6783 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6785 res = env_parse_flags(&name, &value, &flags);
6786 if (res != ERROR_SUCCESS || !value)
6787 goto done;
6789 if (value)
6791 DWORD len = deformat_string( package, value, &deformatted );
6792 if (!deformatted)
6794 res = ERROR_OUTOFMEMORY;
6795 goto done;
6798 if (len)
6800 value = deformatted;
6801 if (flags & ENV_MOD_PREFIX)
6803 p = wcsrchr( value, ';' );
6804 len_value = p - value;
6806 else if (flags & ENV_MOD_APPEND)
6808 value = wcschr( value, ';' ) + 1;
6809 len_value = lstrlenW( value );
6811 else len_value = lstrlenW( value );
6813 else
6815 value = NULL;
6819 res = open_env_key( flags, &env );
6820 if (res != ERROR_SUCCESS)
6821 goto done;
6823 if (flags & ENV_MOD_MACHINE)
6824 action |= 0x20000000;
6826 size = 0;
6827 type = REG_SZ;
6828 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6829 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6830 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6831 goto done;
6833 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6835 action = 0x2;
6837 /* Nothing to do. */
6838 if (!value)
6840 res = ERROR_SUCCESS;
6841 goto done;
6843 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6844 newval = strdupW(value);
6845 if (!newval)
6847 res = ERROR_OUTOFMEMORY;
6848 goto done;
6851 else
6853 action = 0x1;
6855 /* Contrary to MSDN, +-variable to [~];path works */
6856 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6858 res = ERROR_SUCCESS;
6859 goto done;
6862 if (!(p = q = data = msi_alloc( size )))
6864 msi_free(deformatted);
6865 RegCloseKey(env);
6866 return ERROR_OUTOFMEMORY;
6869 res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)data, &size );
6870 if (res != ERROR_SUCCESS)
6871 goto done;
6873 if (flags & ENV_ACT_REMOVEMATCH && (!value || !wcscmp( data, value )))
6875 action = 0x4;
6876 res = RegDeleteValueW(env, name);
6877 if (res != ERROR_SUCCESS)
6878 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6879 goto done;
6882 for (;;)
6884 while (*q && *q != ';') q++;
6885 len = q - p;
6886 if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ) &&
6887 (!p[len] || p[len] == ';'))
6889 found = 1;
6890 break;
6892 if (!*q) break;
6893 p = ++q;
6896 if (found)
6898 TRACE("string already set\n");
6899 goto done;
6902 size = (len_value + 1 + lstrlenW( data ) + 1) * sizeof(WCHAR);
6903 if (!(p = newval = msi_alloc( size )))
6905 res = ERROR_OUTOFMEMORY;
6906 goto done;
6909 if (flags & ENV_MOD_PREFIX)
6911 memcpy( newval, value, len_value * sizeof(WCHAR) );
6912 newval[len_value] = ';';
6913 p = newval + len_value + 1;
6914 action |= 0x80000000;
6917 lstrcpyW( p, data );
6919 if (flags & ENV_MOD_APPEND)
6921 p += lstrlenW( data );
6922 *p++ = ';';
6923 memcpy( p, value, (len_value + 1) * sizeof(WCHAR) );
6924 action |= 0x40000000;
6927 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6928 res = RegSetValueExW( env, name, 0, type, (BYTE *)newval, size );
6929 if (res)
6931 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6934 done:
6935 uirow = MSI_CreateRecord( 3 );
6936 MSI_RecordSetStringW( uirow, 1, name );
6937 MSI_RecordSetStringW( uirow, 2, newval );
6938 MSI_RecordSetInteger( uirow, 3, action );
6939 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6940 msiobj_release( &uirow->hdr );
6942 if (env) RegCloseKey(env);
6943 msi_free(deformatted);
6944 msi_free(data);
6945 msi_free(newval);
6946 return res;
6949 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6951 MSIQUERY *view;
6952 UINT rc;
6954 if (package->script == SCRIPT_NONE)
6955 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteEnvironmentStrings");
6957 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Environment`", &view);
6958 if (rc != ERROR_SUCCESS)
6959 return ERROR_SUCCESS;
6961 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6962 msiobj_release(&view->hdr);
6963 return rc;
6966 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6968 MSIPACKAGE *package = param;
6969 LPCWSTR name, value, component;
6970 WCHAR *p, *q, *deformatted = NULL, *new_value = NULL;
6971 DWORD flags, type, size, len, len_value = 0, len_new_value;
6972 HKEY env = NULL;
6973 MSICOMPONENT *comp;
6974 MSIRECORD *uirow;
6975 int action = 0;
6976 LONG res;
6977 UINT r;
6979 component = MSI_RecordGetString( rec, 4 );
6980 comp = msi_get_loaded_component( package, component );
6981 if (!comp)
6982 return ERROR_SUCCESS;
6984 comp->Action = msi_get_component_action( package, comp );
6985 if (comp->Action != INSTALLSTATE_ABSENT)
6987 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6988 return ERROR_SUCCESS;
6990 name = MSI_RecordGetString( rec, 2 );
6991 value = MSI_RecordGetString( rec, 3 );
6993 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6995 r = env_parse_flags( &name, &value, &flags );
6996 if (r != ERROR_SUCCESS)
6997 return r;
6999 if (!(flags & ENV_ACT_REMOVE))
7001 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7002 return ERROR_SUCCESS;
7005 if (value)
7007 DWORD len = deformat_string( package, value, &deformatted );
7008 if (!deformatted)
7010 res = ERROR_OUTOFMEMORY;
7011 goto done;
7014 if (len)
7016 value = deformatted;
7017 if (flags & ENV_MOD_PREFIX)
7019 p = wcsrchr( value, ';' );
7020 len_value = p - value;
7022 else if (flags & ENV_MOD_APPEND)
7024 value = wcschr( value, ';' ) + 1;
7025 len_value = lstrlenW( value );
7027 else len_value = lstrlenW( value );
7029 else
7031 value = NULL;
7035 r = open_env_key( flags, &env );
7036 if (r != ERROR_SUCCESS)
7038 r = ERROR_SUCCESS;
7039 goto done;
7042 if (flags & ENV_MOD_MACHINE)
7043 action |= 0x20000000;
7045 size = 0;
7046 type = REG_SZ;
7047 res = RegQueryValueExW( env, name, NULL, &type, NULL, &size );
7048 if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ))
7049 goto done;
7051 if (!(new_value = msi_alloc( size ))) goto done;
7053 res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)new_value, &size );
7054 if (res != ERROR_SUCCESS)
7055 goto done;
7057 len_new_value = size / sizeof(WCHAR) - 1;
7058 p = q = new_value;
7059 for (;;)
7061 while (*q && *q != ';') q++;
7062 len = q - p;
7063 if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ))
7065 if (*q == ';') q++;
7066 memmove( p, q, (len_new_value - (q - new_value) + 1) * sizeof(WCHAR) );
7067 break;
7069 if (!*q) break;
7070 p = ++q;
7073 if (!new_value[0] || !value)
7075 TRACE("removing %s\n", debugstr_w(name));
7076 res = RegDeleteValueW( env, name );
7077 if (res != ERROR_SUCCESS)
7078 WARN( "failed to delete value %s (%ld)\n", debugstr_w(name), res );
7080 else
7082 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(new_value));
7083 size = (lstrlenW( new_value ) + 1) * sizeof(WCHAR);
7084 res = RegSetValueExW( env, name, 0, type, (BYTE *)new_value, size );
7085 if (res != ERROR_SUCCESS)
7086 WARN( "failed to set %s to %s (%ld)\n", debugstr_w(name), debugstr_w(new_value), res );
7089 done:
7090 uirow = MSI_CreateRecord( 3 );
7091 MSI_RecordSetStringW( uirow, 1, name );
7092 MSI_RecordSetStringW( uirow, 2, value );
7093 MSI_RecordSetInteger( uirow, 3, action );
7094 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
7095 msiobj_release( &uirow->hdr );
7097 if (env) RegCloseKey( env );
7098 msi_free( deformatted );
7099 msi_free( new_value );
7100 return r;
7103 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7105 MSIQUERY *view;
7106 UINT rc;
7108 if (package->script == SCRIPT_NONE)
7109 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveEnvironmentStrings");
7111 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Environment`", &view );
7112 if (rc != ERROR_SUCCESS)
7113 return ERROR_SUCCESS;
7115 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7116 msiobj_release( &view->hdr );
7117 return rc;
7120 UINT msi_validate_product_id( MSIPACKAGE *package )
7122 LPWSTR key, template, id;
7123 UINT r = ERROR_SUCCESS;
7125 id = msi_dup_property( package->db, L"ProductID" );
7126 if (id)
7128 msi_free( id );
7129 return ERROR_SUCCESS;
7131 template = msi_dup_property( package->db, L"PIDTemplate" );
7132 key = msi_dup_property( package->db, L"PIDKEY" );
7133 if (key && template)
7135 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7136 r = msi_set_property( package->db, L"ProductID", key, -1 );
7138 msi_free( template );
7139 msi_free( key );
7140 return r;
7143 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7145 return msi_validate_product_id( package );
7148 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7150 TRACE("\n");
7151 package->need_reboot_at_end = 1;
7152 return ERROR_SUCCESS;
7155 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7157 MSIRECORD *uirow;
7158 int space = msi_get_property_int( package->db, L"AVAILABLEFREEREG", 0 );
7160 TRACE("%p %d kilobytes\n", package, space);
7162 uirow = MSI_CreateRecord( 1 );
7163 MSI_RecordSetInteger( uirow, 1, space );
7164 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
7165 msiobj_release( &uirow->hdr );
7167 return ERROR_SUCCESS;
7170 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7172 TRACE("%p\n", package);
7174 msi_set_property( package->db, L"RollbackDisabled", L"1", -1 );
7175 return ERROR_SUCCESS;
7178 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7180 FIXME("%p\n", package);
7181 return ERROR_SUCCESS;
7184 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7186 MSIQUERY *view;
7187 UINT r;
7188 DWORD count;
7190 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDriver`", &view );
7191 if (r == ERROR_SUCCESS)
7193 count = 0;
7194 r = MSI_IterateRecords( view, &count, NULL, package );
7195 msiobj_release( &view->hdr );
7196 if (r != ERROR_SUCCESS)
7197 return r;
7198 if (count) FIXME( "ignored %lu rows in ODBCDriver table\n", count );
7200 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCTranslator`", &view );
7201 if (r == ERROR_SUCCESS)
7203 count = 0;
7204 r = MSI_IterateRecords( view, &count, NULL, package );
7205 msiobj_release( &view->hdr );
7206 if (r != ERROR_SUCCESS)
7207 return r;
7208 if (count) FIXME( "ignored %lu rows in ODBCTranslator table\n", count );
7210 return ERROR_SUCCESS;
7213 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7215 MSIPACKAGE *package = param;
7216 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7217 int attrs = MSI_RecordGetInteger( rec, 5 );
7218 UINT len = ARRAY_SIZE( L"msiexec /qn /i %s REMOVE=%s" );
7219 WCHAR *product, *features, *cmd;
7220 STARTUPINFOW si;
7221 PROCESS_INFORMATION info;
7222 BOOL ret;
7224 if (attrs & msidbUpgradeAttributesOnlyDetect) return ERROR_SUCCESS;
7225 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7227 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7229 len += lstrlenW( product );
7230 if (features)
7231 len += lstrlenW( features );
7232 else
7233 len += ARRAY_SIZE( L"ALL" );
7235 if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
7237 msi_free( product );
7238 msi_free( features );
7239 return ERROR_OUTOFMEMORY;
7241 swprintf( cmd, len, L"msiexec /qn /i %s REMOVE=%s", product, features ? features : L"ALL" );
7242 msi_free( product );
7243 msi_free( features );
7245 memset( &si, 0, sizeof(STARTUPINFOW) );
7246 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7247 msi_free( cmd );
7248 if (!ret) return GetLastError();
7249 CloseHandle( info.hThread );
7251 WaitForSingleObject( info.hProcess, INFINITE );
7252 CloseHandle( info.hProcess );
7253 return ERROR_SUCCESS;
7256 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7258 MSIQUERY *view;
7259 UINT r;
7261 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Upgrade`", &view );
7262 if (r == ERROR_SUCCESS)
7264 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7265 msiobj_release( &view->hdr );
7266 if (r != ERROR_SUCCESS)
7267 return r;
7269 return ERROR_SUCCESS;
7272 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7274 MSIPACKAGE *package = param;
7275 int attributes = MSI_RecordGetInteger( rec, 5 );
7277 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7279 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7280 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7281 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7282 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7283 HKEY hkey;
7284 UINT r;
7286 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7288 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7289 if (r != ERROR_SUCCESS)
7290 return ERROR_SUCCESS;
7292 else
7294 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7295 if (r != ERROR_SUCCESS)
7296 return ERROR_SUCCESS;
7298 RegCloseKey( hkey );
7300 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7301 debugstr_w(upgrade_code), debugstr_w(version_min),
7302 debugstr_w(version_max), debugstr_w(language));
7304 return ERROR_SUCCESS;
7307 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7309 MSIQUERY *view;
7310 UINT r;
7312 if (msi_get_property_int( package->db, L"Installed", 0 ))
7314 TRACE("product is installed, skipping action\n");
7315 return ERROR_SUCCESS;
7317 if (msi_get_property_int( package->db, L"Preselected", 0 ))
7319 TRACE("Preselected property is set, not migrating feature states\n");
7320 return ERROR_SUCCESS;
7322 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Upgrade`", &view );
7323 if (r == ERROR_SUCCESS)
7325 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7326 msiobj_release( &view->hdr );
7327 if (r != ERROR_SUCCESS)
7328 return r;
7330 return ERROR_SUCCESS;
7333 static BOOL msi_bind_image( MSIPACKAGE *package, const char *filename, const char *path )
7335 BOOL ret;
7336 msi_disable_fs_redirection( package );
7337 ret = BindImage( filename, path, NULL );
7338 msi_revert_fs_redirection( package );
7339 return ret;
7342 static void bind_image( MSIPACKAGE *package, const char *filename, const char *path )
7344 if (!msi_bind_image( package, filename, path ))
7346 WARN( "failed to bind image %lu\n", GetLastError() );
7350 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7352 UINT i;
7353 MSIFILE *file;
7354 MSIPACKAGE *package = param;
7355 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7356 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7357 char *filenameA, *pathA;
7358 WCHAR *pathW, **path_list;
7360 if (!(file = msi_get_loaded_file( package, key )))
7362 WARN("file %s not found\n", debugstr_w(key));
7363 return ERROR_SUCCESS;
7365 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7367 path_list = msi_split_string( paths, ';' );
7368 if (!path_list) bind_image( package, filenameA, NULL );
7369 else
7371 for (i = 0; path_list[i] && path_list[i][0]; i++)
7373 deformat_string( package, path_list[i], &pathW );
7374 if ((pathA = strdupWtoA( pathW )))
7376 bind_image( package, filenameA, pathA );
7377 msi_free( pathA );
7379 msi_free( pathW );
7382 msi_free( path_list );
7383 msi_free( filenameA );
7385 return ERROR_SUCCESS;
7388 static UINT ACTION_BindImage( MSIPACKAGE *package )
7390 MSIQUERY *view;
7391 UINT r;
7393 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `BindImage`", &view );
7394 if (r == ERROR_SUCCESS)
7396 MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7397 msiobj_release( &view->hdr );
7399 return ERROR_SUCCESS;
7402 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7404 MSIQUERY *view;
7405 DWORD count = 0;
7406 UINT r;
7408 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `%s`", table );
7409 if (r == ERROR_SUCCESS)
7411 r = MSI_IterateRecords(view, &count, NULL, package);
7412 msiobj_release(&view->hdr);
7413 if (r != ERROR_SUCCESS)
7414 return r;
7416 if (count) FIXME( "%s: ignored %lu rows from %s\n", action, count, debugstr_w(table) );
7417 return ERROR_SUCCESS;
7420 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7422 return msi_unimplemented_action_stub( package, "IsolateComponents", L"IsolateComponent" );
7425 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7427 return msi_unimplemented_action_stub( package, "RMCCPSearch", L"CCPSearch" );
7430 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7432 return msi_unimplemented_action_stub( package, "RegisterComPlus", L"Complus" );
7435 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7437 return msi_unimplemented_action_stub( package, "UnregisterComPlus", L"Complus" );
7440 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7442 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", L"SFPCatalog" );
7445 static const struct
7447 const WCHAR *action;
7448 const UINT description;
7449 const UINT template;
7450 UINT (*handler)(MSIPACKAGE *);
7451 const WCHAR *action_rollback;
7453 StandardActions[] =
7455 { L"AllocateRegistrySpace", IDS_DESC_ALLOCATEREGISTRYSPACE, IDS_TEMP_ALLOCATEREGISTRYSPACE, ACTION_AllocateRegistrySpace, NULL },
7456 { L"AppSearch", IDS_DESC_APPSEARCH, IDS_TEMP_APPSEARCH, ACTION_AppSearch, NULL },
7457 { L"BindImage", IDS_DESC_BINDIMAGE, IDS_TEMP_BINDIMAGE, ACTION_BindImage, NULL },
7458 { L"CCPSearch", IDS_DESC_CCPSEARCH, 0, ACTION_CCPSearch, NULL },
7459 { L"CostFinalize", IDS_DESC_COSTFINALIZE, 0, ACTION_CostFinalize, NULL },
7460 { L"CostInitialize", IDS_DESC_COSTINITIALIZE, 0, ACTION_CostInitialize, NULL },
7461 { L"CreateFolders", IDS_DESC_CREATEFOLDERS, IDS_TEMP_CREATEFOLDERS, ACTION_CreateFolders, L"RemoveFolders" },
7462 { L"CreateShortcuts", IDS_DESC_CREATESHORTCUTS, IDS_TEMP_CREATESHORTCUTS, ACTION_CreateShortcuts, L"RemoveShortcuts" },
7463 { L"DeleteServices", IDS_DESC_DELETESERVICES, IDS_TEMP_DELETESERVICES, ACTION_DeleteServices, L"InstallServices" },
7464 { L"DisableRollback", 0, 0, ACTION_DisableRollback, NULL },
7465 { L"DuplicateFiles", IDS_DESC_DUPLICATEFILES, IDS_TEMP_DUPLICATEFILES, ACTION_DuplicateFiles, L"RemoveDuplicateFiles" },
7466 { L"ExecuteAction", 0, 0, ACTION_ExecuteAction, NULL },
7467 { L"FileCost", IDS_DESC_FILECOST, 0, ACTION_FileCost, NULL },
7468 { L"FindRelatedProducts", IDS_DESC_FINDRELATEDPRODUCTS, IDS_TEMP_FINDRELATEDPRODUCTS, ACTION_FindRelatedProducts, NULL },
7469 { L"ForceReboot", 0, 0, ACTION_ForceReboot, NULL },
7470 { L"InstallAdminPackage", IDS_DESC_INSTALLADMINPACKAGE, IDS_TEMP_INSTALLADMINPACKAGE, ACTION_InstallAdminPackage, NULL },
7471 { L"InstallExecute", 0, 0, ACTION_InstallExecute, NULL },
7472 { L"InstallExecuteAgain", 0, 0, ACTION_InstallExecute, NULL },
7473 { L"InstallFiles", IDS_DESC_INSTALLFILES, IDS_TEMP_INSTALLFILES, ACTION_InstallFiles, L"RemoveFiles" },
7474 { L"InstallFinalize", 0, 0, ACTION_InstallFinalize, NULL },
7475 { L"InstallInitialize", 0, 0, ACTION_InstallInitialize, NULL },
7476 { L"InstallODBC", IDS_DESC_INSTALLODBC, 0, ACTION_InstallODBC, L"RemoveODBC" },
7477 { L"InstallServices", IDS_DESC_INSTALLSERVICES, IDS_TEMP_INSTALLSERVICES, ACTION_InstallServices, L"DeleteServices" },
7478 { L"InstallSFPCatalogFile", IDS_DESC_INSTALLSFPCATALOGFILE, IDS_TEMP_INSTALLSFPCATALOGFILE, ACTION_InstallSFPCatalogFile, NULL },
7479 { L"InstallValidate", IDS_DESC_INSTALLVALIDATE, 0, ACTION_InstallValidate, NULL },
7480 { L"IsolateComponents", 0, 0, ACTION_IsolateComponents, NULL },
7481 { L"LaunchConditions", IDS_DESC_LAUNCHCONDITIONS, 0, ACTION_LaunchConditions, NULL },
7482 { L"MigrateFeutureStates", IDS_DESC_MIGRATEFEATURESTATES, IDS_TEMP_MIGRATEFEATURESTATES, ACTION_MigrateFeatureStates, NULL },
7483 { L"MoveFiles", IDS_DESC_MOVEFILES, IDS_TEMP_MOVEFILES, ACTION_MoveFiles, NULL },
7484 { L"MsiPublishAssemblies", IDS_DESC_MSIPUBLISHASSEMBLIES, IDS_TEMP_MSIPUBLISHASSEMBLIES, ACTION_MsiPublishAssemblies, L"MsiUnpublishAssemblies" },
7485 { L"MsiUnpublishAssemblies", IDS_DESC_MSIUNPUBLISHASSEMBLIES, IDS_TEMP_MSIUNPUBLISHASSEMBLIES, ACTION_MsiUnpublishAssemblies, L"MsiPublishAssemblies" },
7486 { L"PatchFiles", IDS_DESC_PATCHFILES, IDS_TEMP_PATCHFILES, ACTION_PatchFiles, NULL },
7487 { L"ProcessComponents", IDS_DESC_PROCESSCOMPONENTS, 0, ACTION_ProcessComponents, L"ProcessComponents" },
7488 { L"PublishComponents", IDS_DESC_PUBLISHCOMPONENTS, IDS_TEMP_PUBLISHCOMPONENTS, ACTION_PublishComponents, L"UnpublishComponents" },
7489 { L"PublishFeatures", IDS_DESC_PUBLISHFEATURES, IDS_TEMP_PUBLISHFEATURES, ACTION_PublishFeatures, L"UnpublishFeatures" },
7490 { L"PublishProduct", IDS_DESC_PUBLISHPRODUCT, 0, ACTION_PublishProduct, L"UnpublishProduct" },
7491 { L"RegisterClassInfo", IDS_DESC_REGISTERCLASSINFO, IDS_TEMP_REGISTERCLASSINFO, ACTION_RegisterClassInfo, L"UnregisterClassInfo" },
7492 { L"RegisterComPlus", IDS_DESC_REGISTERCOMPLUS, IDS_TEMP_REGISTERCOMPLUS, ACTION_RegisterComPlus, L"UnregisterComPlus" },
7493 { L"RegisterExtensionInfo", IDS_DESC_REGISTEREXTENSIONINFO, 0, ACTION_RegisterExtensionInfo, L"UnregisterExtensionInfo" },
7494 { L"RegisterFonts", IDS_DESC_REGISTERFONTS, IDS_TEMP_REGISTERFONTS, ACTION_RegisterFonts, L"UnregisterFonts" },
7495 { L"RegisterMIMEInfo", IDS_DESC_REGISTERMIMEINFO, IDS_TEMP_REGISTERMIMEINFO, ACTION_RegisterMIMEInfo, L"UnregisterMIMEInfo" },
7496 { L"RegisterProduct", IDS_DESC_REGISTERPRODUCT, 0, ACTION_RegisterProduct, NULL },
7497 { L"RegisterProgIdInfo", IDS_DESC_REGISTERPROGIDINFO, IDS_TEMP_REGISTERPROGIDINFO, ACTION_RegisterProgIdInfo, L"UnregisterProgIdInfo" },
7498 { L"RegisterTypeLibraries", IDS_DESC_REGISTERTYPELIBRARIES, IDS_TEMP_REGISTERTYPELIBRARIES, ACTION_RegisterTypeLibraries, L"UnregisterTypeLibraries" },
7499 { L"RegisterUser", IDS_DESC_REGISTERUSER, 0, ACTION_RegisterUser, NULL },
7500 { L"RemoveDuplicateFiles", IDS_DESC_REMOVEDUPLICATEFILES, IDS_TEMP_REMOVEDUPLICATEFILES, ACTION_RemoveDuplicateFiles, L"DuplicateFiles" },
7501 { L"RemoveEnvironmentStrings", IDS_DESC_REMOVEENVIRONMENTSTRINGS, IDS_TEMP_REMOVEENVIRONMENTSTRINGS, ACTION_RemoveEnvironmentStrings, L"WriteEnvironmentStrings" },
7502 { L"RemoveExistingProducts", IDS_DESC_REMOVEEXISTINGPRODUCTS, IDS_TEMP_REMOVEEXISTINGPRODUCTS, ACTION_RemoveExistingProducts, NULL },
7503 { L"RemoveFiles", IDS_DESC_REMOVEFILES, IDS_TEMP_REMOVEFILES, ACTION_RemoveFiles, L"InstallFiles" },
7504 { L"RemoveFolders", IDS_DESC_REMOVEFOLDERS, IDS_TEMP_REMOVEFOLDERS, ACTION_RemoveFolders, L"CreateFolders" },
7505 { L"RemoveIniValues", IDS_DESC_REMOVEINIVALUES, IDS_TEMP_REMOVEINIVALUES, ACTION_RemoveIniValues, L"WriteIniValues" },
7506 { L"RemoveODBC", IDS_DESC_REMOVEODBC, 0, ACTION_RemoveODBC, L"InstallODBC" },
7507 { L"RemoveRegistryValues", IDS_DESC_REMOVEREGISTRYVALUES, IDS_TEMP_REMOVEREGISTRYVALUES, ACTION_RemoveRegistryValues, L"WriteRegistryValues" },
7508 { L"RemoveShortcuts", IDS_DESC_REMOVESHORTCUTS, IDS_TEMP_REMOVESHORTCUTS, ACTION_RemoveShortcuts, L"CreateShortcuts" },
7509 { L"ResolveSource", 0, 0, ACTION_ResolveSource, NULL },
7510 { L"RMCCPSearch", IDS_DESC_RMCCPSEARCH, 0, ACTION_RMCCPSearch, NULL },
7511 { L"ScheduleReboot", 0, 0, ACTION_ScheduleReboot, NULL },
7512 { L"SelfRegModules", IDS_DESC_SELFREGMODULES, IDS_TEMP_SELFREGMODULES, ACTION_SelfRegModules, L"SelfUnregModules" },
7513 { L"SelfUnregModules", IDS_DESC_SELFUNREGMODULES, IDS_TEMP_SELFUNREGMODULES, ACTION_SelfUnregModules, L"SelfRegModules" },
7514 { L"SetODBCFolders", IDS_DESC_SETODBCFOLDERS, 0, ACTION_SetODBCFolders, NULL },
7515 { L"StartServices", IDS_DESC_STARTSERVICES, IDS_TEMP_STARTSERVICES, ACTION_StartServices, L"StopServices" },
7516 { L"StopServices", IDS_DESC_STOPSERVICES, IDS_TEMP_STOPSERVICES, ACTION_StopServices, L"StartServices" },
7517 { L"UnpublishComponents", IDS_DESC_UNPUBLISHCOMPONENTS, IDS_TEMP_UNPUBLISHCOMPONENTS, ACTION_UnpublishComponents, L"PublishComponents" },
7518 { L"UnpublishFeatures", IDS_DESC_UNPUBLISHFEATURES, IDS_TEMP_UNPUBLISHFEATURES, ACTION_UnpublishFeatures, L"PublishFeatures" },
7519 { L"UnpublishProduct", IDS_DESC_UNPUBLISHPRODUCT, 0, ACTION_UnpublishProduct, NULL }, /* for rollback only */
7520 { L"UnregisterClassInfo", IDS_DESC_UNREGISTERCLASSINFO, IDS_TEMP_UNREGISTERCLASSINFO, ACTION_UnregisterClassInfo, L"RegisterClassInfo" },
7521 { L"UnregisterComPlus", IDS_DESC_UNREGISTERCOMPLUS, IDS_TEMP_UNREGISTERCOMPLUS, ACTION_UnregisterComPlus, L"RegisterComPlus" },
7522 { L"UnregisterExtensionInfo", IDS_DESC_UNREGISTEREXTENSIONINFO, IDS_TEMP_UNREGISTEREXTENSIONINFO, ACTION_UnregisterExtensionInfo, L"RegisterExtensionInfo" },
7523 { L"UnregisterFonts", IDS_DESC_UNREGISTERFONTS, IDS_TEMP_UNREGISTERFONTS, ACTION_UnregisterFonts, L"RegisterFonts" },
7524 { L"UnregisterMIMEInfo", IDS_DESC_UNREGISTERMIMEINFO, IDS_TEMP_UNREGISTERMIMEINFO, ACTION_UnregisterMIMEInfo, L"RegisterMIMEInfo" },
7525 { L"UnregisterProgIdInfo", IDS_DESC_UNREGISTERPROGIDINFO, IDS_TEMP_UNREGISTERPROGIDINFO, ACTION_UnregisterProgIdInfo, L"RegisterProgIdInfo" },
7526 { L"UnregisterTypeLibraries", IDS_DESC_UNREGISTERTYPELIBRARIES, IDS_TEMP_UNREGISTERTYPELIBRARIES, ACTION_UnregisterTypeLibraries, L"RegisterTypeLibraries" },
7527 { L"ValidateProductID", 0, 0, ACTION_ValidateProductID, NULL },
7528 { L"WriteEnvironmentStrings", IDS_DESC_WRITEENVIRONMENTSTRINGS, IDS_TEMP_WRITEENVIRONMENTSTRINGS, ACTION_WriteEnvironmentStrings, L"RemoveEnvironmentStrings" },
7529 { L"WriteIniValues", IDS_DESC_WRITEINIVALUES, IDS_TEMP_WRITEINIVALUES, ACTION_WriteIniValues, L"RemoveIniValues" },
7530 { L"WriteRegistryValues", IDS_DESC_WRITEREGISTRYVALUES, IDS_TEMP_WRITEREGISTRYVALUES, ACTION_WriteRegistryValues, L"RemoveRegistryValues" },
7531 { L"INSTALL", 0, 0, ACTION_INSTALL, NULL },
7532 { 0 }
7535 static UINT ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action)
7537 UINT rc = ERROR_FUNCTION_NOT_CALLED;
7538 UINT i;
7540 i = 0;
7541 while (StandardActions[i].action != NULL)
7543 if (!wcscmp( StandardActions[i].action, action ))
7545 WCHAR description[100] = {0}, template[100] = {0};
7547 if (StandardActions[i].description != 0)
7548 LoadStringW(msi_hInstance, StandardActions[i].description, (LPWSTR)&description, 100);
7549 if (StandardActions[i].template != 0)
7550 LoadStringW(msi_hInstance, StandardActions[i].template, (LPWSTR)&template, 100);
7552 ui_actionstart(package, action, description, template);
7553 if (StandardActions[i].handler)
7555 ui_actioninfo( package, action, TRUE, 0 );
7556 rc = StandardActions[i].handler( package );
7557 ui_actioninfo( package, action, FALSE, !rc );
7559 if (StandardActions[i].action_rollback && !package->need_rollback)
7561 TRACE("scheduling rollback action\n");
7562 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7565 else
7567 FIXME("unhandled standard action %s\n", debugstr_w(action));
7568 rc = ERROR_SUCCESS;
7570 break;
7572 i++;
7575 return rc;
7578 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
7580 UINT rc;
7582 TRACE("Performing action (%s)\n", debugstr_w(action));
7584 package->action_progress_increment = 0;
7585 rc = ACTION_HandleStandardAction(package, action);
7587 if (rc == ERROR_FUNCTION_NOT_CALLED)
7588 rc = ACTION_HandleCustomAction(package, action);
7590 if (rc == ERROR_FUNCTION_NOT_CALLED)
7591 WARN("unhandled msi action %s\n", debugstr_w(action));
7593 return rc;
7596 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7598 UINT rc = ERROR_SUCCESS;
7599 MSIRECORD *row;
7601 if (needs_ui_sequence(package))
7602 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `InstallUISequence` WHERE `Sequence` = %d", seq);
7603 else
7604 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `InstallExecuteSequence` WHERE `Sequence` = %d", seq);
7606 if (row)
7608 LPCWSTR action, cond;
7610 TRACE("Running the actions\n");
7612 /* check conditions */
7613 cond = MSI_RecordGetString(row, 2);
7615 /* this is a hack to skip errors in the condition code */
7616 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7618 msiobj_release(&row->hdr);
7619 return ERROR_SUCCESS;
7622 action = MSI_RecordGetString(row, 1);
7623 if (!action)
7625 ERR("failed to fetch action\n");
7626 msiobj_release(&row->hdr);
7627 return ERROR_FUNCTION_FAILED;
7630 rc = ACTION_PerformAction(package, action);
7632 msiobj_release(&row->hdr);
7635 return rc;
7638 /****************************************************
7639 * TOP level entry points
7640 *****************************************************/
7642 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7643 LPCWSTR szCommandLine )
7645 WCHAR *reinstall = NULL, *productcode, *action;
7646 UINT rc;
7647 DWORD len = 0;
7649 if (szPackagePath)
7651 LPWSTR p, dir;
7652 LPCWSTR file;
7654 dir = strdupW(szPackagePath);
7655 p = wcsrchr(dir, '\\');
7656 if (p)
7658 *(++p) = 0;
7659 file = szPackagePath + (p - dir);
7661 else
7663 msi_free(dir);
7664 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7665 GetCurrentDirectoryW(MAX_PATH, dir);
7666 lstrcatW(dir, L"\\");
7667 file = szPackagePath;
7670 msi_free( package->PackagePath );
7671 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7672 if (!package->PackagePath)
7674 msi_free(dir);
7675 return ERROR_OUTOFMEMORY;
7678 lstrcpyW(package->PackagePath, dir);
7679 lstrcatW(package->PackagePath, file);
7680 msi_free(dir);
7682 msi_set_sourcedir_props(package, FALSE);
7685 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7686 if (rc != ERROR_SUCCESS)
7687 return rc;
7689 msi_apply_transforms( package );
7690 msi_apply_patches( package );
7692 if (msi_get_property( package->db, L"ACTION", NULL, &len ))
7693 msi_set_property( package->db, L"ACTION", L"INSTALL", -1 );
7694 action = msi_dup_property( package->db, L"ACTION" );
7695 CharUpperW(action);
7697 msi_set_original_database_property( package->db, szPackagePath );
7698 msi_parse_command_line( package, szCommandLine, FALSE );
7699 msi_adjust_privilege_properties( package );
7700 msi_set_context( package );
7702 productcode = msi_dup_property( package->db, L"ProductCode" );
7703 if (wcsicmp( productcode, package->ProductCode ))
7705 TRACE( "product code changed %s -> %s\n", debugstr_w(package->ProductCode), debugstr_w(productcode) );
7706 msi_free( package->ProductCode );
7707 package->ProductCode = productcode;
7709 else msi_free( productcode );
7711 if (msi_get_property_int( package->db, L"DISABLEROLLBACK", 0 ))
7713 TRACE("disabling rollback\n");
7714 msi_set_property( package->db, L"RollbackDisabled", L"1", -1 );
7717 rc = ACTION_PerformAction(package, action);
7719 /* process the ending type action */
7720 if (rc == ERROR_SUCCESS)
7721 ACTION_PerformActionSequence(package, -1);
7722 else if (rc == ERROR_INSTALL_USEREXIT)
7723 ACTION_PerformActionSequence(package, -2);
7724 else if (rc == ERROR_INSTALL_SUSPEND)
7725 ACTION_PerformActionSequence(package, -4);
7726 else /* failed */
7728 ACTION_PerformActionSequence(package, -3);
7729 if (!msi_get_property_int( package->db, L"RollbackDisabled", 0 ))
7731 package->need_rollback = TRUE;
7735 /* finish up running custom actions */
7736 ACTION_FinishCustomActions(package);
7738 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, L"REINSTALL" )))
7740 WARN("installation failed, running rollback script\n");
7741 execute_script( package, SCRIPT_ROLLBACK );
7743 msi_free( reinstall );
7744 msi_free( action );
7746 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7747 return ERROR_SUCCESS_REBOOT_REQUIRED;
7749 return rc;