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
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
191 sprintfW(message,template_s,timet,action);
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
221 case state_whitespace:
231 if (in_quotes && p[1] != '\"') count--;
247 if (in_quotes) count--;
251 state = state_whitespace;
252 if (!count) goto done;
257 if (!count) in_quotes = 0;
268 if (in_quotes && p[1] != '\"') count--;
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
279 if (!count) in_quotes = 0;
288 if (!ignore) *out++ = *p;
292 if (!len) *value = 0;
299 static void remove_quotes( WCHAR *str )
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
321 return ERROR_SUCCESS;
326 while (*ptr == ' ') ptr++;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
338 if (!preserve_case) struprW( prop );
341 while (*ptr2 == ' ') ptr2++;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
348 WARN("unbalanced quotes\n");
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val, -1 );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
372 LPWSTR p, *ret = NULL;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
395 for( count = 0; (ret[count] = p); count++ )
397 p = strchrW( p, sep );
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 db = msi_dup_property( package->db, szOriginalDatabase );
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
448 p = strrchrW( db, '/' );
452 return ERROR_SUCCESS;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source, -1 );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source, -1 );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
543 rc = ACTION_ForceReboot( package );
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property( package->db, szSourceDir, NULL, -1 );
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
736 if (!(slash = strrchrW( new_path, '\\' )))
741 len = slash - new_path;
743 if (!msi_create_full_path( new_path ))
748 new_path[len] = '\\';
750 msi_free( new_path );
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
814 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
815 return INSTALLSTATE_UNKNOWN;
817 return comp->ActionRequest;
820 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
822 if (package->need_rollback) return feature->Installed;
823 return feature->ActionRequest;
826 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
828 MSIPACKAGE *package = param;
829 LPCWSTR dir, component, full_path;
834 component = MSI_RecordGetString(row, 2);
836 return ERROR_SUCCESS;
838 comp = msi_get_loaded_component(package, component);
840 return ERROR_SUCCESS;
842 comp->Action = msi_get_component_action( package, comp );
843 if (comp->Action != INSTALLSTATE_LOCAL)
845 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
846 return ERROR_SUCCESS;
849 dir = MSI_RecordGetString(row,1);
852 ERR("Unable to get folder id\n");
853 return ERROR_SUCCESS;
856 uirow = MSI_CreateRecord(1);
857 MSI_RecordSetStringW(uirow, 1, dir);
858 msi_ui_actiondata(package, szCreateFolders, uirow);
859 msiobj_release(&uirow->hdr);
861 full_path = msi_get_target_folder( package, dir );
864 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
865 return ERROR_SUCCESS;
867 TRACE("folder is %s\n", debugstr_w(full_path));
869 folder = msi_get_loaded_folder( package, dir );
870 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
871 folder->State = FOLDER_STATE_CREATED;
872 return ERROR_SUCCESS;
875 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
877 static const WCHAR query[] = {
878 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
879 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
883 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
884 if (rc != ERROR_SUCCESS)
885 return ERROR_SUCCESS;
887 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
888 msiobj_release(&view->hdr);
892 static void remove_persistent_folder( MSIFOLDER *folder )
896 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
898 remove_persistent_folder( fl->folder );
900 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
902 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
906 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
908 MSIPACKAGE *package = param;
909 LPCWSTR dir, component, full_path;
914 component = MSI_RecordGetString(row, 2);
916 return ERROR_SUCCESS;
918 comp = msi_get_loaded_component(package, component);
920 return ERROR_SUCCESS;
922 comp->Action = msi_get_component_action( package, comp );
923 if (comp->Action != INSTALLSTATE_ABSENT)
925 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
926 return ERROR_SUCCESS;
929 dir = MSI_RecordGetString( row, 1 );
932 ERR("Unable to get folder id\n");
933 return ERROR_SUCCESS;
936 full_path = msi_get_target_folder( package, dir );
939 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
940 return ERROR_SUCCESS;
942 TRACE("folder is %s\n", debugstr_w(full_path));
944 uirow = MSI_CreateRecord( 1 );
945 MSI_RecordSetStringW( uirow, 1, dir );
946 msi_ui_actiondata( package, szRemoveFolders, uirow );
947 msiobj_release( &uirow->hdr );
949 folder = msi_get_loaded_folder( package, dir );
950 remove_persistent_folder( folder );
951 return ERROR_SUCCESS;
954 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
956 static const WCHAR query[] = {
957 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
958 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
962 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
963 if (rc != ERROR_SUCCESS)
964 return ERROR_SUCCESS;
966 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
967 msiobj_release( &view->hdr );
971 static UINT load_component( MSIRECORD *row, LPVOID param )
973 MSIPACKAGE *package = param;
976 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
978 return ERROR_FUNCTION_FAILED;
980 list_add_tail( &package->components, &comp->entry );
982 /* fill in the data */
983 comp->Component = msi_dup_record_field( row, 1 );
985 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
987 comp->ComponentId = msi_dup_record_field( row, 2 );
988 comp->Directory = msi_dup_record_field( row, 3 );
989 comp->Attributes = MSI_RecordGetInteger(row,4);
990 comp->Condition = msi_dup_record_field( row, 5 );
991 comp->KeyPath = msi_dup_record_field( row, 6 );
993 comp->Installed = INSTALLSTATE_UNKNOWN;
994 comp->Action = INSTALLSTATE_UNKNOWN;
995 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
997 comp->assembly = msi_load_assembly( package, comp );
998 return ERROR_SUCCESS;
1001 UINT msi_load_all_components( MSIPACKAGE *package )
1003 static const WCHAR query[] = {
1004 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1005 '`','C','o','m','p','o','n','e','n','t','`',0};
1009 if (!list_empty(&package->components))
1010 return ERROR_SUCCESS;
1012 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1013 if (r != ERROR_SUCCESS)
1016 if (!msi_init_assembly_caches( package ))
1018 ERR("can't initialize assembly caches\n");
1019 msiobj_release( &view->hdr );
1020 return ERROR_FUNCTION_FAILED;
1023 r = MSI_IterateRecords(view, NULL, load_component, package);
1024 msiobj_release(&view->hdr);
1029 MSIPACKAGE *package;
1030 MSIFEATURE *feature;
1033 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1037 cl = msi_alloc( sizeof (*cl) );
1039 return ERROR_NOT_ENOUGH_MEMORY;
1040 cl->component = comp;
1041 list_add_tail( &feature->Components, &cl->entry );
1043 return ERROR_SUCCESS;
1046 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1050 fl = msi_alloc( sizeof(*fl) );
1052 return ERROR_NOT_ENOUGH_MEMORY;
1053 fl->feature = child;
1054 list_add_tail( &parent->Children, &fl->entry );
1056 return ERROR_SUCCESS;
1059 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1061 _ilfs* ilfs = param;
1065 component = MSI_RecordGetString(row,1);
1067 /* check to see if the component is already loaded */
1068 comp = msi_get_loaded_component( ilfs->package, component );
1071 WARN("ignoring unknown component %s\n", debugstr_w(component));
1072 return ERROR_SUCCESS;
1074 add_feature_component( ilfs->feature, comp );
1075 comp->Enabled = TRUE;
1077 return ERROR_SUCCESS;
1080 static UINT load_feature(MSIRECORD * row, LPVOID param)
1082 static const WCHAR query[] = {
1083 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1084 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1085 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1086 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1087 MSIPACKAGE *package = param;
1088 MSIFEATURE *feature;
1093 /* fill in the data */
1095 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1097 return ERROR_NOT_ENOUGH_MEMORY;
1099 list_init( &feature->Children );
1100 list_init( &feature->Components );
1102 feature->Feature = msi_dup_record_field( row, 1 );
1104 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1106 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1107 feature->Title = msi_dup_record_field( row, 3 );
1108 feature->Description = msi_dup_record_field( row, 4 );
1110 if (!MSI_RecordIsNull(row,5))
1111 feature->Display = MSI_RecordGetInteger(row,5);
1113 feature->Level= MSI_RecordGetInteger(row,6);
1114 feature->Directory = msi_dup_record_field( row, 7 );
1115 feature->Attributes = MSI_RecordGetInteger(row,8);
1117 feature->Installed = INSTALLSTATE_UNKNOWN;
1118 feature->Action = INSTALLSTATE_UNKNOWN;
1119 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1121 list_add_tail( &package->features, &feature->entry );
1123 /* load feature components */
1125 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1126 if (rc != ERROR_SUCCESS)
1127 return ERROR_SUCCESS;
1129 ilfs.package = package;
1130 ilfs.feature = feature;
1132 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1133 msiobj_release(&view->hdr);
1137 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1139 MSIPACKAGE *package = param;
1140 MSIFEATURE *parent, *child;
1142 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1144 return ERROR_FUNCTION_FAILED;
1146 if (!child->Feature_Parent)
1147 return ERROR_SUCCESS;
1149 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1151 return ERROR_FUNCTION_FAILED;
1153 add_feature_child( parent, child );
1154 return ERROR_SUCCESS;
1157 UINT msi_load_all_features( MSIPACKAGE *package )
1159 static const WCHAR query[] = {
1160 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1161 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1162 '`','D','i','s','p','l','a','y','`',0};
1166 if (!list_empty(&package->features))
1167 return ERROR_SUCCESS;
1169 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1170 if (r != ERROR_SUCCESS)
1173 r = MSI_IterateRecords( view, NULL, load_feature, package );
1174 if (r != ERROR_SUCCESS)
1176 msiobj_release( &view->hdr );
1179 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1180 msiobj_release( &view->hdr );
1184 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1195 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1197 static const WCHAR query[] = {
1198 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1199 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1200 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1201 MSIQUERY *view = NULL;
1202 MSIRECORD *row = NULL;
1205 TRACE("%s\n", debugstr_w(file->File));
1207 r = MSI_OpenQuery(package->db, &view, query, file->File);
1208 if (r != ERROR_SUCCESS)
1211 r = MSI_ViewExecute(view, NULL);
1212 if (r != ERROR_SUCCESS)
1215 r = MSI_ViewFetch(view, &row);
1216 if (r != ERROR_SUCCESS)
1219 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1220 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1221 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1222 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1223 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1226 if (view) msiobj_release(&view->hdr);
1227 if (row) msiobj_release(&row->hdr);
1231 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1234 static const WCHAR query[] = {
1235 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1236 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1237 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1239 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1242 WARN("query failed\n");
1243 return ERROR_FUNCTION_FAILED;
1246 file->disk_id = MSI_RecordGetInteger( row, 1 );
1247 msiobj_release( &row->hdr );
1248 return ERROR_SUCCESS;
1251 static UINT load_file(MSIRECORD *row, LPVOID param)
1253 MSIPACKAGE* package = param;
1257 /* fill in the data */
1259 file = msi_alloc_zero( sizeof (MSIFILE) );
1261 return ERROR_NOT_ENOUGH_MEMORY;
1263 file->File = msi_dup_record_field( row, 1 );
1265 component = MSI_RecordGetString( row, 2 );
1266 file->Component = msi_get_loaded_component( package, component );
1268 if (!file->Component)
1270 WARN("Component not found: %s\n", debugstr_w(component));
1271 msi_free(file->File);
1273 return ERROR_SUCCESS;
1276 file->FileName = msi_dup_record_field( row, 3 );
1277 msi_reduce_to_long_filename( file->FileName );
1279 file->ShortName = msi_dup_record_field( row, 3 );
1280 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1282 file->FileSize = MSI_RecordGetInteger( row, 4 );
1283 file->Version = msi_dup_record_field( row, 5 );
1284 file->Language = msi_dup_record_field( row, 6 );
1285 file->Attributes = MSI_RecordGetInteger( row, 7 );
1286 file->Sequence = MSI_RecordGetInteger( row, 8 );
1288 file->state = msifs_invalid;
1290 /* if the compressed bits are not set in the file attributes,
1291 * then read the information from the package word count property
1293 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1295 file->IsCompressed = FALSE;
1297 else if (file->Attributes &
1298 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1300 file->IsCompressed = TRUE;
1302 else if (file->Attributes & msidbFileAttributesNoncompressed)
1304 file->IsCompressed = FALSE;
1308 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1311 load_file_hash(package, file);
1312 load_file_disk_id(package, file);
1314 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1316 list_add_tail( &package->files, &file->entry );
1318 return ERROR_SUCCESS;
1321 static UINT load_all_files(MSIPACKAGE *package)
1323 static const WCHAR query[] = {
1324 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1325 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1326 '`','S','e','q','u','e','n','c','e','`', 0};
1330 if (!list_empty(&package->files))
1331 return ERROR_SUCCESS;
1333 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1334 if (rc != ERROR_SUCCESS)
1335 return ERROR_SUCCESS;
1337 rc = MSI_IterateRecords(view, NULL, load_file, package);
1338 msiobj_release(&view->hdr);
1342 static UINT load_media( MSIRECORD *row, LPVOID param )
1344 MSIPACKAGE *package = param;
1345 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1346 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1348 /* FIXME: load external cabinets and directory sources too */
1349 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1350 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1351 return ERROR_SUCCESS;
1354 static UINT load_all_media( MSIPACKAGE *package )
1356 static const WCHAR query[] = {
1357 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1358 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1359 '`','D','i','s','k','I','d','`',0};
1363 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1364 if (r != ERROR_SUCCESS)
1365 return ERROR_SUCCESS;
1367 r = MSI_IterateRecords( view, NULL, load_media, package );
1368 msiobj_release( &view->hdr );
1372 static UINT load_patch(MSIRECORD *row, LPVOID param)
1374 MSIPACKAGE *package = param;
1375 MSIFILEPATCH *patch;
1378 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1380 return ERROR_NOT_ENOUGH_MEMORY;
1382 file_key = msi_dup_record_field( row, 1 );
1383 patch->File = msi_get_loaded_file( package, file_key );
1388 ERR("Failed to find target for patch in File table\n");
1390 return ERROR_FUNCTION_FAILED;
1393 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1395 /* FIXME: The database should be properly transformed */
1396 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1398 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1399 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1400 patch->IsApplied = FALSE;
1403 * Header field - for patch validation.
1404 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1407 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1409 list_add_tail( &package->filepatches, &patch->entry );
1411 return ERROR_SUCCESS;
1414 static UINT load_all_patches(MSIPACKAGE *package)
1416 static const WCHAR query[] = {
1417 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1418 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1419 '`','S','e','q','u','e','n','c','e','`',0};
1423 if (!list_empty(&package->filepatches))
1424 return ERROR_SUCCESS;
1426 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1427 if (rc != ERROR_SUCCESS)
1428 return ERROR_SUCCESS;
1430 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1431 msiobj_release(&view->hdr);
1435 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1437 static const WCHAR query[] = {
1438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1439 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1440 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1443 folder->persistent = FALSE;
1444 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1446 if (!MSI_ViewExecute( view, NULL ))
1449 if (!MSI_ViewFetch( view, &rec ))
1451 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1452 folder->persistent = TRUE;
1453 msiobj_release( &rec->hdr );
1456 msiobj_release( &view->hdr );
1458 return ERROR_SUCCESS;
1461 static UINT load_folder( MSIRECORD *row, LPVOID param )
1463 MSIPACKAGE *package = param;
1464 static WCHAR szEmpty[] = { 0 };
1465 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1468 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1469 list_init( &folder->children );
1470 folder->Directory = msi_dup_record_field( row, 1 );
1471 folder->Parent = msi_dup_record_field( row, 2 );
1472 p = msi_dup_record_field(row, 3);
1474 TRACE("%s\n", debugstr_w(folder->Directory));
1476 /* split src and target dir */
1478 src_short = folder_split_path( p, ':' );
1480 /* split the long and short paths */
1481 tgt_long = folder_split_path( tgt_short, '|' );
1482 src_long = folder_split_path( src_short, '|' );
1484 /* check for no-op dirs */
1485 if (tgt_short && !strcmpW( szDot, tgt_short ))
1486 tgt_short = szEmpty;
1487 if (src_short && !strcmpW( szDot, src_short ))
1488 src_short = szEmpty;
1491 tgt_long = tgt_short;
1494 src_short = tgt_short;
1495 src_long = tgt_long;
1499 src_long = src_short;
1501 /* FIXME: use the target short path too */
1502 folder->TargetDefault = strdupW(tgt_long);
1503 folder->SourceShortPath = strdupW(src_short);
1504 folder->SourceLongPath = strdupW(src_long);
1507 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1508 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1509 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1511 load_folder_persistence( package, folder );
1513 list_add_tail( &package->folders, &folder->entry );
1514 return ERROR_SUCCESS;
1517 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1521 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1523 list_add_tail( &parent->children, &fl->entry );
1524 return ERROR_SUCCESS;
1527 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1529 MSIPACKAGE *package = param;
1530 MSIFOLDER *parent, *child;
1532 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1533 return ERROR_FUNCTION_FAILED;
1535 if (!child->Parent) return ERROR_SUCCESS;
1537 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1538 return ERROR_FUNCTION_FAILED;
1540 return add_folder_child( parent, child );
1543 static UINT load_all_folders( MSIPACKAGE *package )
1545 static const WCHAR query[] = {
1546 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1547 '`','D','i','r','e','c','t','o','r','y','`',0};
1551 if (!list_empty(&package->folders))
1552 return ERROR_SUCCESS;
1554 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1555 if (r != ERROR_SUCCESS)
1558 r = MSI_IterateRecords( view, NULL, load_folder, package );
1559 if (r != ERROR_SUCCESS)
1561 msiobj_release( &view->hdr );
1564 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1565 msiobj_release( &view->hdr );
1569 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1571 msi_set_property( package->db, szCostingComplete, szZero, -1 );
1572 msi_set_property( package->db, szRootDrive, szCRoot, -1 );
1574 load_all_folders( package );
1575 msi_load_all_components( package );
1576 msi_load_all_features( package );
1577 load_all_files( package );
1578 load_all_patches( package );
1579 load_all_media( package );
1581 return ERROR_SUCCESS;
1584 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1586 const WCHAR *action = package->script->Actions[script][index];
1587 ui_actionstart( package, action );
1588 TRACE("executing %s\n", debugstr_w(action));
1589 return ACTION_PerformAction( package, action, script );
1592 static UINT execute_script( MSIPACKAGE *package, UINT script )
1594 UINT i, rc = ERROR_SUCCESS;
1596 TRACE("executing script %u\n", script);
1598 if (!package->script)
1600 ERR("no script!\n");
1601 return ERROR_FUNCTION_FAILED;
1603 if (script == SCRIPT_ROLLBACK)
1605 for (i = package->script->ActionCount[script]; i > 0; i--)
1607 rc = execute_script_action( package, script, i - 1 );
1608 if (rc != ERROR_SUCCESS) break;
1613 for (i = 0; i < package->script->ActionCount[script]; i++)
1615 rc = execute_script_action( package, script, i );
1616 if (rc != ERROR_SUCCESS) break;
1619 msi_free_action_script(package, script);
1623 static UINT ACTION_FileCost(MSIPACKAGE *package)
1625 return ERROR_SUCCESS;
1628 static void get_client_counts( MSIPACKAGE *package )
1633 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1635 if (!comp->ComponentId) continue;
1637 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE ) &&
1638 MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ))
1640 comp->num_clients = 0;
1643 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
1644 NULL, NULL, NULL, NULL );
1645 RegCloseKey( hkey );
1649 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1654 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1656 if (!comp->ComponentId) continue;
1658 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1659 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1661 if (r == ERROR_SUCCESS) continue;
1663 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1664 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1666 if (r == ERROR_SUCCESS) continue;
1668 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1669 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1671 if (r == ERROR_SUCCESS) continue;
1673 comp->Installed = INSTALLSTATE_ABSENT;
1677 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1679 MSIFEATURE *feature;
1681 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1685 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1686 feature->Installed = INSTALLSTATE_ABSENT;
1688 feature->Installed = state;
1692 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1694 return (feature->Level > 0 && feature->Level <= level);
1697 static BOOL process_state_property(MSIPACKAGE* package, int level,
1698 LPCWSTR property, INSTALLSTATE state)
1701 MSIFEATURE *feature;
1703 override = msi_dup_property( package->db, property );
1707 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1709 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1712 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1714 if (!strcmpiW( override, szAll ))
1716 if (feature->Installed != state)
1718 feature->Action = state;
1719 feature->ActionRequest = state;
1724 LPWSTR ptr = override;
1725 LPWSTR ptr2 = strchrW(override,',');
1729 int len = ptr2 - ptr;
1731 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1732 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1734 if (feature->Installed != state)
1736 feature->Action = state;
1737 feature->ActionRequest = state;
1744 ptr2 = strchrW(ptr,',');
1755 static BOOL process_overrides( MSIPACKAGE *package, int level )
1757 static const WCHAR szAddLocal[] =
1758 {'A','D','D','L','O','C','A','L',0};
1759 static const WCHAR szAddSource[] =
1760 {'A','D','D','S','O','U','R','C','E',0};
1761 static const WCHAR szAdvertise[] =
1762 {'A','D','V','E','R','T','I','S','E',0};
1765 /* all these activation/deactivation things happen in order and things
1766 * later on the list override things earlier on the list.
1768 * 0 INSTALLLEVEL processing
1781 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1782 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1783 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1784 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1785 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1788 msi_set_property( package->db, szPreselected, szOne, -1 );
1793 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1796 MSICOMPONENT* component;
1797 MSIFEATURE *feature;
1799 TRACE("Checking Install Level\n");
1801 level = msi_get_property_int(package->db, szInstallLevel, 1);
1803 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1805 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1807 if (!is_feature_selected( feature, level )) continue;
1809 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1811 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1813 feature->Action = INSTALLSTATE_SOURCE;
1814 feature->ActionRequest = INSTALLSTATE_SOURCE;
1816 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1818 feature->Action = INSTALLSTATE_ADVERTISED;
1819 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1823 feature->Action = INSTALLSTATE_LOCAL;
1824 feature->ActionRequest = INSTALLSTATE_LOCAL;
1828 /* disable child features of unselected parent or follow parent */
1829 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1833 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1835 if (!is_feature_selected( feature, level ))
1837 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1838 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1840 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1842 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1843 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1844 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1845 fl->feature->Action = feature->Action;
1846 fl->feature->ActionRequest = feature->ActionRequest;
1851 else /* preselected */
1853 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1855 if (!is_feature_selected( feature, level )) continue;
1857 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1859 if (feature->Installed == INSTALLSTATE_ABSENT)
1861 feature->Action = INSTALLSTATE_UNKNOWN;
1862 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1866 feature->Action = feature->Installed;
1867 feature->ActionRequest = feature->Installed;
1871 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1875 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1877 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1878 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1880 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1881 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1882 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1883 fl->feature->Action = feature->Action;
1884 fl->feature->ActionRequest = feature->ActionRequest;
1890 /* now we want to set component state based based on feature state */
1891 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1895 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1896 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1897 feature->ActionRequest, feature->Action);
1899 if (!is_feature_selected( feature, level )) continue;
1901 /* features with components that have compressed files are made local */
1902 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1904 if (cl->component->ForceLocalState &&
1905 feature->ActionRequest == INSTALLSTATE_SOURCE)
1907 feature->Action = INSTALLSTATE_LOCAL;
1908 feature->ActionRequest = INSTALLSTATE_LOCAL;
1913 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1915 component = cl->component;
1917 switch (feature->ActionRequest)
1919 case INSTALLSTATE_ABSENT:
1920 component->anyAbsent = 1;
1922 case INSTALLSTATE_ADVERTISED:
1923 component->hasAdvertiseFeature = 1;
1925 case INSTALLSTATE_SOURCE:
1926 component->hasSourceFeature = 1;
1928 case INSTALLSTATE_LOCAL:
1929 component->hasLocalFeature = 1;
1931 case INSTALLSTATE_DEFAULT:
1932 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1933 component->hasAdvertiseFeature = 1;
1934 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1935 component->hasSourceFeature = 1;
1937 component->hasLocalFeature = 1;
1945 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1947 /* check if it's local or source */
1948 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1949 (component->hasLocalFeature || component->hasSourceFeature))
1951 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1952 !component->ForceLocalState)
1954 component->Action = INSTALLSTATE_SOURCE;
1955 component->ActionRequest = INSTALLSTATE_SOURCE;
1959 component->Action = INSTALLSTATE_LOCAL;
1960 component->ActionRequest = INSTALLSTATE_LOCAL;
1965 /* if any feature is local, the component must be local too */
1966 if (component->hasLocalFeature)
1968 component->Action = INSTALLSTATE_LOCAL;
1969 component->ActionRequest = INSTALLSTATE_LOCAL;
1972 if (component->hasSourceFeature)
1974 component->Action = INSTALLSTATE_SOURCE;
1975 component->ActionRequest = INSTALLSTATE_SOURCE;
1978 if (component->hasAdvertiseFeature)
1980 component->Action = INSTALLSTATE_ADVERTISED;
1981 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1984 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1985 if (component->anyAbsent &&
1986 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1988 component->Action = INSTALLSTATE_ABSENT;
1989 component->ActionRequest = INSTALLSTATE_ABSENT;
1993 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1995 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1997 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1998 component->Action = INSTALLSTATE_LOCAL;
1999 component->ActionRequest = INSTALLSTATE_LOCAL;
2002 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2003 component->Installed == INSTALLSTATE_SOURCE &&
2004 component->hasSourceFeature)
2006 component->Action = INSTALLSTATE_UNKNOWN;
2007 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2010 TRACE("component %s (installed %d request %d action %d)\n",
2011 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2013 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
2014 component->num_clients++;
2015 else if (component->Action == INSTALLSTATE_ABSENT)
2016 component->num_clients--;
2019 return ERROR_SUCCESS;
2022 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2024 MSIPACKAGE *package = param;
2026 MSIFEATURE *feature;
2028 name = MSI_RecordGetString( row, 1 );
2030 feature = msi_get_loaded_feature( package, name );
2032 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2036 Condition = MSI_RecordGetString(row,3);
2038 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2040 int level = MSI_RecordGetInteger(row,2);
2041 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2042 feature->Level = level;
2045 return ERROR_SUCCESS;
2048 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2050 static const WCHAR name[] = {'\\',0};
2051 VS_FIXEDFILEINFO *ptr, *ret;
2053 DWORD versize, handle;
2056 versize = GetFileVersionInfoSizeW( filename, &handle );
2060 version = msi_alloc( versize );
2064 GetFileVersionInfoW( filename, 0, versize, version );
2066 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2068 msi_free( version );
2072 ret = msi_alloc( sz );
2073 memcpy( ret, ptr, sz );
2075 msi_free( version );
2079 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2083 msi_parse_version_string( version, &ms, &ls );
2085 if (fi->dwFileVersionMS > ms) return 1;
2086 else if (fi->dwFileVersionMS < ms) return -1;
2087 else if (fi->dwFileVersionLS > ls) return 1;
2088 else if (fi->dwFileVersionLS < ls) return -1;
2092 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2096 msi_parse_version_string( ver1, &ms1, NULL );
2097 msi_parse_version_string( ver2, &ms2, NULL );
2099 if (ms1 > ms2) return 1;
2100 else if (ms1 < ms2) return -1;
2104 DWORD msi_get_disk_file_size( LPCWSTR filename )
2109 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2110 if (file == INVALID_HANDLE_VALUE)
2111 return INVALID_FILE_SIZE;
2113 size = GetFileSize( file, NULL );
2114 TRACE("size is %u\n", size);
2115 CloseHandle( file );
2119 BOOL msi_file_hash_matches( MSIFILE *file )
2122 MSIFILEHASHINFO hash;
2124 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2125 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2126 if (r != ERROR_SUCCESS)
2129 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2132 static WCHAR *get_temp_dir( void )
2135 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2137 GetTempPathW( MAX_PATH, tmp );
2140 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2141 if (CreateDirectoryW( dir, NULL )) break;
2143 return strdupW( dir );
2147 * msi_build_directory_name()
2149 * This function is to save messing round with directory names
2150 * It handles adding backslashes between path segments,
2151 * and can add \ at the end of the directory name if told to.
2153 * It takes a variable number of arguments.
2154 * It always allocates a new string for the result, so make sure
2155 * to free the return value when finished with it.
2157 * The first arg is the number of path segments that follow.
2158 * The arguments following count are a list of path segments.
2159 * A path segment may be NULL.
2161 * Path segments will be added with a \ separating them.
2162 * A \ will not be added after the last segment, however if the
2163 * last segment is NULL, then the last character will be a \
2165 WCHAR *msi_build_directory_name( DWORD count, ... )
2171 va_start( va, count );
2172 for (i = 0; i < count; i++)
2174 const WCHAR *str = va_arg( va, const WCHAR * );
2175 if (str) sz += strlenW( str ) + 1;
2179 dir = msi_alloc( sz * sizeof(WCHAR) );
2182 va_start( va, count );
2183 for (i = 0; i < count; i++)
2185 const WCHAR *str = va_arg( va, const WCHAR * );
2187 strcatW( dir, str );
2188 if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2194 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2196 MSIASSEMBLY *assembly = file->Component->assembly;
2198 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2200 msi_free( file->TargetPath );
2201 if (assembly && !assembly->application)
2203 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2204 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2205 msi_track_tempfile( package, file->TargetPath );
2209 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2210 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2213 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2216 static UINT calculate_file_cost( MSIPACKAGE *package )
2218 VS_FIXEDFILEINFO *file_version;
2219 WCHAR *font_version;
2222 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2224 MSICOMPONENT *comp = file->Component;
2227 if (!comp->Enabled) continue;
2229 if (file->IsCompressed)
2230 comp->ForceLocalState = TRUE;
2232 set_target_path( package, file );
2234 if ((comp->assembly && !comp->assembly->installed) ||
2235 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2237 comp->Cost += file->FileSize;
2240 file_size = msi_get_disk_file_size( file->TargetPath );
2244 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2246 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2248 comp->Cost += file->FileSize - file_size;
2250 msi_free( file_version );
2253 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2255 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2257 comp->Cost += file->FileSize - file_size;
2259 msi_free( font_version );
2263 if (file_size != file->FileSize)
2265 comp->Cost += file->FileSize - file_size;
2268 return ERROR_SUCCESS;
2271 WCHAR *msi_normalize_path( const WCHAR *in )
2273 const WCHAR *p = in;
2275 int n, len = strlenW( in ) + 2;
2277 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2282 /* copy until the end of the string or a space */
2283 while (*p != ' ' && (*q = *p))
2286 /* reduce many backslashes to one */
2287 if (*p != '\\' || *q != '\\')
2291 /* quit at the end of the string */
2295 /* count the number of spaces */
2300 /* if it's leading or trailing space, skip it */
2301 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2303 else /* copy n spaces */
2304 while (n && (*q++ = *p++)) n--;
2306 while (q - ret > 0 && q[-1] == ' ') q--;
2307 if (q - ret > 0 && q[-1] != '\\')
2315 static WCHAR *get_install_location( MSIPACKAGE *package )
2320 if (!package->ProductCode) return NULL;
2321 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ))
2323 path = msi_reg_get_val_str( hkey, szInstallLocation );
2324 RegCloseKey( hkey );
2328 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2331 MSIFOLDER *folder, *parent, *child;
2332 WCHAR *path, *normalized_path;
2334 TRACE("resolving %s\n", debugstr_w(name));
2336 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2338 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2340 if (!(path = get_install_location( package )) &&
2341 (!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))))
2343 path = msi_dup_property( package->db, szRootDrive );
2346 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2348 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2350 parent = msi_get_loaded_folder( package, folder->Parent );
2351 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2354 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2356 normalized_path = msi_normalize_path( path );
2358 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2360 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2361 msi_free( normalized_path );
2364 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2365 msi_free( folder->ResolvedTarget );
2366 folder->ResolvedTarget = normalized_path;
2368 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2371 msi_resolve_target_folder( package, child->Directory, load_prop );
2373 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2376 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2378 static const WCHAR query[] = {
2379 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2380 '`','C','o','n','d','i','t','i','o','n','`',0};
2381 static const WCHAR szOutOfDiskSpace[] = {
2382 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2388 TRACE("Building directory properties\n");
2389 msi_resolve_target_folder( package, szTargetDir, TRUE );
2391 TRACE("Evaluating component conditions\n");
2392 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2394 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2396 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2397 comp->Enabled = FALSE;
2400 comp->Enabled = TRUE;
2402 get_client_counts( package );
2404 /* read components states from the registry */
2405 ACTION_GetComponentInstallStates(package);
2406 ACTION_GetFeatureInstallStates(package);
2408 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2410 TRACE("Evaluating feature conditions\n");
2412 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2413 if (rc == ERROR_SUCCESS)
2415 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2416 msiobj_release( &view->hdr );
2417 if (rc != ERROR_SUCCESS)
2422 TRACE("Calculating file cost\n");
2423 calculate_file_cost( package );
2425 msi_set_property( package->db, szCostingComplete, szOne, -1 );
2426 /* set default run level if not set */
2427 level = msi_dup_property( package->db, szInstallLevel );
2429 msi_set_property( package->db, szInstallLevel, szOne, -1 );
2432 /* FIXME: check volume disk space */
2433 msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
2435 return MSI_SetFeatureStates(package);
2438 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, DWORD *size)
2444 data = (LPSTR)strdupW(szEmpty);
2445 *size = sizeof(szEmpty);
2449 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2455 LPWSTR deformated = NULL;
2458 deformat_string(package, &value[2], &deformated);
2460 /* binary value type */
2464 *size = (strlenW(ptr)/2)+1;
2466 *size = strlenW(ptr)/2;
2468 data = msi_alloc(*size);
2474 /* if uneven pad with a zero in front */
2480 data[count] = (BYTE)strtol(byte,NULL,0);
2482 TRACE("Uneven byte count\n");
2490 data[count] = (BYTE)strtol(byte,NULL,0);
2493 msi_free(deformated);
2495 TRACE("Data %i bytes(%i)\n",*size,count);
2502 deformat_string(package, &value[1], &deformated);
2505 *size = sizeof(DWORD);
2506 data = msi_alloc(*size);
2512 if ( (*p < '0') || (*p > '9') )
2518 if (deformated[0] == '-')
2521 TRACE("DWORD %i\n",*(LPDWORD)data);
2523 msi_free(deformated);
2528 static const WCHAR szMulti[] = {'[','~',']',0};
2537 *type=REG_EXPAND_SZ;
2545 if (strstrW(value, szMulti))
2546 *type = REG_MULTI_SZ;
2548 /* remove initial delimiter */
2549 if (!strncmpW(value, szMulti, 3))
2552 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2554 /* add double NULL terminator */
2555 if (*type == REG_MULTI_SZ)
2557 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2558 data = msi_realloc_zero(data, *size);
2564 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2571 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2573 *root_key = HKEY_LOCAL_MACHINE;
2578 *root_key = HKEY_CURRENT_USER;
2583 *root_key = HKEY_CLASSES_ROOT;
2587 *root_key = HKEY_CURRENT_USER;
2591 *root_key = HKEY_LOCAL_MACHINE;
2595 *root_key = HKEY_USERS;
2599 ERR("Unknown root %i\n", root);
2606 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2608 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2609 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2611 if ((is_64bit || is_wow64) &&
2612 !(comp->Attributes & msidbComponentAttributes64bit) &&
2613 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2618 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2619 if (!(path_32node = msi_alloc( size ))) return NULL;
2621 memcpy( path_32node, path, len * sizeof(WCHAR) );
2622 strcpyW( path_32node + len, szWow6432Node );
2623 strcatW( path_32node, szBackSlash );
2624 strcatW( path_32node, path + len );
2627 return strdupW( path );
2630 static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
2632 REGSAM access = KEY_ALL_ACCESS;
2633 WCHAR *subkey, *p, *q;
2634 HKEY hkey, ret = NULL;
2637 if (is_wow64) access |= KEY_WOW64_64KEY;
2639 if (!(subkey = strdupW( path ))) return NULL;
2641 if ((q = strchrW( p, '\\' ))) *q = 0;
2643 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2645 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2648 TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
2654 ret = open_key( hkey, q + 1, create );
2655 RegCloseKey( hkey );
2662 static BOOL is_special_entry( const WCHAR *name )
2664 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2667 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2669 MSIPACKAGE *package = param;
2671 HKEY root_key, hkey;
2673 LPWSTR deformated, uikey, keypath;
2674 LPCWSTR szRoot, component, name, key;
2678 BOOL check_first = FALSE;
2681 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2683 component = MSI_RecordGetString(row, 6);
2684 comp = msi_get_loaded_component(package,component);
2686 return ERROR_SUCCESS;
2688 comp->Action = msi_get_component_action( package, comp );
2689 if (comp->Action != INSTALLSTATE_LOCAL)
2691 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2692 return ERROR_SUCCESS;
2695 name = MSI_RecordGetString(row, 4);
2696 if( MSI_RecordIsNull(row,5) && name )
2698 /* null values can have special meanings */
2699 if (name[0]=='-' && name[1] == 0)
2700 return ERROR_SUCCESS;
2701 if ((name[0] == '+' || name[0] == '*') && !name[1])
2705 root = MSI_RecordGetInteger(row,2);
2706 key = MSI_RecordGetString(row, 3);
2708 szRoot = get_root_key( package, root, &root_key );
2710 return ERROR_SUCCESS;
2712 deformat_string(package, key , &deformated);
2713 size = strlenW(deformated) + strlenW(szRoot) + 1;
2714 uikey = msi_alloc(size*sizeof(WCHAR));
2715 strcpyW(uikey,szRoot);
2716 strcatW(uikey,deformated);
2718 keypath = get_keypath( comp, root_key, deformated );
2719 msi_free( deformated );
2720 if (!(hkey = open_key( root_key, keypath, TRUE )))
2722 ERR("Could not create key %s\n", debugstr_w(keypath));
2725 return ERROR_FUNCTION_FAILED;
2727 value = parse_value(package, MSI_RecordGetString(row, 5), &type, &size);
2728 deformat_string(package, name, &deformated);
2730 if (!is_special_entry( name ))
2734 TRACE("Setting value %s of %s\n", debugstr_w(deformated),
2736 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2741 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2742 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2744 TRACE("value %s of %s checked already exists\n", debugstr_w(deformated),
2749 TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated),
2751 if (deformated || size)
2752 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2758 uirow = MSI_CreateRecord(3);
2759 MSI_RecordSetStringW(uirow,2,deformated);
2760 MSI_RecordSetStringW(uirow,1,uikey);
2761 if (type == REG_SZ || type == REG_EXPAND_SZ)
2762 MSI_RecordSetStringW(uirow, 3, (LPWSTR)value);
2763 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2764 msiobj_release( &uirow->hdr );
2767 msi_free(deformated);
2771 return ERROR_SUCCESS;
2774 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2776 static const WCHAR query[] = {
2777 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2778 '`','R','e','g','i','s','t','r','y','`',0};
2782 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2783 if (rc != ERROR_SUCCESS)
2784 return ERROR_SUCCESS;
2786 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2787 msiobj_release(&view->hdr);
2791 static void delete_key( HKEY root, const WCHAR *path )
2798 if (is_wow64) access |= KEY_WOW64_64KEY;
2800 if (!(subkey = strdupW( path ))) return;
2803 if ((p = strrchrW( subkey, '\\' ))) *p = 0;
2804 hkey = open_key( root, subkey, FALSE );
2807 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2809 res = RegDeleteKeyExW( root, subkey, access, 0 );
2812 TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
2815 if (p && p[1]) RegCloseKey( hkey );
2821 static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
2825 DWORD num_subkeys, num_values;
2827 if ((hkey = open_key( root, path, FALSE )))
2829 if ((res = RegDeleteValueW( hkey, value )))
2830 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2832 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2833 NULL, NULL, NULL, NULL );
2834 RegCloseKey( hkey );
2835 if (!res && !num_subkeys && !num_values)
2837 TRACE("removing empty key %s\n", debugstr_w(path));
2838 delete_key( root, path );
2843 static void delete_tree( HKEY root, const WCHAR *path )
2848 if (!(hkey = open_key( root, path, FALSE ))) return;
2849 res = RegDeleteTreeW( hkey, NULL );
2850 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
2851 delete_key( root, path );
2852 RegCloseKey( hkey );
2855 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2857 MSIPACKAGE *package = param;
2858 LPCWSTR component, name, key_str, root_key_str;
2859 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2862 BOOL delete_key = FALSE;
2867 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2869 component = MSI_RecordGetString( row, 6 );
2870 comp = msi_get_loaded_component( package, component );
2872 return ERROR_SUCCESS;
2874 comp->Action = msi_get_component_action( package, comp );
2875 if (comp->Action != INSTALLSTATE_ABSENT)
2877 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2878 return ERROR_SUCCESS;
2881 name = MSI_RecordGetString( row, 4 );
2882 if (MSI_RecordIsNull( row, 5 ) && name )
2884 if (name[0] == '+' && !name[1])
2885 return ERROR_SUCCESS;
2886 if ((name[0] == '-' || name[0] == '*') && !name[1])
2893 root = MSI_RecordGetInteger( row, 2 );
2894 key_str = MSI_RecordGetString( row, 3 );
2896 root_key_str = get_root_key( package, root, &hkey_root );
2898 return ERROR_SUCCESS;
2900 deformat_string( package, key_str, &deformated_key );
2901 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2902 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2903 strcpyW( ui_key_str, root_key_str );
2904 strcatW( ui_key_str, deformated_key );
2906 deformat_string( package, name, &deformated_name );
2908 keypath = get_keypath( comp, hkey_root, deformated_key );
2909 msi_free( deformated_key );
2910 if (delete_key) delete_tree( hkey_root, keypath );
2911 else delete_value( hkey_root, keypath, deformated_name );
2912 msi_free( keypath );
2914 uirow = MSI_CreateRecord( 2 );
2915 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2916 MSI_RecordSetStringW( uirow, 2, deformated_name );
2917 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2918 msiobj_release( &uirow->hdr );
2920 msi_free( ui_key_str );
2921 msi_free( deformated_name );
2922 return ERROR_SUCCESS;
2925 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2927 MSIPACKAGE *package = param;
2928 LPCWSTR component, name, key_str, root_key_str;
2929 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2932 BOOL delete_key = FALSE;
2937 component = MSI_RecordGetString( row, 5 );
2938 comp = msi_get_loaded_component( package, component );
2940 return ERROR_SUCCESS;
2942 comp->Action = msi_get_component_action( package, comp );
2943 if (comp->Action != INSTALLSTATE_LOCAL)
2945 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2946 return ERROR_SUCCESS;
2949 if ((name = MSI_RecordGetString( row, 4 )))
2951 if (name[0] == '-' && !name[1])
2958 root = MSI_RecordGetInteger( row, 2 );
2959 key_str = MSI_RecordGetString( row, 3 );
2961 root_key_str = get_root_key( package, root, &hkey_root );
2963 return ERROR_SUCCESS;
2965 deformat_string( package, key_str, &deformated_key );
2966 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2967 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2968 strcpyW( ui_key_str, root_key_str );
2969 strcatW( ui_key_str, deformated_key );
2971 deformat_string( package, name, &deformated_name );
2973 keypath = get_keypath( comp, hkey_root, deformated_key );
2974 msi_free( deformated_key );
2975 if (delete_key) delete_tree( hkey_root, keypath );
2976 else delete_value( hkey_root, keypath, deformated_name );
2977 msi_free( keypath );
2979 uirow = MSI_CreateRecord( 2 );
2980 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2981 MSI_RecordSetStringW( uirow, 2, deformated_name );
2982 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2983 msiobj_release( &uirow->hdr );
2985 msi_free( ui_key_str );
2986 msi_free( deformated_name );
2987 return ERROR_SUCCESS;
2990 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2992 static const WCHAR registry_query[] = {
2993 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2994 '`','R','e','g','i','s','t','r','y','`',0};
2995 static const WCHAR remove_registry_query[] = {
2996 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2997 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
3001 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3002 if (rc == ERROR_SUCCESS)
3004 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3005 msiobj_release( &view->hdr );
3006 if (rc != ERROR_SUCCESS)
3009 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3010 if (rc == ERROR_SUCCESS)
3012 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3013 msiobj_release( &view->hdr );
3014 if (rc != ERROR_SUCCESS)
3017 return ERROR_SUCCESS;
3020 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3022 package->script->CurrentlyScripting = TRUE;
3024 return ERROR_SUCCESS;
3028 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3030 static const WCHAR query[]= {
3031 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3032 '`','R','e','g','i','s','t','r','y','`',0};
3034 DWORD total = 0, count = 0;
3036 MSIFEATURE *feature;
3040 TRACE("InstallValidate\n");
3042 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3043 if (rc == ERROR_SUCCESS)
3045 rc = MSI_IterateRecords( view, &count, NULL, package );
3046 msiobj_release( &view->hdr );
3047 if (rc != ERROR_SUCCESS)
3049 total += count * REG_PROGRESS_VALUE;
3051 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3052 total += COMPONENT_PROGRESS_VALUE;
3054 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3055 total += file->FileSize;
3057 msi_ui_progress( package, 0, total, 0, 0 );
3059 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3061 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3062 debugstr_w(feature->Feature), feature->Installed,
3063 feature->ActionRequest, feature->Action);
3065 return ERROR_SUCCESS;
3068 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3070 MSIPACKAGE* package = param;
3071 LPCWSTR cond = NULL;
3072 LPCWSTR message = NULL;
3075 static const WCHAR title[]=
3076 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3078 cond = MSI_RecordGetString(row,1);
3080 r = MSI_EvaluateConditionW(package,cond);
3081 if (r == MSICONDITION_FALSE)
3083 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3086 message = MSI_RecordGetString(row,2);
3087 deformat_string(package,message,&deformated);
3088 MessageBoxW(NULL,deformated,title,MB_OK);
3089 msi_free(deformated);
3092 return ERROR_INSTALL_FAILURE;
3095 return ERROR_SUCCESS;
3098 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3100 static const WCHAR query[] = {
3101 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3102 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3106 TRACE("Checking launch conditions\n");
3108 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3109 if (rc != ERROR_SUCCESS)
3110 return ERROR_SUCCESS;
3112 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3113 msiobj_release(&view->hdr);
3117 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3121 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3123 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3125 static const WCHAR query[] = {
3126 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3127 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3128 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3129 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3130 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3133 LPWSTR deformated, buffer, deformated_name;
3136 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3140 root = MSI_RecordGetInteger(row,2);
3141 key = MSI_RecordGetString(row, 3);
3142 name = MSI_RecordGetString(row, 4);
3143 deformat_string(package, key , &deformated);
3144 deformat_string(package, name, &deformated_name);
3146 len = strlenW(deformated) + 6;
3147 if (deformated_name)
3148 len+=strlenW(deformated_name);
3150 buffer = msi_alloc( len *sizeof(WCHAR));
3152 if (deformated_name)
3153 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3155 sprintfW(buffer,fmt,root,deformated);
3157 msi_free(deformated);
3158 msi_free(deformated_name);
3159 msiobj_release(&row->hdr);
3163 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3165 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3170 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3173 return strdupW( file->TargetPath );
3178 static HKEY openSharedDLLsKey(void)
3181 static const WCHAR path[] =
3182 {'S','o','f','t','w','a','r','e','\\',
3183 'M','i','c','r','o','s','o','f','t','\\',
3184 'W','i','n','d','o','w','s','\\',
3185 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3186 'S','h','a','r','e','d','D','L','L','s',0};
3188 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3192 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3197 DWORD sz = sizeof(count);
3200 hkey = openSharedDLLsKey();
3201 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3202 if (rc != ERROR_SUCCESS)
3208 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3212 hkey = openSharedDLLsKey();
3214 msi_reg_set_val_dword( hkey, path, count );
3216 RegDeleteValueW(hkey,path);
3221 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3223 MSIFEATURE *feature;
3227 /* only refcount DLLs */
3228 if (comp->KeyPath == NULL ||
3230 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3231 comp->Attributes & msidbComponentAttributesODBCDataSource)
3235 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3236 write = (count > 0);
3238 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3242 /* increment counts */
3243 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3247 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3250 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3252 if ( cl->component == comp )
3257 /* decrement counts */
3258 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3262 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3265 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3267 if ( cl->component == comp )
3272 /* ref count all the files in the component */
3277 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3279 if (file->Component == comp)
3280 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3284 /* add a count for permanent */
3285 if (comp->Attributes & msidbComponentAttributesPermanent)
3288 comp->RefCount = count;
3291 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3294 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3298 const WCHAR prefixW[] = {'<','\\',0};
3299 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3300 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3304 strcpyW( keypath, prefixW );
3305 strcatW( keypath, comp->assembly->display_name );
3309 return resolve_keypath( package, comp );
3312 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3314 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3321 squash_guid(package->ProductCode,squished_pc);
3322 msi_set_sourcedir_props(package, FALSE);
3324 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3327 INSTALLSTATE action;
3329 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3330 if (!comp->ComponentId)
3333 squash_guid( comp->ComponentId, squished_cc );
3334 msi_free( comp->FullKeypath );
3335 comp->FullKeypath = build_full_keypath( package, comp );
3337 ACTION_RefCountComponent( package, comp );
3339 if (package->need_rollback) action = comp->Installed;
3340 else action = comp->ActionRequest;
3342 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3343 debugstr_w(comp->Component), debugstr_w(squished_cc),
3344 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3346 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3348 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3349 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3351 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3353 if (rc != ERROR_SUCCESS)
3356 if (comp->Attributes & msidbComponentAttributesPermanent)
3358 static const WCHAR szPermKey[] =
3359 { '0','0','0','0','0','0','0','0','0','0','0','0',
3360 '0','0','0','0','0','0','0','0','0','0','0','0',
3361 '0','0','0','0','0','0','0','0',0 };
3363 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3365 if (action == INSTALLSTATE_LOCAL)
3366 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3372 WCHAR source[MAX_PATH];
3373 WCHAR base[MAX_PATH];
3376 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3377 static const WCHAR query[] = {
3378 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3379 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3380 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3381 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3382 '`','D','i','s','k','I','d','`',0};
3384 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3387 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3388 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3389 ptr2 = strrchrW(source, '\\') + 1;
3390 msiobj_release(&row->hdr);
3392 lstrcpyW(base, package->PackagePath);
3393 ptr = strrchrW(base, '\\');
3396 sourcepath = msi_resolve_file_source(package, file);
3397 ptr = sourcepath + lstrlenW(base);
3398 lstrcpyW(ptr2, ptr);
3399 msi_free(sourcepath);
3401 msi_reg_set_val_str(hkey, squished_pc, source);
3405 else if (action == INSTALLSTATE_ABSENT)
3407 if (comp->num_clients <= 0)
3409 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3410 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid );
3412 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
3417 uirow = MSI_CreateRecord(3);
3418 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3419 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3420 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3421 msi_ui_actiondata( package, szProcessComponents, uirow );
3422 msiobj_release( &uirow->hdr );
3424 return ERROR_SUCCESS;
3435 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3436 LPWSTR lpszName, LONG_PTR lParam)
3439 typelib_struct *tl_struct = (typelib_struct*) lParam;
3440 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3444 if (!IS_INTRESOURCE(lpszName))
3446 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3450 sz = strlenW(tl_struct->source)+4;
3451 sz *= sizeof(WCHAR);
3453 if ((INT_PTR)lpszName == 1)
3454 tl_struct->path = strdupW(tl_struct->source);
3457 tl_struct->path = msi_alloc(sz);
3458 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3461 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3462 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3465 msi_free(tl_struct->path);
3466 tl_struct->path = NULL;
3471 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3472 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3474 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3478 msi_free(tl_struct->path);
3479 tl_struct->path = NULL;
3481 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3482 ITypeLib_Release(tl_struct->ptLib);
3487 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3489 MSIPACKAGE* package = param;
3493 typelib_struct tl_struct;
3498 component = MSI_RecordGetString(row,3);
3499 comp = msi_get_loaded_component(package,component);
3501 return ERROR_SUCCESS;
3503 comp->Action = msi_get_component_action( package, comp );
3504 if (comp->Action != INSTALLSTATE_LOCAL)
3506 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3507 return ERROR_SUCCESS;
3510 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3512 TRACE("component has no key path\n");
3513 return ERROR_SUCCESS;
3515 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3517 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3521 guid = MSI_RecordGetString(row,1);
3522 CLSIDFromString( guid, &tl_struct.clsid);
3523 tl_struct.source = strdupW( file->TargetPath );
3524 tl_struct.path = NULL;
3526 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3527 (LONG_PTR)&tl_struct);
3531 LPCWSTR helpid, help_path = NULL;
3534 helpid = MSI_RecordGetString(row,6);
3536 if (helpid) help_path = msi_get_target_folder( package, helpid );
3537 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3540 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3542 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3544 ITypeLib_Release(tl_struct.ptLib);
3545 msi_free(tl_struct.path);
3547 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3549 FreeLibrary(module);
3550 msi_free(tl_struct.source);
3554 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3557 ERR("Failed to load type library: %08x\n", hr);
3558 return ERROR_INSTALL_FAILURE;
3561 ITypeLib_Release(tlib);
3564 return ERROR_SUCCESS;
3567 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3569 static const WCHAR query[] = {
3570 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3571 '`','T','y','p','e','L','i','b','`',0};
3575 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3576 if (rc != ERROR_SUCCESS)
3577 return ERROR_SUCCESS;
3579 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3580 msiobj_release(&view->hdr);
3584 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3586 MSIPACKAGE *package = param;
3587 LPCWSTR component, guid;
3595 component = MSI_RecordGetString( row, 3 );
3596 comp = msi_get_loaded_component( package, component );
3598 return ERROR_SUCCESS;
3600 comp->Action = msi_get_component_action( package, comp );
3601 if (comp->Action != INSTALLSTATE_ABSENT)
3603 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3604 return ERROR_SUCCESS;
3606 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3608 guid = MSI_RecordGetString( row, 1 );
3609 CLSIDFromString( guid, &libid );
3610 version = MSI_RecordGetInteger( row, 4 );
3611 language = MSI_RecordGetInteger( row, 2 );
3614 syskind = SYS_WIN64;
3616 syskind = SYS_WIN32;
3619 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3622 WARN("Failed to unregister typelib: %08x\n", hr);
3625 return ERROR_SUCCESS;
3628 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3630 static const WCHAR query[] = {
3631 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3632 '`','T','y','p','e','L','i','b','`',0};
3636 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3637 if (rc != ERROR_SUCCESS)
3638 return ERROR_SUCCESS;
3640 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3641 msiobj_release( &view->hdr );
3645 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3647 static const WCHAR szlnk[] = {'.','l','n','k',0};
3648 LPCWSTR directory, extension, link_folder;
3649 LPWSTR link_file, filename;
3651 directory = MSI_RecordGetString( row, 2 );
3652 link_folder = msi_get_target_folder( package, directory );
3655 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3658 /* may be needed because of a bug somewhere else */
3659 msi_create_full_path( link_folder );
3661 filename = msi_dup_record_field( row, 3 );
3662 msi_reduce_to_long_filename( filename );
3664 extension = strchrW( filename, '.' );
3665 if (!extension || strcmpiW( extension, szlnk ))
3667 int len = strlenW( filename );
3668 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3669 memcpy( filename + len, szlnk, sizeof(szlnk) );
3671 link_file = msi_build_directory_name( 2, link_folder, filename );
3672 msi_free( filename );
3677 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3679 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3680 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3681 WCHAR *folder, *dest, *path;
3683 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3684 folder = msi_dup_property( package->db, szWindowsFolder );
3687 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3688 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3689 msi_free( appdata );
3691 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3692 msi_create_full_path( dest );
3693 path = msi_build_directory_name( 2, dest, icon_name );
3699 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3701 MSIPACKAGE *package = param;
3702 LPWSTR link_file, deformated, path;
3703 LPCWSTR component, target;
3705 IShellLinkW *sl = NULL;
3706 IPersistFile *pf = NULL;
3709 component = MSI_RecordGetString(row, 4);
3710 comp = msi_get_loaded_component(package, component);
3712 return ERROR_SUCCESS;
3714 comp->Action = msi_get_component_action( package, comp );
3715 if (comp->Action != INSTALLSTATE_LOCAL)
3717 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3718 return ERROR_SUCCESS;
3720 msi_ui_actiondata( package, szCreateShortcuts, row );
3722 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3723 &IID_IShellLinkW, (LPVOID *) &sl );
3727 ERR("CLSID_ShellLink not available\n");
3731 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3734 ERR("QueryInterface(IID_IPersistFile) failed\n");
3738 target = MSI_RecordGetString(row, 5);
3739 if (strchrW(target, '['))
3741 deformat_string( package, target, &path );
3742 TRACE("target path is %s\n", debugstr_w(path));
3743 IShellLinkW_SetPath( sl, path );
3748 FIXME("poorly handled shortcut format, advertised shortcut\n");
3749 IShellLinkW_SetPath(sl,comp->FullKeypath);
3752 if (!MSI_RecordIsNull(row,6))
3754 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3755 deformat_string(package, arguments, &deformated);
3756 IShellLinkW_SetArguments(sl,deformated);
3757 msi_free(deformated);
3760 if (!MSI_RecordIsNull(row,7))
3762 LPCWSTR description = MSI_RecordGetString(row, 7);
3763 IShellLinkW_SetDescription(sl, description);
3766 if (!MSI_RecordIsNull(row,8))
3767 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3769 if (!MSI_RecordIsNull(row,9))
3772 LPCWSTR icon = MSI_RecordGetString(row, 9);
3774 path = msi_build_icon_path(package, icon);
3775 index = MSI_RecordGetInteger(row,10);
3777 /* no value means 0 */
3778 if (index == MSI_NULL_INTEGER)
3781 IShellLinkW_SetIconLocation(sl, path, index);
3785 if (!MSI_RecordIsNull(row,11))
3786 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3788 if (!MSI_RecordIsNull(row,12))
3790 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3791 full_path = msi_get_target_folder( package, wkdir );
3792 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3794 link_file = get_link_file(package, row);
3796 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3797 IPersistFile_Save(pf, link_file, FALSE);
3798 msi_free(link_file);
3802 IPersistFile_Release( pf );
3804 IShellLinkW_Release( sl );
3806 return ERROR_SUCCESS;
3809 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3811 static const WCHAR query[] = {
3812 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3813 '`','S','h','o','r','t','c','u','t','`',0};
3818 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3819 if (rc != ERROR_SUCCESS)
3820 return ERROR_SUCCESS;
3822 res = CoInitialize( NULL );
3824 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3825 msiobj_release(&view->hdr);
3827 if (SUCCEEDED(res)) CoUninitialize();
3831 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3833 MSIPACKAGE *package = param;
3838 component = MSI_RecordGetString( row, 4 );
3839 comp = msi_get_loaded_component( package, component );
3841 return ERROR_SUCCESS;
3843 comp->Action = msi_get_component_action( package, comp );
3844 if (comp->Action != INSTALLSTATE_ABSENT)
3846 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3847 return ERROR_SUCCESS;
3849 msi_ui_actiondata( package, szRemoveShortcuts, row );
3851 link_file = get_link_file( package, row );
3853 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3854 if (!DeleteFileW( link_file ))
3856 WARN("Failed to remove shortcut file %u\n", GetLastError());
3858 msi_free( link_file );
3860 return ERROR_SUCCESS;
3863 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3865 static const WCHAR query[] = {
3866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3867 '`','S','h','o','r','t','c','u','t','`',0};
3871 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3872 if (rc != ERROR_SUCCESS)
3873 return ERROR_SUCCESS;
3875 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3876 msiobj_release( &view->hdr );
3880 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3882 MSIPACKAGE* package = param;
3890 FileName = MSI_RecordGetString(row,1);
3893 ERR("Unable to get FileName\n");
3894 return ERROR_SUCCESS;
3897 FilePath = msi_build_icon_path(package, FileName);
3899 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3901 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3902 FILE_ATTRIBUTE_NORMAL, NULL);
3904 if (the_file == INVALID_HANDLE_VALUE)
3906 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3908 return ERROR_SUCCESS;
3915 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3916 if (rc != ERROR_SUCCESS)
3918 ERR("Failed to get stream\n");
3919 CloseHandle(the_file);
3920 DeleteFileW(FilePath);
3923 WriteFile(the_file,buffer,sz,&write,NULL);
3924 } while (sz == 1024);
3927 CloseHandle(the_file);
3929 return ERROR_SUCCESS;
3932 static UINT msi_publish_icons(MSIPACKAGE *package)
3934 static const WCHAR query[]= {
3935 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3936 '`','I','c','o','n','`',0};
3940 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3941 if (r == ERROR_SUCCESS)
3943 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3944 msiobj_release(&view->hdr);
3945 if (r != ERROR_SUCCESS)
3948 return ERROR_SUCCESS;
3951 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3957 MSISOURCELISTINFO *info;
3959 r = RegCreateKeyW(hkey, szSourceList, &source);
3960 if (r != ERROR_SUCCESS)
3963 RegCloseKey(source);
3965 buffer = strrchrW(package->PackagePath, '\\') + 1;
3966 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3967 package->Context, MSICODE_PRODUCT,
3968 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3969 if (r != ERROR_SUCCESS)
3972 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3973 package->Context, MSICODE_PRODUCT,
3974 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3975 if (r != ERROR_SUCCESS)
3978 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3979 package->Context, MSICODE_PRODUCT,
3980 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3981 if (r != ERROR_SUCCESS)
3984 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3986 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3987 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3988 info->options, info->value);
3990 MsiSourceListSetInfoW(package->ProductCode, NULL,
3991 info->context, info->options,
3992 info->property, info->value);
3995 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3997 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3998 disk->context, disk->options,
3999 disk->disk_id, disk->volume_label, disk->disk_prompt);
4002 return ERROR_SUCCESS;
4005 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4007 MSIHANDLE hdb, suminfo;
4008 WCHAR guids[MAX_PATH];
4009 WCHAR packcode[SQUISH_GUID_SIZE];
4016 static const WCHAR szARPProductIcon[] =
4017 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4018 static const WCHAR szAssignment[] =
4019 {'A','s','s','i','g','n','m','e','n','t',0};
4020 static const WCHAR szAdvertiseFlags[] =
4021 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4022 static const WCHAR szClients[] =
4023 {'C','l','i','e','n','t','s',0};
4024 static const WCHAR szColon[] = {':',0};
4026 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4027 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4030 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4031 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4034 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4036 buffer = msi_dup_property(package->db, szARPProductIcon);
4039 LPWSTR path = msi_build_icon_path(package, buffer);
4040 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4045 buffer = msi_dup_property(package->db, szProductVersion);
4048 DWORD verdword = msi_version_str_to_dword(buffer);
4049 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4053 msi_reg_set_val_dword(hkey, szAssignment, 0);
4054 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4055 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4056 msi_reg_set_val_str(hkey, szClients, szColon);
4058 hdb = alloc_msihandle(&package->db->hdr);
4060 return ERROR_NOT_ENOUGH_MEMORY;
4062 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4063 MsiCloseHandle(hdb);
4064 if (r != ERROR_SUCCESS)
4068 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4069 NULL, guids, &size);
4070 if (r != ERROR_SUCCESS)
4073 ptr = strchrW(guids, ';');
4075 squash_guid(guids, packcode);
4076 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4079 MsiCloseHandle(suminfo);
4080 return ERROR_SUCCESS;
4083 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4088 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4090 upgrade = msi_dup_property(package->db, szUpgradeCode);
4092 return ERROR_SUCCESS;
4094 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4095 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4097 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4099 if (r != ERROR_SUCCESS)
4101 WARN("failed to open upgrade code key\n");
4103 return ERROR_SUCCESS;
4105 squash_guid(package->ProductCode, squashed_pc);
4106 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4109 return ERROR_SUCCESS;
4112 static BOOL msi_check_publish(MSIPACKAGE *package)
4114 MSIFEATURE *feature;
4116 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4118 feature->Action = msi_get_feature_action( package, feature );
4119 if (feature->Action == INSTALLSTATE_LOCAL)
4126 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4128 MSIFEATURE *feature;
4130 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4132 feature->Action = msi_get_feature_action( package, feature );
4133 if (feature->Action != INSTALLSTATE_ABSENT)
4140 static UINT msi_publish_patches( MSIPACKAGE *package )
4142 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4143 WCHAR patch_squashed[GUID_SIZE];
4144 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4146 MSIPATCHINFO *patch;
4148 WCHAR *p, *all_patches = NULL;
4151 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4152 if (r != ERROR_SUCCESS)
4153 return ERROR_FUNCTION_FAILED;
4155 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4156 if (res != ERROR_SUCCESS)
4158 r = ERROR_FUNCTION_FAILED;
4162 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4163 if (r != ERROR_SUCCESS)
4166 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4168 squash_guid( patch->patchcode, patch_squashed );
4169 len += strlenW( patch_squashed ) + 1;
4172 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4176 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4180 squash_guid( patch->patchcode, p );
4181 p += strlenW( p ) + 1;
4183 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4184 (const BYTE *)patch->transforms,
4185 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4186 if (res != ERROR_SUCCESS)
4189 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4190 if (r != ERROR_SUCCESS)
4193 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4194 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4195 RegCloseKey( patch_key );
4196 if (res != ERROR_SUCCESS)
4199 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4201 res = GetLastError();
4202 ERR("Unable to copy patch package %d\n", res);
4205 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4206 if (res != ERROR_SUCCESS)
4209 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4210 RegCloseKey( patch_key );
4211 if (res != ERROR_SUCCESS)
4215 all_patches[len] = 0;
4216 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4217 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4218 if (res != ERROR_SUCCESS)
4221 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4222 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4223 if (res != ERROR_SUCCESS)
4224 r = ERROR_FUNCTION_FAILED;
4227 RegCloseKey( product_patches_key );
4228 RegCloseKey( patches_key );
4229 RegCloseKey( product_key );
4230 msi_free( all_patches );
4234 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4237 HKEY hukey = NULL, hudkey = NULL;
4240 if (!list_empty(&package->patches))
4242 rc = msi_publish_patches(package);
4243 if (rc != ERROR_SUCCESS)
4247 /* FIXME: also need to publish if the product is in advertise mode */
4248 if (!msi_check_publish(package))
4249 return ERROR_SUCCESS;
4251 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4253 if (rc != ERROR_SUCCESS)
4256 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4257 NULL, &hudkey, TRUE);
4258 if (rc != ERROR_SUCCESS)
4261 rc = msi_publish_upgrade_code(package);
4262 if (rc != ERROR_SUCCESS)
4265 rc = msi_publish_product_properties(package, hukey);
4266 if (rc != ERROR_SUCCESS)
4269 rc = msi_publish_sourcelist(package, hukey);
4270 if (rc != ERROR_SUCCESS)
4273 rc = msi_publish_icons(package);
4276 uirow = MSI_CreateRecord( 1 );
4277 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4278 msi_ui_actiondata( package, szPublishProduct, uirow );
4279 msiobj_release( &uirow->hdr );
4282 RegCloseKey(hudkey);
4286 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4288 WCHAR *filename, *ptr, *folder, *ret;
4289 const WCHAR *dirprop;
4291 filename = msi_dup_record_field( row, 2 );
4292 if (filename && (ptr = strchrW( filename, '|' )))
4297 dirprop = MSI_RecordGetString( row, 3 );
4300 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4301 if (!folder) folder = msi_dup_property( package->db, dirprop );
4304 folder = msi_dup_property( package->db, szWindowsFolder );
4308 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4309 msi_free( filename );
4313 ret = msi_build_directory_name( 2, folder, ptr );
4315 msi_free( filename );
4320 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4322 MSIPACKAGE *package = param;
4323 LPCWSTR component, section, key, value, identifier;
4324 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4329 component = MSI_RecordGetString(row, 8);
4330 comp = msi_get_loaded_component(package,component);
4332 return ERROR_SUCCESS;
4334 comp->Action = msi_get_component_action( package, comp );
4335 if (comp->Action != INSTALLSTATE_LOCAL)
4337 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4338 return ERROR_SUCCESS;
4341 identifier = MSI_RecordGetString(row,1);
4342 section = MSI_RecordGetString(row,4);
4343 key = MSI_RecordGetString(row,5);
4344 value = MSI_RecordGetString(row,6);
4345 action = MSI_RecordGetInteger(row,7);
4347 deformat_string(package,section,&deformated_section);
4348 deformat_string(package,key,&deformated_key);
4349 deformat_string(package,value,&deformated_value);
4351 fullname = get_ini_file_name(package, row);
4355 TRACE("Adding value %s to section %s in %s\n",
4356 debugstr_w(deformated_key), debugstr_w(deformated_section),
4357 debugstr_w(fullname));
4358 WritePrivateProfileStringW(deformated_section, deformated_key,
4359 deformated_value, fullname);
4361 else if (action == 1)
4364 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4365 returned, 10, fullname);
4366 if (returned[0] == 0)
4368 TRACE("Adding value %s to section %s in %s\n",
4369 debugstr_w(deformated_key), debugstr_w(deformated_section),
4370 debugstr_w(fullname));
4372 WritePrivateProfileStringW(deformated_section, deformated_key,
4373 deformated_value, fullname);
4376 else if (action == 3)
4377 FIXME("Append to existing section not yet implemented\n");
4379 uirow = MSI_CreateRecord(4);
4380 MSI_RecordSetStringW(uirow,1,identifier);
4381 MSI_RecordSetStringW(uirow,2,deformated_section);
4382 MSI_RecordSetStringW(uirow,3,deformated_key);
4383 MSI_RecordSetStringW(uirow,4,deformated_value);
4384 msi_ui_actiondata( package, szWriteIniValues, uirow );
4385 msiobj_release( &uirow->hdr );
4388 msi_free(deformated_key);
4389 msi_free(deformated_value);
4390 msi_free(deformated_section);
4391 return ERROR_SUCCESS;
4394 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4396 static const WCHAR query[] = {
4397 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4398 '`','I','n','i','F','i','l','e','`',0};
4402 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4403 if (rc != ERROR_SUCCESS)
4404 return ERROR_SUCCESS;
4406 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4407 msiobj_release(&view->hdr);
4411 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4413 MSIPACKAGE *package = param;
4414 LPCWSTR component, section, key, value, identifier;
4415 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4420 component = MSI_RecordGetString( row, 8 );
4421 comp = msi_get_loaded_component( package, component );
4423 return ERROR_SUCCESS;
4425 comp->Action = msi_get_component_action( package, comp );
4426 if (comp->Action != INSTALLSTATE_ABSENT)
4428 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4429 return ERROR_SUCCESS;
4432 identifier = MSI_RecordGetString( row, 1 );
4433 section = MSI_RecordGetString( row, 4 );
4434 key = MSI_RecordGetString( row, 5 );
4435 value = MSI_RecordGetString( row, 6 );
4436 action = MSI_RecordGetInteger( row, 7 );
4438 deformat_string( package, section, &deformated_section );
4439 deformat_string( package, key, &deformated_key );
4440 deformat_string( package, value, &deformated_value );
4442 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4444 filename = get_ini_file_name( package, row );
4446 TRACE("Removing key %s from section %s in %s\n",
4447 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4449 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4451 WARN("Unable to remove key %u\n", GetLastError());
4453 msi_free( filename );
4456 FIXME("Unsupported action %d\n", action);
4459 uirow = MSI_CreateRecord( 4 );
4460 MSI_RecordSetStringW( uirow, 1, identifier );
4461 MSI_RecordSetStringW( uirow, 2, deformated_section );
4462 MSI_RecordSetStringW( uirow, 3, deformated_key );
4463 MSI_RecordSetStringW( uirow, 4, deformated_value );
4464 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4465 msiobj_release( &uirow->hdr );
4467 msi_free( deformated_key );
4468 msi_free( deformated_value );
4469 msi_free( deformated_section );
4470 return ERROR_SUCCESS;
4473 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4475 MSIPACKAGE *package = param;
4476 LPCWSTR component, section, key, value, identifier;
4477 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4482 component = MSI_RecordGetString( row, 8 );
4483 comp = msi_get_loaded_component( package, component );
4485 return ERROR_SUCCESS;
4487 comp->Action = msi_get_component_action( package, comp );
4488 if (comp->Action != INSTALLSTATE_LOCAL)
4490 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4491 return ERROR_SUCCESS;
4494 identifier = MSI_RecordGetString( row, 1 );
4495 section = MSI_RecordGetString( row, 4 );
4496 key = MSI_RecordGetString( row, 5 );
4497 value = MSI_RecordGetString( row, 6 );
4498 action = MSI_RecordGetInteger( row, 7 );
4500 deformat_string( package, section, &deformated_section );
4501 deformat_string( package, key, &deformated_key );
4502 deformat_string( package, value, &deformated_value );
4504 if (action == msidbIniFileActionRemoveLine)
4506 filename = get_ini_file_name( package, row );
4508 TRACE("Removing key %s from section %s in %s\n",
4509 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4511 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4513 WARN("Unable to remove key %u\n", GetLastError());
4515 msi_free( filename );
4518 FIXME("Unsupported action %d\n", action);
4520 uirow = MSI_CreateRecord( 4 );
4521 MSI_RecordSetStringW( uirow, 1, identifier );
4522 MSI_RecordSetStringW( uirow, 2, deformated_section );
4523 MSI_RecordSetStringW( uirow, 3, deformated_key );
4524 MSI_RecordSetStringW( uirow, 4, deformated_value );
4525 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4526 msiobj_release( &uirow->hdr );
4528 msi_free( deformated_key );
4529 msi_free( deformated_value );
4530 msi_free( deformated_section );
4531 return ERROR_SUCCESS;
4534 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4536 static const WCHAR query[] = {
4537 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4538 '`','I','n','i','F','i','l','e','`',0};
4539 static const WCHAR remove_query[] = {
4540 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4541 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4545 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4546 if (rc == ERROR_SUCCESS)
4548 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4549 msiobj_release( &view->hdr );
4550 if (rc != ERROR_SUCCESS)
4553 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4554 if (rc == ERROR_SUCCESS)
4556 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4557 msiobj_release( &view->hdr );
4558 if (rc != ERROR_SUCCESS)
4561 return ERROR_SUCCESS;
4564 static void register_dll( const WCHAR *dll, BOOL unregister )
4568 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4571 HRESULT (WINAPI *func_ptr)( void );
4572 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4574 func_ptr = (void *)GetProcAddress( hmod, func );
4577 HRESULT hr = func_ptr();
4579 WARN("failed to register dll 0x%08x\n", hr);
4582 WARN("entry point %s not found\n", func);
4583 FreeLibrary( hmod );
4586 WARN("failed to load library %u\n", GetLastError());
4589 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4591 MSIPACKAGE *package = param;
4596 filename = MSI_RecordGetString( row, 1 );
4597 file = msi_get_loaded_file( package, filename );
4600 WARN("unable to find file %s\n", debugstr_w(filename));
4601 return ERROR_SUCCESS;
4603 file->Component->Action = msi_get_component_action( package, file->Component );
4604 if (file->Component->Action != INSTALLSTATE_LOCAL)
4606 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4607 return ERROR_SUCCESS;
4610 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4611 register_dll( file->TargetPath, FALSE );
4613 uirow = MSI_CreateRecord( 2 );
4614 MSI_RecordSetStringW( uirow, 1, file->File );
4615 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4616 msi_ui_actiondata( package, szSelfRegModules, uirow );
4617 msiobj_release( &uirow->hdr );
4619 return ERROR_SUCCESS;
4622 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4624 static const WCHAR query[] = {
4625 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4626 '`','S','e','l','f','R','e','g','`',0};
4630 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4631 if (rc != ERROR_SUCCESS)
4632 return ERROR_SUCCESS;
4634 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4635 msiobj_release(&view->hdr);
4639 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4641 MSIPACKAGE *package = param;
4646 filename = MSI_RecordGetString( row, 1 );
4647 file = msi_get_loaded_file( package, filename );
4650 WARN("unable to find file %s\n", debugstr_w(filename));
4651 return ERROR_SUCCESS;
4653 file->Component->Action = msi_get_component_action( package, file->Component );
4654 if (file->Component->Action != INSTALLSTATE_ABSENT)
4656 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4657 return ERROR_SUCCESS;
4660 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4661 register_dll( file->TargetPath, TRUE );
4663 uirow = MSI_CreateRecord( 2 );
4664 MSI_RecordSetStringW( uirow, 1, file->File );
4665 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4666 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4667 msiobj_release( &uirow->hdr );
4669 return ERROR_SUCCESS;
4672 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4674 static const WCHAR query[] = {
4675 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4676 '`','S','e','l','f','R','e','g','`',0};
4680 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4681 if (rc != ERROR_SUCCESS)
4682 return ERROR_SUCCESS;
4684 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4685 msiobj_release( &view->hdr );
4689 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4691 MSIFEATURE *feature;
4693 HKEY hkey = NULL, userdata = NULL;
4695 if (!msi_check_publish(package))
4696 return ERROR_SUCCESS;
4698 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4700 if (rc != ERROR_SUCCESS)
4703 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4705 if (rc != ERROR_SUCCESS)
4708 /* here the guids are base 85 encoded */
4709 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4715 BOOL absent = FALSE;
4718 if (feature->Action != INSTALLSTATE_LOCAL &&
4719 feature->Action != INSTALLSTATE_SOURCE &&
4720 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4723 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4727 if (feature->Feature_Parent)
4728 size += strlenW( feature->Feature_Parent )+2;
4730 data = msi_alloc(size * sizeof(WCHAR));
4733 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4735 MSICOMPONENT* component = cl->component;
4739 if (component->ComponentId)
4741 TRACE("From %s\n",debugstr_w(component->ComponentId));
4742 CLSIDFromString(component->ComponentId, &clsid);
4743 encode_base85_guid(&clsid,buf);
4744 TRACE("to %s\n",debugstr_w(buf));
4749 if (feature->Feature_Parent)
4751 static const WCHAR sep[] = {'\2',0};
4753 strcatW(data,feature->Feature_Parent);
4756 msi_reg_set_val_str( userdata, feature->Feature, data );
4760 if (feature->Feature_Parent)
4761 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4764 size += sizeof(WCHAR);
4765 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4766 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4770 size += 2*sizeof(WCHAR);
4771 data = msi_alloc(size);
4774 if (feature->Feature_Parent)
4775 strcpyW( &data[1], feature->Feature_Parent );
4776 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4782 uirow = MSI_CreateRecord( 1 );
4783 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4784 msi_ui_actiondata( package, szPublishFeatures, uirow );
4785 msiobj_release( &uirow->hdr );
4786 /* FIXME: call msi_ui_progress? */
4791 RegCloseKey(userdata);
4795 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4801 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4803 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4805 if (r == ERROR_SUCCESS)
4807 RegDeleteValueW(hkey, feature->Feature);
4811 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4813 if (r == ERROR_SUCCESS)
4815 RegDeleteValueW(hkey, feature->Feature);
4819 uirow = MSI_CreateRecord( 1 );
4820 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4821 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4822 msiobj_release( &uirow->hdr );
4824 return ERROR_SUCCESS;
4827 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4829 MSIFEATURE *feature;
4831 if (!msi_check_unpublish(package))
4832 return ERROR_SUCCESS;
4834 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4836 msi_unpublish_feature(package, feature);
4839 return ERROR_SUCCESS;
4842 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4846 WCHAR date[9], *val, *buffer;
4847 const WCHAR *prop, *key;
4849 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4850 static const WCHAR modpath_fmt[] =
4851 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4852 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4853 static const WCHAR szModifyPath[] =
4854 {'M','o','d','i','f','y','P','a','t','h',0};
4855 static const WCHAR szUninstallString[] =
4856 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4857 static const WCHAR szEstimatedSize[] =
4858 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4859 static const WCHAR szDisplayVersion[] =
4860 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4861 static const WCHAR szInstallSource[] =
4862 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4863 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4864 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4865 static const WCHAR szAuthorizedCDFPrefix[] =
4866 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4867 static const WCHAR szARPCONTACT[] =
4868 {'A','R','P','C','O','N','T','A','C','T',0};
4869 static const WCHAR szContact[] =
4870 {'C','o','n','t','a','c','t',0};
4871 static const WCHAR szARPCOMMENTS[] =
4872 {'A','R','P','C','O','M','M','E','N','T','S',0};
4873 static const WCHAR szComments[] =
4874 {'C','o','m','m','e','n','t','s',0};
4875 static const WCHAR szProductName[] =
4876 {'P','r','o','d','u','c','t','N','a','m','e',0};
4877 static const WCHAR szDisplayName[] =
4878 {'D','i','s','p','l','a','y','N','a','m','e',0};
4879 static const WCHAR szARPHELPLINK[] =
4880 {'A','R','P','H','E','L','P','L','I','N','K',0};
4881 static const WCHAR szHelpLink[] =
4882 {'H','e','l','p','L','i','n','k',0};
4883 static const WCHAR szARPHELPTELEPHONE[] =
4884 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4885 static const WCHAR szHelpTelephone[] =
4886 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4887 static const WCHAR szARPINSTALLLOCATION[] =
4888 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4889 static const WCHAR szManufacturer[] =
4890 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4891 static const WCHAR szPublisher[] =
4892 {'P','u','b','l','i','s','h','e','r',0};
4893 static const WCHAR szARPREADME[] =
4894 {'A','R','P','R','E','A','D','M','E',0};
4895 static const WCHAR szReadme[] =
4896 {'R','e','a','d','M','e',0};
4897 static const WCHAR szARPSIZE[] =
4898 {'A','R','P','S','I','Z','E',0};
4899 static const WCHAR szSize[] =
4900 {'S','i','z','e',0};
4901 static const WCHAR szARPURLINFOABOUT[] =
4902 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4903 static const WCHAR szURLInfoAbout[] =
4904 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4905 static const WCHAR szARPURLUPDATEINFO[] =
4906 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4907 static const WCHAR szURLUpdateInfo[] =
4908 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4909 static const WCHAR szARPSYSTEMCOMPONENT[] =
4910 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4911 static const WCHAR szSystemComponent[] =
4912 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4914 static const WCHAR *propval[] = {
4915 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4916 szARPCONTACT, szContact,
4917 szARPCOMMENTS, szComments,
4918 szProductName, szDisplayName,
4919 szARPHELPLINK, szHelpLink,
4920 szARPHELPTELEPHONE, szHelpTelephone,
4921 szARPINSTALLLOCATION, szInstallLocation,
4922 szSourceDir, szInstallSource,
4923 szManufacturer, szPublisher,
4924 szARPREADME, szReadme,
4926 szARPURLINFOABOUT, szURLInfoAbout,
4927 szARPURLUPDATEINFO, szURLUpdateInfo,
4930 const WCHAR **p = propval;
4936 val = msi_dup_property(package->db, prop);
4937 msi_reg_set_val_str(hkey, key, val);
4941 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4942 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4944 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4946 size = deformat_string(package, modpath_fmt, &buffer);
4947 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4948 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4951 /* FIXME: Write real Estimated Size when we have it */
4952 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4954 GetLocalTime(&systime);
4955 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4956 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4958 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4959 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4961 buffer = msi_dup_property(package->db, szProductVersion);
4962 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4965 DWORD verdword = msi_version_str_to_dword(buffer);
4967 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4968 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4969 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4973 return ERROR_SUCCESS;
4976 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4978 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4980 LPWSTR upgrade_code;
4981 HKEY hkey, props, upgrade_key;
4984 /* FIXME: also need to publish if the product is in advertise mode */
4985 if (!msi_check_publish(package))
4986 return ERROR_SUCCESS;
4988 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4989 if (rc != ERROR_SUCCESS)
4992 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4993 if (rc != ERROR_SUCCESS)
4996 rc = msi_publish_install_properties(package, hkey);
4997 if (rc != ERROR_SUCCESS)
5000 rc = msi_publish_install_properties(package, props);
5001 if (rc != ERROR_SUCCESS)
5004 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5007 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
5008 if (rc == ERROR_SUCCESS)
5010 squash_guid( package->ProductCode, squashed_pc );
5011 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
5012 RegCloseKey( upgrade_key );
5014 msi_free( upgrade_code );
5016 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
5017 package->delete_on_close = FALSE;
5020 uirow = MSI_CreateRecord( 1 );
5021 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5022 msi_ui_actiondata( package, szRegisterProduct, uirow );
5023 msiobj_release( &uirow->hdr );
5026 return ERROR_SUCCESS;
5029 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5031 return execute_script(package, SCRIPT_INSTALL);
5034 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5036 MSIPACKAGE *package = param;
5037 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5038 WCHAR *p, *icon_path;
5040 if (!icon) return ERROR_SUCCESS;
5041 if ((icon_path = msi_build_icon_path( package, icon )))
5043 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5044 DeleteFileW( icon_path );
5045 if ((p = strrchrW( icon_path, '\\' )))
5048 RemoveDirectoryW( icon_path );
5050 msi_free( icon_path );
5052 return ERROR_SUCCESS;
5055 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5057 static const WCHAR query[]= {
5058 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
5062 r = MSI_DatabaseOpenViewW( package->db, query, &view );
5063 if (r == ERROR_SUCCESS)
5065 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5066 msiobj_release( &view->hdr );
5067 if (r != ERROR_SUCCESS)
5070 return ERROR_SUCCESS;
5073 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
5075 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
5076 WCHAR *upgrade, **features;
5077 BOOL full_uninstall = TRUE;
5078 MSIFEATURE *feature;
5079 MSIPATCHINFO *patch;
5082 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5084 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
5086 features = msi_split_string( remove, ',' );
5087 for (i = 0; features && features[i]; i++)
5089 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
5093 if (!full_uninstall)
5094 return ERROR_SUCCESS;
5096 MSIREG_DeleteProductKey(package->ProductCode);
5097 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5098 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5100 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5101 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5102 MSIREG_DeleteUserProductKey(package->ProductCode);
5103 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5105 upgrade = msi_dup_property(package->db, szUpgradeCode);
5108 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5109 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5113 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5115 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5116 if (!strcmpW( package->ProductCode, patch->products ))
5118 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5119 patch->delete_on_close = TRUE;
5121 /* FIXME: remove local patch package if this is the last product */
5123 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5124 package->delete_on_close = TRUE;
5126 msi_unpublish_icons( package );
5127 return ERROR_SUCCESS;
5130 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5135 /* turn off scheduling */
5136 package->script->CurrentlyScripting= FALSE;
5138 /* first do the same as an InstallExecute */
5139 rc = ACTION_InstallExecute(package);
5140 if (rc != ERROR_SUCCESS)
5143 /* then handle commit actions */
5144 rc = execute_script(package, SCRIPT_COMMIT);
5145 if (rc != ERROR_SUCCESS)
5148 remove = msi_dup_property(package->db, szRemove);
5149 rc = msi_unpublish_product(package, remove);
5154 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5156 static const WCHAR RunOnce[] = {
5157 'S','o','f','t','w','a','r','e','\\',
5158 'M','i','c','r','o','s','o','f','t','\\',
5159 'W','i','n','d','o','w','s','\\',
5160 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5161 'R','u','n','O','n','c','e',0};
5162 static const WCHAR InstallRunOnce[] = {
5163 'S','o','f','t','w','a','r','e','\\',
5164 'M','i','c','r','o','s','o','f','t','\\',
5165 'W','i','n','d','o','w','s','\\',
5166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5167 'I','n','s','t','a','l','l','e','r','\\',
5168 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5170 static const WCHAR msiexec_fmt[] = {
5172 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5173 '\"','%','s','\"',0};
5174 static const WCHAR install_fmt[] = {
5175 '/','I',' ','\"','%','s','\"',' ',
5176 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5177 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5178 WCHAR buffer[256], sysdir[MAX_PATH];
5180 WCHAR squished_pc[100];
5182 squash_guid(package->ProductCode,squished_pc);
5184 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5185 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5186 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5189 msi_reg_set_val_str( hkey, squished_pc, buffer );
5192 TRACE("Reboot command %s\n",debugstr_w(buffer));
5194 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5195 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5197 msi_reg_set_val_str( hkey, squished_pc, buffer );
5200 return ERROR_INSTALL_SUSPEND;
5203 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5205 static const WCHAR query[] =
5206 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5207 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5208 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5209 MSIRECORD *rec, *row;
5215 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5217 rec = MSI_CreateRecord( count + 2 );
5218 str = MSI_RecordGetString( row, 1 );
5219 MSI_RecordSetStringW( rec, 0, str );
5220 msiobj_release( &row->hdr );
5221 MSI_RecordSetInteger( rec, 1, error );
5223 va_start( va, count );
5224 for (i = 0; i < count; i++)
5226 str = va_arg( va, const WCHAR *);
5227 MSI_RecordSetStringW( rec, i + 2, str );
5231 MSI_FormatRecordW( package, rec, NULL, &size );
5233 data = msi_alloc( size * sizeof(WCHAR) );
5234 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5236 msiobj_release( &rec->hdr );
5240 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5246 * We are currently doing what should be done here in the top level Install
5247 * however for Administrative and uninstalls this step will be needed
5249 if (!package->PackagePath)
5250 return ERROR_SUCCESS;
5252 msi_set_sourcedir_props(package, TRUE);
5254 attrib = GetFileAttributesW(package->db->path);
5255 if (attrib == INVALID_FILE_ATTRIBUTES)
5260 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5261 package->Context, MSICODE_PRODUCT,
5262 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5263 if (rc == ERROR_MORE_DATA)
5265 prompt = msi_alloc(size * sizeof(WCHAR));
5266 MsiSourceListGetInfoW(package->ProductCode, NULL,
5267 package->Context, MSICODE_PRODUCT,
5268 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5271 prompt = strdupW(package->db->path);
5273 msg = msi_build_error_string(package, 1302, 1, prompt);
5275 while(attrib == INVALID_FILE_ATTRIBUTES)
5277 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5281 return ERROR_INSTALL_USEREXIT;
5283 attrib = GetFileAttributesW(package->db->path);
5289 return ERROR_SUCCESS;
5294 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5297 LPWSTR buffer, productid = NULL;
5298 UINT i, rc = ERROR_SUCCESS;
5301 static const WCHAR szPropKeys[][80] =
5303 {'P','r','o','d','u','c','t','I','D',0},
5304 {'U','S','E','R','N','A','M','E',0},
5305 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5309 static const WCHAR szRegKeys[][80] =
5311 {'P','r','o','d','u','c','t','I','D',0},
5312 {'R','e','g','O','w','n','e','r',0},
5313 {'R','e','g','C','o','m','p','a','n','y',0},
5317 if (msi_check_unpublish(package))
5319 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5323 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5327 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5329 if (rc != ERROR_SUCCESS)
5332 for( i = 0; szPropKeys[i][0]; i++ )
5334 buffer = msi_dup_property( package->db, szPropKeys[i] );
5335 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5340 uirow = MSI_CreateRecord( 1 );
5341 MSI_RecordSetStringW( uirow, 1, productid );
5342 msi_ui_actiondata( package, szRegisterUser, uirow );
5343 msiobj_release( &uirow->hdr );
5345 msi_free(productid);
5351 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5355 package->script->InWhatSequence |= SEQUENCE_EXEC;
5356 rc = ACTION_ProcessExecSequence(package,FALSE);
5360 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5362 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5363 WCHAR productid_85[21], component_85[21], *ret;
5367 /* > is used if there is a component GUID and < if not. */
5369 productid_85[0] = 0;
5370 component_85[0] = 0;
5371 CLSIDFromString( package->ProductCode, &clsid );
5373 encode_base85_guid( &clsid, productid_85 );
5376 CLSIDFromString( component->ComponentId, &clsid );
5377 encode_base85_guid( &clsid, component_85 );
5380 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5381 debugstr_w(component_85));
5383 sz = 20 + strlenW( feature ) + 20 + 3;
5384 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5385 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5389 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5391 MSIPACKAGE *package = param;
5392 LPCWSTR compgroupid, component, feature, qualifier, text;
5393 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5402 feature = MSI_RecordGetString(rec, 5);
5403 feat = msi_get_loaded_feature(package, feature);
5405 return ERROR_SUCCESS;
5407 feat->Action = msi_get_feature_action( package, feat );
5408 if (feat->Action != INSTALLSTATE_LOCAL &&
5409 feat->Action != INSTALLSTATE_SOURCE &&
5410 feat->Action != INSTALLSTATE_ADVERTISED)
5412 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5413 return ERROR_SUCCESS;
5416 component = MSI_RecordGetString(rec, 3);
5417 comp = msi_get_loaded_component(package, component);
5419 return ERROR_SUCCESS;
5421 compgroupid = MSI_RecordGetString(rec,1);
5422 qualifier = MSI_RecordGetString(rec,2);
5424 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5425 if (rc != ERROR_SUCCESS)
5428 advertise = msi_create_component_advertise_string( package, comp, feature );
5429 text = MSI_RecordGetString( rec, 4 );
5432 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5433 strcpyW( p, advertise );
5435 msi_free( advertise );
5438 existing = msi_reg_get_val_str( hkey, qualifier );
5440 sz = strlenW( advertise ) + 1;
5443 for (p = existing; *p; p += len)
5445 len = strlenW( p ) + 1;
5446 if (strcmpW( advertise, p )) sz += len;
5449 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5451 rc = ERROR_OUTOFMEMORY;
5457 for (p = existing; *p; p += len)
5459 len = strlenW( p ) + 1;
5460 if (strcmpW( advertise, p ))
5462 memcpy( q, p, len * sizeof(WCHAR) );
5467 strcpyW( q, advertise );
5468 q[strlenW( q ) + 1] = 0;
5470 msi_reg_set_val_multi_str( hkey, qualifier, output );
5475 msi_free( advertise );
5476 msi_free( existing );
5479 uirow = MSI_CreateRecord( 2 );
5480 MSI_RecordSetStringW( uirow, 1, compgroupid );
5481 MSI_RecordSetStringW( uirow, 2, qualifier);
5482 msi_ui_actiondata( package, szPublishComponents, uirow );
5483 msiobj_release( &uirow->hdr );
5484 /* FIXME: call ui_progress? */
5490 * At present I am ignorning the advertised components part of this and only
5491 * focusing on the qualified component sets
5493 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5495 static const WCHAR query[] = {
5496 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5497 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5501 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5502 if (rc != ERROR_SUCCESS)
5503 return ERROR_SUCCESS;
5505 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5506 msiobj_release(&view->hdr);
5510 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5512 static const WCHAR szInstallerComponents[] = {
5513 'S','o','f','t','w','a','r','e','\\',
5514 'M','i','c','r','o','s','o','f','t','\\',
5515 'I','n','s','t','a','l','l','e','r','\\',
5516 'C','o','m','p','o','n','e','n','t','s','\\',0};
5518 MSIPACKAGE *package = param;
5519 LPCWSTR compgroupid, component, feature, qualifier;
5523 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5526 feature = MSI_RecordGetString( rec, 5 );
5527 feat = msi_get_loaded_feature( package, feature );
5529 return ERROR_SUCCESS;
5531 feat->Action = msi_get_feature_action( package, feat );
5532 if (feat->Action != INSTALLSTATE_ABSENT)
5534 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5535 return ERROR_SUCCESS;
5538 component = MSI_RecordGetString( rec, 3 );
5539 comp = msi_get_loaded_component( package, component );
5541 return ERROR_SUCCESS;
5543 compgroupid = MSI_RecordGetString( rec, 1 );
5544 qualifier = MSI_RecordGetString( rec, 2 );
5546 squash_guid( compgroupid, squashed );
5547 strcpyW( keypath, szInstallerComponents );
5548 strcatW( keypath, squashed );
5550 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5551 if (res != ERROR_SUCCESS)
5553 WARN("Unable to delete component key %d\n", res);
5556 uirow = MSI_CreateRecord( 2 );
5557 MSI_RecordSetStringW( uirow, 1, compgroupid );
5558 MSI_RecordSetStringW( uirow, 2, qualifier );
5559 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5560 msiobj_release( &uirow->hdr );
5562 return ERROR_SUCCESS;
5565 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5567 static const WCHAR query[] = {
5568 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5569 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5573 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5574 if (rc != ERROR_SUCCESS)
5575 return ERROR_SUCCESS;
5577 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5578 msiobj_release( &view->hdr );
5582 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5584 static const WCHAR query[] =
5585 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5586 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5587 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5588 MSIPACKAGE *package = param;
5589 MSICOMPONENT *component;
5592 SC_HANDLE hscm = NULL, service = NULL;
5594 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5595 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5596 DWORD serv_type, start_type, err_control;
5597 SERVICE_DESCRIPTIONW sd = {NULL};
5599 comp = MSI_RecordGetString( rec, 12 );
5600 component = msi_get_loaded_component( package, comp );
5603 WARN("service component not found\n");
5606 component->Action = msi_get_component_action( package, component );
5607 if (component->Action != INSTALLSTATE_LOCAL)
5609 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5612 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5615 ERR("Failed to open the SC Manager!\n");
5619 start_type = MSI_RecordGetInteger(rec, 5);
5620 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5623 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5624 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5625 serv_type = MSI_RecordGetInteger(rec, 4);
5626 err_control = MSI_RecordGetInteger(rec, 6);
5627 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5628 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5629 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5630 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5631 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5632 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5634 /* fetch the service path */
5635 row = MSI_QueryGetRecord(package->db, query, comp);
5638 ERR("Query failed\n");
5641 key = MSI_RecordGetString(row, 6);
5642 file = msi_get_loaded_file(package, key);
5643 msiobj_release(&row->hdr);
5646 ERR("Failed to load the service file\n");
5650 if (!args || !args[0]) image_path = file->TargetPath;
5653 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5654 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5655 return ERROR_OUTOFMEMORY;
5657 strcpyW(image_path, file->TargetPath);
5658 strcatW(image_path, szSpace);
5659 strcatW(image_path, args);
5661 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5662 start_type, err_control, image_path, load_order,
5663 NULL, depends, serv_name, pass);
5667 if (GetLastError() != ERROR_SERVICE_EXISTS)
5668 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5670 else if (sd.lpDescription)
5672 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5673 WARN("failed to set service description %u\n", GetLastError());
5676 if (image_path != file->TargetPath) msi_free(image_path);
5678 CloseServiceHandle(service);
5679 CloseServiceHandle(hscm);
5682 msi_free(sd.lpDescription);
5683 msi_free(load_order);
5684 msi_free(serv_name);
5689 return ERROR_SUCCESS;
5692 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5694 static const WCHAR query[] = {
5695 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5696 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5700 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5701 if (rc != ERROR_SUCCESS)
5702 return ERROR_SUCCESS;
5704 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5705 msiobj_release(&view->hdr);
5709 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5710 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5712 LPCWSTR *vector, *temp_vector;
5716 static const WCHAR separator[] = {'[','~',']',0};
5719 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5724 vector = msi_alloc(sizeof(LPWSTR));
5732 vector[*numargs - 1] = p;
5734 if ((q = strstrW(p, separator)))
5738 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5744 vector = temp_vector;
5753 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5755 MSIPACKAGE *package = param;
5758 SC_HANDLE scm = NULL, service = NULL;
5759 LPCWSTR component, *vector = NULL;
5760 LPWSTR name, args, display_name = NULL;
5761 DWORD event, numargs, len, wait, dummy;
5762 UINT r = ERROR_FUNCTION_FAILED;
5763 SERVICE_STATUS_PROCESS status;
5764 ULONGLONG start_time;
5766 component = MSI_RecordGetString(rec, 6);
5767 comp = msi_get_loaded_component(package, component);
5769 return ERROR_SUCCESS;
5771 comp->Action = msi_get_component_action( package, comp );
5772 if (comp->Action != INSTALLSTATE_LOCAL)
5774 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5775 return ERROR_SUCCESS;
5778 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5779 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5780 event = MSI_RecordGetInteger(rec, 3);
5781 wait = MSI_RecordGetInteger(rec, 5);
5783 if (!(event & msidbServiceControlEventStart))
5789 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5792 ERR("Failed to open the service control manager\n");
5797 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5798 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5800 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5801 GetServiceDisplayNameW( scm, name, display_name, &len );
5804 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5807 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5811 vector = msi_service_args_to_vector(args, &numargs);
5813 if (!StartServiceW(service, numargs, vector) &&
5814 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5816 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5823 /* wait for at most 30 seconds for the service to be up and running */
5824 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5825 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5827 TRACE("failed to query service status (%u)\n", GetLastError());
5830 start_time = GetTickCount64();
5831 while (status.dwCurrentState == SERVICE_START_PENDING)
5833 if (GetTickCount64() - start_time > 30000) break;
5835 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5836 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5838 TRACE("failed to query service status (%u)\n", GetLastError());
5842 if (status.dwCurrentState != SERVICE_RUNNING)
5844 WARN("service failed to start %u\n", status.dwCurrentState);
5845 r = ERROR_FUNCTION_FAILED;
5850 uirow = MSI_CreateRecord( 2 );
5851 MSI_RecordSetStringW( uirow, 1, display_name );
5852 MSI_RecordSetStringW( uirow, 2, name );
5853 msi_ui_actiondata( package, szStartServices, uirow );
5854 msiobj_release( &uirow->hdr );
5856 CloseServiceHandle(service);
5857 CloseServiceHandle(scm);
5862 msi_free(display_name);
5866 static UINT ACTION_StartServices( MSIPACKAGE *package )
5868 static const WCHAR query[] = {
5869 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5870 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5874 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5875 if (rc != ERROR_SUCCESS)
5876 return ERROR_SUCCESS;
5878 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5879 msiobj_release(&view->hdr);
5883 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5885 DWORD i, needed, count;
5886 ENUM_SERVICE_STATUSW *dependencies;
5890 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5891 0, &needed, &count))
5894 if (GetLastError() != ERROR_MORE_DATA)
5897 dependencies = msi_alloc(needed);
5901 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5902 needed, &needed, &count))
5905 for (i = 0; i < count; i++)
5907 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5908 SERVICE_STOP | SERVICE_QUERY_STATUS);
5912 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5919 msi_free(dependencies);
5923 static UINT stop_service( LPCWSTR name )
5925 SC_HANDLE scm = NULL, service = NULL;
5926 SERVICE_STATUS status;
5927 SERVICE_STATUS_PROCESS ssp;
5930 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5933 WARN("Failed to open the SCM: %d\n", GetLastError());
5937 service = OpenServiceW(scm, name,
5939 SERVICE_QUERY_STATUS |
5940 SERVICE_ENUMERATE_DEPENDENTS);
5943 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5947 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5948 sizeof(SERVICE_STATUS_PROCESS), &needed))
5950 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5954 if (ssp.dwCurrentState == SERVICE_STOPPED)
5957 stop_service_dependents(scm, service);
5959 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5960 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5963 CloseServiceHandle(service);
5964 CloseServiceHandle(scm);
5966 return ERROR_SUCCESS;
5969 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5971 MSIPACKAGE *package = param;
5975 LPWSTR name = NULL, display_name = NULL;
5979 event = MSI_RecordGetInteger( rec, 3 );
5980 if (!(event & msidbServiceControlEventStop))
5981 return ERROR_SUCCESS;
5983 component = MSI_RecordGetString( rec, 6 );
5984 comp = msi_get_loaded_component( package, component );
5986 return ERROR_SUCCESS;
5988 comp->Action = msi_get_component_action( package, comp );
5989 if (comp->Action != INSTALLSTATE_ABSENT)
5991 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5992 return ERROR_SUCCESS;
5995 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5998 ERR("Failed to open the service control manager\n");
6003 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6004 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6006 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6007 GetServiceDisplayNameW( scm, name, display_name, &len );
6009 CloseServiceHandle( scm );
6011 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6012 stop_service( name );
6015 uirow = MSI_CreateRecord( 2 );
6016 MSI_RecordSetStringW( uirow, 1, display_name );
6017 MSI_RecordSetStringW( uirow, 2, name );
6018 msi_ui_actiondata( package, szStopServices, uirow );
6019 msiobj_release( &uirow->hdr );
6022 msi_free( display_name );
6023 return ERROR_SUCCESS;
6026 static UINT ACTION_StopServices( MSIPACKAGE *package )
6028 static const WCHAR query[] = {
6029 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6030 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6034 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6035 if (rc != ERROR_SUCCESS)
6036 return ERROR_SUCCESS;
6038 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6039 msiobj_release(&view->hdr);
6043 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6045 MSIPACKAGE *package = param;
6048 LPWSTR name = NULL, display_name = NULL;
6050 SC_HANDLE scm = NULL, service = NULL;
6052 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6054 return ERROR_SUCCESS;
6056 event = MSI_RecordGetInteger( rec, 3 );
6057 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6059 comp->Action = msi_get_component_action( package, comp );
6060 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6061 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6063 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6065 return ERROR_SUCCESS;
6067 stop_service( name );
6069 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6072 WARN("Failed to open the SCM: %d\n", GetLastError());
6077 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6078 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6080 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6081 GetServiceDisplayNameW( scm, name, display_name, &len );
6084 service = OpenServiceW( scm, name, DELETE );
6087 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6091 if (!DeleteService( service ))
6092 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6095 uirow = MSI_CreateRecord( 2 );
6096 MSI_RecordSetStringW( uirow, 1, display_name );
6097 MSI_RecordSetStringW( uirow, 2, name );
6098 msi_ui_actiondata( package, szDeleteServices, uirow );
6099 msiobj_release( &uirow->hdr );
6101 CloseServiceHandle( service );
6102 CloseServiceHandle( scm );
6104 msi_free( display_name );
6106 return ERROR_SUCCESS;
6109 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6111 static const WCHAR query[] = {
6112 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6113 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6117 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6118 if (rc != ERROR_SUCCESS)
6119 return ERROR_SUCCESS;
6121 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6122 msiobj_release( &view->hdr );
6126 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6128 MSIPACKAGE *package = param;
6129 LPWSTR driver, driver_path, ptr;
6130 WCHAR outpath[MAX_PATH];
6131 MSIFILE *driver_file = NULL, *setup_file = NULL;
6134 LPCWSTR desc, file_key, component;
6136 UINT r = ERROR_SUCCESS;
6138 static const WCHAR driver_fmt[] = {
6139 'D','r','i','v','e','r','=','%','s',0};
6140 static const WCHAR setup_fmt[] = {
6141 'S','e','t','u','p','=','%','s',0};
6142 static const WCHAR usage_fmt[] = {
6143 'F','i','l','e','U','s','a','g','e','=','1',0};
6145 component = MSI_RecordGetString( rec, 2 );
6146 comp = msi_get_loaded_component( package, component );
6148 return ERROR_SUCCESS;
6150 comp->Action = msi_get_component_action( package, comp );
6151 if (comp->Action != INSTALLSTATE_LOCAL)
6153 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6154 return ERROR_SUCCESS;
6156 desc = MSI_RecordGetString(rec, 3);
6158 file_key = MSI_RecordGetString( rec, 4 );
6159 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6161 file_key = MSI_RecordGetString( rec, 5 );
6162 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6166 ERR("ODBC Driver entry not found!\n");
6167 return ERROR_FUNCTION_FAILED;
6170 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6172 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6173 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6175 driver = msi_alloc(len * sizeof(WCHAR));
6177 return ERROR_OUTOFMEMORY;
6180 lstrcpyW(ptr, desc);
6181 ptr += lstrlenW(ptr) + 1;
6183 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6188 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6192 lstrcpyW(ptr, usage_fmt);
6193 ptr += lstrlenW(ptr) + 1;
6196 if (!driver_file->TargetPath)
6198 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6199 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6201 driver_path = strdupW(driver_file->TargetPath);
6202 ptr = strrchrW(driver_path, '\\');
6203 if (ptr) *ptr = '\0';
6205 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6206 NULL, ODBC_INSTALL_COMPLETE, &usage))
6208 ERR("Failed to install SQL driver!\n");
6209 r = ERROR_FUNCTION_FAILED;
6212 uirow = MSI_CreateRecord( 5 );
6213 MSI_RecordSetStringW( uirow, 1, desc );
6214 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6215 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6216 msi_ui_actiondata( package, szInstallODBC, uirow );
6217 msiobj_release( &uirow->hdr );
6220 msi_free(driver_path);
6225 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6227 MSIPACKAGE *package = param;
6228 LPWSTR translator, translator_path, ptr;
6229 WCHAR outpath[MAX_PATH];
6230 MSIFILE *translator_file = NULL, *setup_file = NULL;
6233 LPCWSTR desc, file_key, component;
6235 UINT r = ERROR_SUCCESS;
6237 static const WCHAR translator_fmt[] = {
6238 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6239 static const WCHAR setup_fmt[] = {
6240 'S','e','t','u','p','=','%','s',0};
6242 component = MSI_RecordGetString( rec, 2 );
6243 comp = msi_get_loaded_component( package, component );
6245 return ERROR_SUCCESS;
6247 comp->Action = msi_get_component_action( package, comp );
6248 if (comp->Action != INSTALLSTATE_LOCAL)
6250 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6251 return ERROR_SUCCESS;
6253 desc = MSI_RecordGetString(rec, 3);
6255 file_key = MSI_RecordGetString( rec, 4 );
6256 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6258 file_key = MSI_RecordGetString( rec, 5 );
6259 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6261 if (!translator_file)
6263 ERR("ODBC Translator entry not found!\n");
6264 return ERROR_FUNCTION_FAILED;
6267 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6269 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6271 translator = msi_alloc(len * sizeof(WCHAR));
6273 return ERROR_OUTOFMEMORY;
6276 lstrcpyW(ptr, desc);
6277 ptr += lstrlenW(ptr) + 1;
6279 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6284 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6289 translator_path = strdupW(translator_file->TargetPath);
6290 ptr = strrchrW(translator_path, '\\');
6291 if (ptr) *ptr = '\0';
6293 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6294 NULL, ODBC_INSTALL_COMPLETE, &usage))
6296 ERR("Failed to install SQL translator!\n");
6297 r = ERROR_FUNCTION_FAILED;
6300 uirow = MSI_CreateRecord( 5 );
6301 MSI_RecordSetStringW( uirow, 1, desc );
6302 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6303 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6304 msi_ui_actiondata( package, szInstallODBC, uirow );
6305 msiobj_release( &uirow->hdr );
6307 msi_free(translator);
6308 msi_free(translator_path);
6313 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6315 MSIPACKAGE *package = param;
6318 LPCWSTR desc, driver, component;
6319 WORD request = ODBC_ADD_SYS_DSN;
6322 UINT r = ERROR_SUCCESS;
6325 static const WCHAR attrs_fmt[] = {
6326 'D','S','N','=','%','s',0 };
6328 component = MSI_RecordGetString( rec, 2 );
6329 comp = msi_get_loaded_component( package, component );
6331 return ERROR_SUCCESS;
6333 comp->Action = msi_get_component_action( package, comp );
6334 if (comp->Action != INSTALLSTATE_LOCAL)
6336 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6337 return ERROR_SUCCESS;
6340 desc = MSI_RecordGetString(rec, 3);
6341 driver = MSI_RecordGetString(rec, 4);
6342 registration = MSI_RecordGetInteger(rec, 5);
6344 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6345 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6347 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6348 attrs = msi_alloc(len * sizeof(WCHAR));
6350 return ERROR_OUTOFMEMORY;
6352 len = sprintfW(attrs, attrs_fmt, desc);
6355 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6357 ERR("Failed to install SQL data source!\n");
6358 r = ERROR_FUNCTION_FAILED;
6361 uirow = MSI_CreateRecord( 5 );
6362 MSI_RecordSetStringW( uirow, 1, desc );
6363 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6364 MSI_RecordSetInteger( uirow, 3, request );
6365 msi_ui_actiondata( package, szInstallODBC, uirow );
6366 msiobj_release( &uirow->hdr );
6373 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6375 static const WCHAR driver_query[] = {
6376 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6377 'O','D','B','C','D','r','i','v','e','r',0};
6378 static const WCHAR translator_query[] = {
6379 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6380 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6381 static const WCHAR source_query[] = {
6382 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6383 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6387 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6388 if (rc == ERROR_SUCCESS)
6390 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6391 msiobj_release(&view->hdr);
6392 if (rc != ERROR_SUCCESS)
6395 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6396 if (rc == ERROR_SUCCESS)
6398 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6399 msiobj_release(&view->hdr);
6400 if (rc != ERROR_SUCCESS)
6403 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6404 if (rc == ERROR_SUCCESS)
6406 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6407 msiobj_release(&view->hdr);
6408 if (rc != ERROR_SUCCESS)
6411 return ERROR_SUCCESS;
6414 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6416 MSIPACKAGE *package = param;
6420 LPCWSTR desc, component;
6422 component = MSI_RecordGetString( rec, 2 );
6423 comp = msi_get_loaded_component( package, component );
6425 return ERROR_SUCCESS;
6427 comp->Action = msi_get_component_action( package, comp );
6428 if (comp->Action != INSTALLSTATE_ABSENT)
6430 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6431 return ERROR_SUCCESS;
6434 desc = MSI_RecordGetString( rec, 3 );
6435 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6437 WARN("Failed to remove ODBC driver\n");
6441 FIXME("Usage count reached 0\n");
6444 uirow = MSI_CreateRecord( 2 );
6445 MSI_RecordSetStringW( uirow, 1, desc );
6446 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6447 msi_ui_actiondata( package, szRemoveODBC, uirow );
6448 msiobj_release( &uirow->hdr );
6450 return ERROR_SUCCESS;
6453 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6455 MSIPACKAGE *package = param;
6459 LPCWSTR desc, component;
6461 component = MSI_RecordGetString( rec, 2 );
6462 comp = msi_get_loaded_component( package, component );
6464 return ERROR_SUCCESS;
6466 comp->Action = msi_get_component_action( package, comp );
6467 if (comp->Action != INSTALLSTATE_ABSENT)
6469 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6470 return ERROR_SUCCESS;
6473 desc = MSI_RecordGetString( rec, 3 );
6474 if (!SQLRemoveTranslatorW( desc, &usage ))
6476 WARN("Failed to remove ODBC translator\n");
6480 FIXME("Usage count reached 0\n");
6483 uirow = MSI_CreateRecord( 2 );
6484 MSI_RecordSetStringW( uirow, 1, desc );
6485 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6486 msi_ui_actiondata( package, szRemoveODBC, uirow );
6487 msiobj_release( &uirow->hdr );
6489 return ERROR_SUCCESS;
6492 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6494 MSIPACKAGE *package = param;
6498 LPCWSTR desc, driver, component;
6499 WORD request = ODBC_REMOVE_SYS_DSN;
6503 static const WCHAR attrs_fmt[] = {
6504 'D','S','N','=','%','s',0 };
6506 component = MSI_RecordGetString( rec, 2 );
6507 comp = msi_get_loaded_component( package, component );
6509 return ERROR_SUCCESS;
6511 comp->Action = msi_get_component_action( package, comp );
6512 if (comp->Action != INSTALLSTATE_ABSENT)
6514 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6515 return ERROR_SUCCESS;
6518 desc = MSI_RecordGetString( rec, 3 );
6519 driver = MSI_RecordGetString( rec, 4 );
6520 registration = MSI_RecordGetInteger( rec, 5 );
6522 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6523 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6525 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6526 attrs = msi_alloc( len * sizeof(WCHAR) );
6528 return ERROR_OUTOFMEMORY;
6530 FIXME("Use ODBCSourceAttribute table\n");
6532 len = sprintfW( attrs, attrs_fmt, desc );
6535 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6537 WARN("Failed to remove ODBC data source\n");
6541 uirow = MSI_CreateRecord( 3 );
6542 MSI_RecordSetStringW( uirow, 1, desc );
6543 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6544 MSI_RecordSetInteger( uirow, 3, request );
6545 msi_ui_actiondata( package, szRemoveODBC, uirow );
6546 msiobj_release( &uirow->hdr );
6548 return ERROR_SUCCESS;
6551 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6553 static const WCHAR driver_query[] = {
6554 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6555 'O','D','B','C','D','r','i','v','e','r',0};
6556 static const WCHAR translator_query[] = {
6557 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6558 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6559 static const WCHAR source_query[] = {
6560 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6561 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6565 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6566 if (rc == ERROR_SUCCESS)
6568 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6569 msiobj_release( &view->hdr );
6570 if (rc != ERROR_SUCCESS)
6573 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6574 if (rc == ERROR_SUCCESS)
6576 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6577 msiobj_release( &view->hdr );
6578 if (rc != ERROR_SUCCESS)
6581 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6582 if (rc == ERROR_SUCCESS)
6584 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6585 msiobj_release( &view->hdr );
6586 if (rc != ERROR_SUCCESS)
6589 return ERROR_SUCCESS;
6592 #define ENV_ACT_SETALWAYS 0x1
6593 #define ENV_ACT_SETABSENT 0x2
6594 #define ENV_ACT_REMOVE 0x4
6595 #define ENV_ACT_REMOVEMATCH 0x8
6597 #define ENV_MOD_MACHINE 0x20000000
6598 #define ENV_MOD_APPEND 0x40000000
6599 #define ENV_MOD_PREFIX 0x80000000
6600 #define ENV_MOD_MASK 0xC0000000
6602 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6604 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6606 LPCWSTR cptr = *name;
6608 static const WCHAR prefix[] = {'[','~',']',0};
6609 static const int prefix_len = 3;
6615 *flags |= ENV_ACT_SETALWAYS;
6616 else if (*cptr == '+')
6617 *flags |= ENV_ACT_SETABSENT;
6618 else if (*cptr == '-')
6619 *flags |= ENV_ACT_REMOVE;
6620 else if (*cptr == '!')
6621 *flags |= ENV_ACT_REMOVEMATCH;
6622 else if (*cptr == '*')
6623 *flags |= ENV_MOD_MACHINE;
6633 ERR("Missing environment variable\n");
6634 return ERROR_FUNCTION_FAILED;
6639 LPCWSTR ptr = *value;
6640 if (!strncmpW(ptr, prefix, prefix_len))
6642 if (ptr[prefix_len] == szSemiColon[0])
6644 *flags |= ENV_MOD_APPEND;
6645 *value += lstrlenW(prefix);
6652 else if (lstrlenW(*value) >= prefix_len)
6654 ptr += lstrlenW(ptr) - prefix_len;
6655 if (!strcmpW( ptr, prefix ))
6657 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6659 *flags |= ENV_MOD_PREFIX;
6660 /* the "[~]" will be removed by deformat_string */;
6670 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6671 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6672 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6673 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6675 ERR("Invalid flags: %08x\n", *flags);
6676 return ERROR_FUNCTION_FAILED;
6680 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6682 return ERROR_SUCCESS;
6685 static UINT open_env_key( DWORD flags, HKEY *key )
6687 static const WCHAR user_env[] =
6688 {'E','n','v','i','r','o','n','m','e','n','t',0};
6689 static const WCHAR machine_env[] =
6690 {'S','y','s','t','e','m','\\',
6691 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6692 'C','o','n','t','r','o','l','\\',
6693 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6694 'E','n','v','i','r','o','n','m','e','n','t',0};
6699 if (flags & ENV_MOD_MACHINE)
6702 root = HKEY_LOCAL_MACHINE;
6707 root = HKEY_CURRENT_USER;
6710 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6711 if (res != ERROR_SUCCESS)
6713 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6714 return ERROR_FUNCTION_FAILED;
6717 return ERROR_SUCCESS;
6720 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6722 MSIPACKAGE *package = param;
6723 LPCWSTR name, value, component;
6724 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6725 DWORD flags, type, size;
6732 component = MSI_RecordGetString(rec, 4);
6733 comp = msi_get_loaded_component(package, component);
6735 return ERROR_SUCCESS;
6737 comp->Action = msi_get_component_action( package, comp );
6738 if (comp->Action != INSTALLSTATE_LOCAL)
6740 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6741 return ERROR_SUCCESS;
6743 name = MSI_RecordGetString(rec, 2);
6744 value = MSI_RecordGetString(rec, 3);
6746 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6748 res = env_parse_flags(&name, &value, &flags);
6749 if (res != ERROR_SUCCESS || !value)
6752 if (value && !deformat_string(package, value, &deformatted))
6754 res = ERROR_OUTOFMEMORY;
6758 value = deformatted;
6760 res = open_env_key( flags, &env );
6761 if (res != ERROR_SUCCESS)
6764 if (flags & ENV_MOD_MACHINE)
6765 action |= 0x20000000;
6769 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6770 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6771 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6774 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6778 /* Nothing to do. */
6781 res = ERROR_SUCCESS;
6785 /* If we are appending but the string was empty, strip ; */
6786 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6788 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6789 newval = strdupW(value);
6792 res = ERROR_OUTOFMEMORY;
6800 /* Contrary to MSDN, +-variable to [~];path works */
6801 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6803 res = ERROR_SUCCESS;
6807 data = msi_alloc(size);
6811 return ERROR_OUTOFMEMORY;
6814 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6815 if (res != ERROR_SUCCESS)
6818 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6821 res = RegDeleteValueW(env, name);
6822 if (res != ERROR_SUCCESS)
6823 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6827 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6828 if (flags & ENV_MOD_MASK)
6832 if (flags & ENV_MOD_APPEND) multiplier++;
6833 if (flags & ENV_MOD_PREFIX) multiplier++;
6834 mod_size = lstrlenW(value) * multiplier;
6835 size += mod_size * sizeof(WCHAR);
6838 newval = msi_alloc(size);
6842 res = ERROR_OUTOFMEMORY;
6846 if (flags & ENV_MOD_PREFIX)
6848 lstrcpyW(newval, value);
6849 ptr = newval + lstrlenW(value);
6850 action |= 0x80000000;
6853 lstrcpyW(ptr, data);
6855 if (flags & ENV_MOD_APPEND)
6857 lstrcatW(newval, value);
6858 action |= 0x40000000;
6861 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6862 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6865 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6869 uirow = MSI_CreateRecord( 3 );
6870 MSI_RecordSetStringW( uirow, 1, name );
6871 MSI_RecordSetStringW( uirow, 2, newval );
6872 MSI_RecordSetInteger( uirow, 3, action );
6873 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6874 msiobj_release( &uirow->hdr );
6876 if (env) RegCloseKey(env);
6877 msi_free(deformatted);
6883 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6885 static const WCHAR query[] = {
6886 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6887 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6891 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6892 if (rc != ERROR_SUCCESS)
6893 return ERROR_SUCCESS;
6895 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6896 msiobj_release(&view->hdr);
6900 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6902 MSIPACKAGE *package = param;
6903 LPCWSTR name, value, component;
6904 LPWSTR deformatted = NULL;
6913 component = MSI_RecordGetString( rec, 4 );
6914 comp = msi_get_loaded_component( package, component );
6916 return ERROR_SUCCESS;
6918 comp->Action = msi_get_component_action( package, comp );
6919 if (comp->Action != INSTALLSTATE_ABSENT)
6921 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6922 return ERROR_SUCCESS;
6924 name = MSI_RecordGetString( rec, 2 );
6925 value = MSI_RecordGetString( rec, 3 );
6927 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6929 r = env_parse_flags( &name, &value, &flags );
6930 if (r != ERROR_SUCCESS)
6933 if (!(flags & ENV_ACT_REMOVE))
6935 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6936 return ERROR_SUCCESS;
6939 if (value && !deformat_string( package, value, &deformatted ))
6940 return ERROR_OUTOFMEMORY;
6942 value = deformatted;
6944 r = open_env_key( flags, &env );
6945 if (r != ERROR_SUCCESS)
6951 if (flags & ENV_MOD_MACHINE)
6952 action |= 0x20000000;
6954 TRACE("Removing %s\n", debugstr_w(name));
6956 res = RegDeleteValueW( env, name );
6957 if (res != ERROR_SUCCESS)
6959 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6964 uirow = MSI_CreateRecord( 3 );
6965 MSI_RecordSetStringW( uirow, 1, name );
6966 MSI_RecordSetStringW( uirow, 2, value );
6967 MSI_RecordSetInteger( uirow, 3, action );
6968 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6969 msiobj_release( &uirow->hdr );
6971 if (env) RegCloseKey( env );
6972 msi_free( deformatted );
6976 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6978 static const WCHAR query[] = {
6979 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6980 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6984 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6985 if (rc != ERROR_SUCCESS)
6986 return ERROR_SUCCESS;
6988 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6989 msiobj_release( &view->hdr );
6993 UINT msi_validate_product_id( MSIPACKAGE *package )
6995 LPWSTR key, template, id;
6996 UINT r = ERROR_SUCCESS;
6998 id = msi_dup_property( package->db, szProductID );
7002 return ERROR_SUCCESS;
7004 template = msi_dup_property( package->db, szPIDTemplate );
7005 key = msi_dup_property( package->db, szPIDKEY );
7006 if (key && template)
7008 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7009 r = msi_set_property( package->db, szProductID, key, -1 );
7011 msi_free( template );
7016 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7018 return msi_validate_product_id( package );
7021 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7024 package->need_reboot_at_end = 1;
7025 return ERROR_SUCCESS;
7028 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7030 static const WCHAR szAvailableFreeReg[] =
7031 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7033 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7035 TRACE("%p %d kilobytes\n", package, space);
7037 uirow = MSI_CreateRecord( 1 );
7038 MSI_RecordSetInteger( uirow, 1, space );
7039 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
7040 msiobj_release( &uirow->hdr );
7042 return ERROR_SUCCESS;
7045 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7047 TRACE("%p\n", package);
7049 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7050 return ERROR_SUCCESS;
7053 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7055 FIXME("%p\n", package);
7056 return ERROR_SUCCESS;
7059 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7061 static const WCHAR driver_query[] = {
7062 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7063 'O','D','B','C','D','r','i','v','e','r',0};
7064 static const WCHAR translator_query[] = {
7065 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7066 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
7070 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7071 if (r == ERROR_SUCCESS)
7074 r = MSI_IterateRecords( view, &count, NULL, package );
7075 msiobj_release( &view->hdr );
7076 if (r != ERROR_SUCCESS)
7078 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7080 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7081 if (r == ERROR_SUCCESS)
7084 r = MSI_IterateRecords( view, &count, NULL, package );
7085 msiobj_release( &view->hdr );
7086 if (r != ERROR_SUCCESS)
7088 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7090 return ERROR_SUCCESS;
7093 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7095 static const WCHAR fmtW[] =
7096 {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0};
7097 MSIPACKAGE *package = param;
7098 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7099 UINT len = sizeof(fmtW)/sizeof(fmtW[0]);
7100 WCHAR *product, *features, *cmd;
7102 PROCESS_INFORMATION info;
7105 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7107 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7109 len += strlenW( product );
7111 len += strlenW( features );
7113 len += sizeof(szAll) / sizeof(szAll[0]);
7115 if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
7117 msi_free( product );
7118 msi_free( features );
7119 return ERROR_OUTOFMEMORY;
7121 sprintfW( cmd, fmtW, product, features ? features : szAll );
7122 msi_free( product );
7123 msi_free( features );
7125 memset( &si, 0, sizeof(STARTUPINFOW) );
7126 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7128 if (!ret) return GetLastError();
7129 CloseHandle( info.hThread );
7131 WaitForSingleObject( info.hProcess, INFINITE );
7132 CloseHandle( info.hProcess );
7133 return ERROR_SUCCESS;
7136 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7138 static const WCHAR query[] = {
7139 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7143 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7144 if (r == ERROR_SUCCESS)
7146 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7147 msiobj_release( &view->hdr );
7148 if (r != ERROR_SUCCESS)
7151 return ERROR_SUCCESS;
7154 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7156 MSIPACKAGE *package = param;
7157 int attributes = MSI_RecordGetInteger( rec, 5 );
7159 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7161 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7162 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7163 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7164 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7168 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7170 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7171 if (r != ERROR_SUCCESS)
7172 return ERROR_SUCCESS;
7176 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7177 if (r != ERROR_SUCCESS)
7178 return ERROR_SUCCESS;
7180 RegCloseKey( hkey );
7182 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7183 debugstr_w(upgrade_code), debugstr_w(version_min),
7184 debugstr_w(version_max), debugstr_w(language));
7186 return ERROR_SUCCESS;
7189 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7191 static const WCHAR query[] = {
7192 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7193 'U','p','g','r','a','d','e',0};
7197 if (msi_get_property_int( package->db, szInstalled, 0 ))
7199 TRACE("product is installed, skipping action\n");
7200 return ERROR_SUCCESS;
7202 if (msi_get_property_int( package->db, szPreselected, 0 ))
7204 TRACE("Preselected property is set, not migrating feature states\n");
7205 return ERROR_SUCCESS;
7207 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7208 if (r == ERROR_SUCCESS)
7210 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7211 msiobj_release( &view->hdr );
7212 if (r != ERROR_SUCCESS)
7215 return ERROR_SUCCESS;
7218 static void bind_image( const char *filename, const char *path )
7220 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7222 WARN("failed to bind image %u\n", GetLastError());
7226 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7230 MSIPACKAGE *package = param;
7231 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7232 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7233 char *filenameA, *pathA;
7234 WCHAR *pathW, **path_list;
7236 if (!(file = msi_get_loaded_file( package, key )))
7238 WARN("file %s not found\n", debugstr_w(key));
7239 return ERROR_SUCCESS;
7241 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7242 path_list = msi_split_string( paths, ';' );
7243 if (!path_list) bind_image( filenameA, NULL );
7246 for (i = 0; path_list[i] && path_list[i][0]; i++)
7248 deformat_string( package, path_list[i], &pathW );
7249 if ((pathA = strdupWtoA( pathW )))
7251 bind_image( filenameA, pathA );
7257 msi_free( path_list );
7258 msi_free( filenameA );
7259 return ERROR_SUCCESS;
7262 static UINT ACTION_BindImage( MSIPACKAGE *package )
7264 static const WCHAR query[] = {
7265 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7266 'B','i','n','d','I','m','a','g','e',0};
7270 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7271 if (r == ERROR_SUCCESS)
7273 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7274 msiobj_release( &view->hdr );
7275 if (r != ERROR_SUCCESS)
7278 return ERROR_SUCCESS;
7281 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7283 static const WCHAR query[] = {
7284 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7289 r = MSI_OpenQuery( package->db, &view, query, table );
7290 if (r == ERROR_SUCCESS)
7292 r = MSI_IterateRecords(view, &count, NULL, package);
7293 msiobj_release(&view->hdr);
7294 if (r != ERROR_SUCCESS)
7297 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7298 return ERROR_SUCCESS;
7301 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7303 static const WCHAR table[] = {
7304 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7305 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7308 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7310 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7311 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7314 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7316 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7317 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7320 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7322 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7323 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7326 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7328 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7329 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7334 const WCHAR *action;
7335 UINT (*handler)(MSIPACKAGE *);
7336 const WCHAR *action_rollback;
7340 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7341 { szAppSearch, ACTION_AppSearch, NULL },
7342 { szBindImage, ACTION_BindImage, NULL },
7343 { szCCPSearch, ACTION_CCPSearch, NULL },
7344 { szCostFinalize, ACTION_CostFinalize, NULL },
7345 { szCostInitialize, ACTION_CostInitialize, NULL },
7346 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7347 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7348 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7349 { szDisableRollback, ACTION_DisableRollback, NULL },
7350 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7351 { szExecuteAction, ACTION_ExecuteAction, NULL },
7352 { szFileCost, ACTION_FileCost, NULL },
7353 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7354 { szForceReboot, ACTION_ForceReboot, NULL },
7355 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7356 { szInstallExecute, ACTION_InstallExecute, NULL },
7357 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7358 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7359 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7360 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7361 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7362 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7363 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7364 { szInstallValidate, ACTION_InstallValidate, NULL },
7365 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7366 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7367 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7368 { szMoveFiles, ACTION_MoveFiles, NULL },
7369 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7370 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7371 { szPatchFiles, ACTION_PatchFiles, NULL },
7372 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7373 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7374 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7375 { szPublishProduct, ACTION_PublishProduct, NULL },
7376 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7377 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7378 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7379 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7380 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7381 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7382 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7383 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7384 { szRegisterUser, ACTION_RegisterUser, NULL },
7385 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7386 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7387 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7388 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7389 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7390 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7391 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7392 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7393 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7394 { szResolveSource, ACTION_ResolveSource, NULL },
7395 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7396 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7397 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7398 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7399 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7400 { szStartServices, ACTION_StartServices, szStopServices },
7401 { szStopServices, ACTION_StopServices, szStartServices },
7402 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7403 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7404 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7405 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7406 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7407 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7408 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7409 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7410 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7411 { szValidateProductID, ACTION_ValidateProductID, NULL },
7412 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7413 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7414 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7415 { NULL, NULL, NULL }
7418 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7424 while (StandardActions[i].action != NULL)
7426 if (!strcmpW( StandardActions[i].action, action ))
7428 ui_actionstart( package, action );
7429 if (StandardActions[i].handler)
7431 ui_actioninfo( package, action, TRUE, 0 );
7432 *rc = StandardActions[i].handler( package );
7433 ui_actioninfo( package, action, FALSE, *rc );
7435 if (StandardActions[i].action_rollback && !package->need_rollback)
7437 TRACE("scheduling rollback action\n");
7438 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7443 FIXME("unhandled standard action %s\n", debugstr_w(action));
7444 *rc = ERROR_SUCCESS;
7454 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7456 UINT rc = ERROR_SUCCESS;
7459 TRACE("Performing action (%s)\n", debugstr_w(action));
7461 handled = ACTION_HandleStandardAction(package, action, &rc);
7464 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7468 WARN("unhandled msi action %s\n", debugstr_w(action));
7469 rc = ERROR_FUNCTION_NOT_CALLED;
7475 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7477 UINT rc = ERROR_SUCCESS;
7478 BOOL handled = FALSE;
7480 TRACE("Performing action (%s)\n", debugstr_w(action));
7482 package->action_progress_increment = 0;
7483 handled = ACTION_HandleStandardAction(package, action, &rc);
7486 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7488 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7493 WARN("unhandled msi action %s\n", debugstr_w(action));
7494 rc = ERROR_FUNCTION_NOT_CALLED;
7500 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7502 UINT rc = ERROR_SUCCESS;
7505 static const WCHAR query[] =
7506 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7507 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7508 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7509 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7510 static const WCHAR ui_query[] =
7511 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7512 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7513 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7514 ' ', '=',' ','%','i',0};
7516 if (needs_ui_sequence(package))
7517 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7519 row = MSI_QueryGetRecord(package->db, query, seq);
7523 LPCWSTR action, cond;
7525 TRACE("Running the actions\n");
7527 /* check conditions */
7528 cond = MSI_RecordGetString(row, 2);
7530 /* this is a hack to skip errors in the condition code */
7531 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7533 msiobj_release(&row->hdr);
7534 return ERROR_SUCCESS;
7537 action = MSI_RecordGetString(row, 1);
7540 ERR("failed to fetch action\n");
7541 msiobj_release(&row->hdr);
7542 return ERROR_FUNCTION_FAILED;
7545 if (needs_ui_sequence(package))
7546 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7548 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7550 msiobj_release(&row->hdr);
7556 /****************************************************
7557 * TOP level entry points
7558 *****************************************************/
7560 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7561 LPCWSTR szCommandLine )
7563 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7564 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7565 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7566 WCHAR *reinstall = NULL;
7570 msi_set_property( package->db, szAction, szInstall, -1 );
7572 package->script->InWhatSequence = SEQUENCE_INSTALL;
7579 dir = strdupW(szPackagePath);
7580 p = strrchrW(dir, '\\');
7584 file = szPackagePath + (p - dir);
7589 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7590 GetCurrentDirectoryW(MAX_PATH, dir);
7591 lstrcatW(dir, szBackSlash);
7592 file = szPackagePath;
7595 msi_free( package->PackagePath );
7596 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7597 if (!package->PackagePath)
7600 return ERROR_OUTOFMEMORY;
7603 lstrcpyW(package->PackagePath, dir);
7604 lstrcatW(package->PackagePath, file);
7607 msi_set_sourcedir_props(package, FALSE);
7610 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7611 if (rc != ERROR_SUCCESS)
7614 msi_apply_transforms( package );
7615 msi_apply_patches( package );
7617 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7619 TRACE("setting reinstall property\n");
7620 msi_set_property( package->db, szReinstall, szAll, -1 );
7623 /* properties may have been added by a transform */
7624 msi_clone_properties( package );
7626 msi_parse_command_line( package, szCommandLine, FALSE );
7627 msi_adjust_privilege_properties( package );
7628 msi_set_context( package );
7630 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7632 TRACE("disabling rollback\n");
7633 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7636 if (needs_ui_sequence( package))
7638 package->script->InWhatSequence |= SEQUENCE_UI;
7639 rc = ACTION_ProcessUISequence(package);
7640 ui_exists = ui_sequence_exists(package);
7641 if (rc == ERROR_SUCCESS || !ui_exists)
7643 package->script->InWhatSequence |= SEQUENCE_EXEC;
7644 rc = ACTION_ProcessExecSequence(package, ui_exists);
7648 rc = ACTION_ProcessExecSequence(package, FALSE);
7650 package->script->CurrentlyScripting = FALSE;
7652 /* process the ending type action */
7653 if (rc == ERROR_SUCCESS)
7654 ACTION_PerformActionSequence(package, -1);
7655 else if (rc == ERROR_INSTALL_USEREXIT)
7656 ACTION_PerformActionSequence(package, -2);
7657 else if (rc == ERROR_INSTALL_SUSPEND)
7658 ACTION_PerformActionSequence(package, -4);
7661 ACTION_PerformActionSequence(package, -3);
7662 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7664 package->need_rollback = TRUE;
7668 /* finish up running custom actions */
7669 ACTION_FinishCustomActions(package);
7671 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7673 WARN("installation failed, running rollback script\n");
7674 execute_script( package, SCRIPT_ROLLBACK );
7676 msi_free( reinstall );
7678 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7679 return ERROR_SUCCESS_REBOOT_REQUIRED;