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 );
1787 if (ret && !package->full_reinstall)
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 && component->ComponentId)
1987 component->Action = INSTALLSTATE_ABSENT;
1988 component->ActionRequest = INSTALLSTATE_ABSENT;
1992 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1994 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1996 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1997 component->Action = INSTALLSTATE_LOCAL;
1998 component->ActionRequest = INSTALLSTATE_LOCAL;
2001 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2002 component->Installed == INSTALLSTATE_SOURCE &&
2003 component->hasSourceFeature)
2005 component->Action = INSTALLSTATE_UNKNOWN;
2006 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2009 TRACE("component %s (installed %d request %d action %d)\n",
2010 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2012 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
2013 component->num_clients++;
2014 else if (component->Action == INSTALLSTATE_ABSENT)
2015 component->num_clients--;
2018 return ERROR_SUCCESS;
2021 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2023 MSIPACKAGE *package = param;
2025 MSIFEATURE *feature;
2027 name = MSI_RecordGetString( row, 1 );
2029 feature = msi_get_loaded_feature( package, name );
2031 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2035 Condition = MSI_RecordGetString(row,3);
2037 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2039 int level = MSI_RecordGetInteger(row,2);
2040 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2041 feature->Level = level;
2044 return ERROR_SUCCESS;
2047 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2049 static const WCHAR name[] = {'\\',0};
2050 VS_FIXEDFILEINFO *ptr, *ret;
2052 DWORD versize, handle;
2055 versize = GetFileVersionInfoSizeW( filename, &handle );
2059 version = msi_alloc( versize );
2063 GetFileVersionInfoW( filename, 0, versize, version );
2065 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2067 msi_free( version );
2071 ret = msi_alloc( sz );
2072 memcpy( ret, ptr, sz );
2074 msi_free( version );
2078 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2082 msi_parse_version_string( version, &ms, &ls );
2084 if (fi->dwFileVersionMS > ms) return 1;
2085 else if (fi->dwFileVersionMS < ms) return -1;
2086 else if (fi->dwFileVersionLS > ls) return 1;
2087 else if (fi->dwFileVersionLS < ls) return -1;
2091 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2095 msi_parse_version_string( ver1, &ms1, NULL );
2096 msi_parse_version_string( ver2, &ms2, NULL );
2098 if (ms1 > ms2) return 1;
2099 else if (ms1 < ms2) return -1;
2103 DWORD msi_get_disk_file_size( LPCWSTR filename )
2108 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2109 if (file == INVALID_HANDLE_VALUE)
2110 return INVALID_FILE_SIZE;
2112 size = GetFileSize( file, NULL );
2113 TRACE("size is %u\n", size);
2114 CloseHandle( file );
2118 BOOL msi_file_hash_matches( MSIFILE *file )
2121 MSIFILEHASHINFO hash;
2123 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2124 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2125 if (r != ERROR_SUCCESS)
2128 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2131 static WCHAR *get_temp_dir( void )
2134 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2136 GetTempPathW( MAX_PATH, tmp );
2139 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2140 if (CreateDirectoryW( dir, NULL )) break;
2142 return strdupW( dir );
2146 * msi_build_directory_name()
2148 * This function is to save messing round with directory names
2149 * It handles adding backslashes between path segments,
2150 * and can add \ at the end of the directory name if told to.
2152 * It takes a variable number of arguments.
2153 * It always allocates a new string for the result, so make sure
2154 * to free the return value when finished with it.
2156 * The first arg is the number of path segments that follow.
2157 * The arguments following count are a list of path segments.
2158 * A path segment may be NULL.
2160 * Path segments will be added with a \ separating them.
2161 * A \ will not be added after the last segment, however if the
2162 * last segment is NULL, then the last character will be a \
2164 WCHAR *msi_build_directory_name( DWORD count, ... )
2170 va_start( va, count );
2171 for (i = 0; i < count; i++)
2173 const WCHAR *str = va_arg( va, const WCHAR * );
2174 if (str) sz += strlenW( str ) + 1;
2178 dir = msi_alloc( sz * sizeof(WCHAR) );
2181 va_start( va, count );
2182 for (i = 0; i < count; i++)
2184 const WCHAR *str = va_arg( va, const WCHAR * );
2186 strcatW( dir, str );
2187 if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2193 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2195 MSIASSEMBLY *assembly = file->Component->assembly;
2197 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2199 msi_free( file->TargetPath );
2200 if (assembly && !assembly->application)
2202 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2203 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2204 msi_track_tempfile( package, file->TargetPath );
2208 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2209 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2212 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2215 static UINT calculate_file_cost( MSIPACKAGE *package )
2217 VS_FIXEDFILEINFO *file_version;
2218 WCHAR *font_version;
2221 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2223 MSICOMPONENT *comp = file->Component;
2226 if (!comp->Enabled) continue;
2228 if (file->IsCompressed)
2229 comp->ForceLocalState = TRUE;
2231 set_target_path( package, file );
2233 if ((comp->assembly && !comp->assembly->installed) ||
2234 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2236 comp->Cost += file->FileSize;
2239 file_size = msi_get_disk_file_size( file->TargetPath );
2243 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2245 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2247 comp->Cost += file->FileSize - file_size;
2249 msi_free( file_version );
2252 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2254 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2256 comp->Cost += file->FileSize - file_size;
2258 msi_free( font_version );
2262 if (file_size != file->FileSize)
2264 comp->Cost += file->FileSize - file_size;
2267 return ERROR_SUCCESS;
2270 WCHAR *msi_normalize_path( const WCHAR *in )
2272 const WCHAR *p = in;
2274 int n, len = strlenW( in ) + 2;
2276 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2281 /* copy until the end of the string or a space */
2282 while (*p != ' ' && (*q = *p))
2285 /* reduce many backslashes to one */
2286 if (*p != '\\' || *q != '\\')
2290 /* quit at the end of the string */
2294 /* count the number of spaces */
2299 /* if it's leading or trailing space, skip it */
2300 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2302 else /* copy n spaces */
2303 while (n && (*q++ = *p++)) n--;
2305 while (q - ret > 0 && q[-1] == ' ') q--;
2306 if (q - ret > 0 && q[-1] != '\\')
2314 static WCHAR *get_install_location( MSIPACKAGE *package )
2319 if (!package->ProductCode) return NULL;
2320 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ))
2322 path = msi_reg_get_val_str( hkey, szInstallLocation );
2323 RegCloseKey( hkey );
2327 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2330 MSIFOLDER *folder, *parent, *child;
2331 WCHAR *path, *normalized_path;
2333 TRACE("resolving %s\n", debugstr_w(name));
2335 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2337 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2339 if (!(path = get_install_location( package )) &&
2340 (!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))))
2342 path = msi_dup_property( package->db, szRootDrive );
2345 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2347 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2349 parent = msi_get_loaded_folder( package, folder->Parent );
2350 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2353 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2355 normalized_path = msi_normalize_path( path );
2357 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2359 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2360 msi_free( normalized_path );
2363 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2364 msi_free( folder->ResolvedTarget );
2365 folder->ResolvedTarget = normalized_path;
2367 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2370 msi_resolve_target_folder( package, child->Directory, load_prop );
2372 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2375 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2377 static const WCHAR query[] = {
2378 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2379 '`','C','o','n','d','i','t','i','o','n','`',0};
2380 static const WCHAR szOutOfDiskSpace[] = {
2381 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2387 TRACE("Building directory properties\n");
2388 msi_resolve_target_folder( package, szTargetDir, TRUE );
2390 TRACE("Evaluating component conditions\n");
2391 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2393 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2395 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2396 comp->Enabled = FALSE;
2399 comp->Enabled = TRUE;
2401 get_client_counts( package );
2403 /* read components states from the registry */
2404 ACTION_GetComponentInstallStates(package);
2405 ACTION_GetFeatureInstallStates(package);
2407 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2409 TRACE("Evaluating feature conditions\n");
2411 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2412 if (rc == ERROR_SUCCESS)
2414 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2415 msiobj_release( &view->hdr );
2416 if (rc != ERROR_SUCCESS)
2421 TRACE("Calculating file cost\n");
2422 calculate_file_cost( package );
2424 msi_set_property( package->db, szCostingComplete, szOne, -1 );
2425 /* set default run level if not set */
2426 level = msi_dup_property( package->db, szInstallLevel );
2428 msi_set_property( package->db, szInstallLevel, szOne, -1 );
2431 /* FIXME: check volume disk space */
2432 msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
2434 return MSI_SetFeatureStates(package);
2437 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type, DWORD *size )
2443 *size = sizeof(WCHAR);
2445 if ((data = msi_alloc( *size ))) *(WCHAR *)data = 0;
2448 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2454 LPWSTR deformated = NULL;
2457 deformat_string(package, &value[2], &deformated);
2459 /* binary value type */
2463 *size = (strlenW(ptr)/2)+1;
2465 *size = strlenW(ptr)/2;
2467 data = msi_alloc(*size);
2473 /* if uneven pad with a zero in front */
2479 data[count] = (BYTE)strtol(byte,NULL,0);
2481 TRACE("Uneven byte count\n");
2489 data[count] = (BYTE)strtol(byte,NULL,0);
2492 msi_free(deformated);
2494 TRACE("Data %i bytes(%i)\n",*size,count);
2501 deformat_string(package, &value[1], &deformated);
2504 *size = sizeof(DWORD);
2505 data = msi_alloc(*size);
2511 if ( (*p < '0') || (*p > '9') )
2517 if (deformated[0] == '-')
2520 TRACE("DWORD %i\n",*(LPDWORD)data);
2522 msi_free(deformated);
2527 const WCHAR *ptr = value;
2531 if (value[0] == '#')
2534 if (value[1] == '%')
2537 *type = REG_EXPAND_SZ;
2540 len = deformat_string( package, ptr, (WCHAR **)&data );
2541 if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
2542 *size = (len + 1) * sizeof(WCHAR);
2547 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2554 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2556 *root_key = HKEY_LOCAL_MACHINE;
2561 *root_key = HKEY_CURRENT_USER;
2566 *root_key = HKEY_CLASSES_ROOT;
2570 *root_key = HKEY_CURRENT_USER;
2574 *root_key = HKEY_LOCAL_MACHINE;
2578 *root_key = HKEY_USERS;
2582 ERR("Unknown root %i\n", root);
2589 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2591 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2592 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2594 if ((is_64bit || is_wow64) &&
2595 !(comp->Attributes & msidbComponentAttributes64bit) &&
2596 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2601 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2602 if (!(path_32node = msi_alloc( size ))) return NULL;
2604 memcpy( path_32node, path, len * sizeof(WCHAR) );
2605 strcpyW( path_32node + len, szWow6432Node );
2606 strcatW( path_32node, szBackSlash );
2607 strcatW( path_32node, path + len );
2610 return strdupW( path );
2613 static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
2615 REGSAM access = KEY_ALL_ACCESS;
2616 WCHAR *subkey, *p, *q;
2617 HKEY hkey, ret = NULL;
2620 if (is_wow64) access |= KEY_WOW64_64KEY;
2622 if (!(subkey = strdupW( path ))) return NULL;
2624 if ((q = strchrW( p, '\\' ))) *q = 0;
2626 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2628 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2631 TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
2637 ret = open_key( hkey, q + 1, create );
2638 RegCloseKey( hkey );
2645 static BOOL is_special_entry( const WCHAR *name )
2647 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2650 static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count )
2652 const WCHAR *p = str;
2657 if (!str) return NULL;
2658 while ((p - str) < len)
2660 p += strlenW( p ) + 1;
2663 if (!(ret = msi_alloc( *count * sizeof(WCHAR *) ))) return NULL;
2665 while ((p - str) < len)
2667 if (!(ret[i] = strdupW( p )))
2669 for (; i >= 0; i--) msi_free( ret[i] );
2673 p += strlenW( p ) + 1;
2679 static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count,
2680 WCHAR **right, DWORD right_count, DWORD *size )
2685 *size = sizeof(WCHAR);
2686 for (i = 0; i < left_count; i++) *size += (strlenW( left[i] ) + 1) * sizeof(WCHAR);
2687 for (i = 0; i < right_count; i++) *size += (strlenW( right[i] ) + 1) * sizeof(WCHAR);
2689 if (!(ret = p = msi_alloc( *size ))) return NULL;
2691 for (i = 0; i < left_count; i++)
2693 strcpyW( p, left[i] );
2694 p += strlenW( p ) + 1;
2696 for (i = 0; i < right_count; i++)
2698 strcpyW( p, right[i] );
2699 p += strlenW( p ) + 1;
2705 static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
2706 WCHAR **new, DWORD new_count )
2708 DWORD ret = old_count;
2709 unsigned int i, j, k;
2711 for (i = 0; i < new_count; i++)
2713 for (j = 0; j < old_count; j++)
2715 if (old[j] && !strcmpW( new[i], old[j] ))
2718 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
2734 static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
2735 WCHAR **new, DWORD new_count, DWORD *size )
2739 case JOIN_OP_APPEND:
2740 old_count = remove_duplicate_values( old, old_count, new, new_count );
2741 return flatten_multi_string_values( old, old_count, new, new_count, size );
2743 case JOIN_OP_PREPEND:
2744 old_count = remove_duplicate_values( old, old_count, new, new_count );
2745 return flatten_multi_string_values( new, new_count, old, old_count, size );
2747 case JOIN_OP_REPLACE:
2748 return flatten_multi_string_values( new, new_count, NULL, 0, size );
2751 ERR("unhandled join op %u\n", op);
2756 static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size,
2757 BYTE *new_value, DWORD new_size, DWORD *size )
2759 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
2760 const WCHAR *new_ptr = NULL, *old_ptr = NULL;
2761 enum join_op op = JOIN_OP_REPLACE;
2762 WCHAR **old = NULL, **new = NULL;
2765 if (new_size / sizeof(WCHAR) - 1 > 1)
2767 new_ptr = (const WCHAR *)new_value;
2768 new_len = new_size / sizeof(WCHAR) - 1;
2770 if (!new_ptr[0] && new_ptr[new_len - 1])
2772 op = JOIN_OP_APPEND;
2776 else if (new_ptr[0] && !new_ptr[new_len - 1])
2778 op = JOIN_OP_PREPEND;
2781 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2783 op = JOIN_OP_REPLACE;
2787 new = split_multi_string_values( new_ptr, new_len, &new_count );
2789 if (old_size / sizeof(WCHAR) - 1 > 1)
2791 old_ptr = (const WCHAR *)old_value;
2792 old_len = old_size / sizeof(WCHAR) - 1;
2793 old = split_multi_string_values( old_ptr, old_len, &old_count );
2795 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
2796 for (i = 0; i < old_count; i++) msi_free( old[i] );
2797 for (i = 0; i < new_count; i++) msi_free( new[i] );
2803 static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
2806 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
2807 if (!(ret = msi_alloc( *size ))) return NULL;
2808 RegQueryValueExW( hkey, name, NULL, type, ret, size );
2812 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2814 MSIPACKAGE *package = param;
2815 BYTE *new_value, *old_value = NULL;
2816 HKEY root_key, hkey;
2817 DWORD type, old_type, new_size, old_size = 0;
2818 LPWSTR deformated, uikey, keypath;
2819 const WCHAR *szRoot, *component, *name, *key, *str;
2823 BOOL check_first = FALSE;
2826 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2828 component = MSI_RecordGetString(row, 6);
2829 comp = msi_get_loaded_component(package,component);
2831 return ERROR_SUCCESS;
2833 comp->Action = msi_get_component_action( package, comp );
2834 if (comp->Action != INSTALLSTATE_LOCAL)
2836 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2837 return ERROR_SUCCESS;
2840 name = MSI_RecordGetString(row, 4);
2841 if( MSI_RecordIsNull(row,5) && name )
2843 /* null values can have special meanings */
2844 if (name[0]=='-' && name[1] == 0)
2845 return ERROR_SUCCESS;
2846 if ((name[0] == '+' || name[0] == '*') && !name[1])
2850 root = MSI_RecordGetInteger(row,2);
2851 key = MSI_RecordGetString(row, 3);
2853 szRoot = get_root_key( package, root, &root_key );
2855 return ERROR_SUCCESS;
2857 deformat_string(package, key , &deformated);
2858 uikey = msi_alloc( (strlenW(deformated) + strlenW(szRoot) + 1) * sizeof(WCHAR) );
2859 strcpyW(uikey,szRoot);
2860 strcatW(uikey,deformated);
2862 keypath = get_keypath( comp, root_key, deformated );
2863 msi_free( deformated );
2864 if (!(hkey = open_key( root_key, keypath, TRUE )))
2866 ERR("Could not create key %s\n", debugstr_w(keypath));
2869 return ERROR_FUNCTION_FAILED;
2871 str = msi_record_get_string( row, 5, &len );
2872 if (str && len > strlenW( str ))
2874 type = REG_MULTI_SZ;
2875 new_size = (len + 1) * sizeof(WCHAR);
2876 new_value = (BYTE *)msi_strdupW( str, len );
2878 else new_value = parse_value( package, str, &type, &new_size );
2879 deformat_string(package, name, &deformated);
2881 if (!is_special_entry( name ))
2883 old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
2884 if (type == REG_MULTI_SZ)
2887 if (old_value && old_type != REG_MULTI_SZ)
2889 msi_free( old_value );
2893 new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size );
2894 msi_free( new_value );
2899 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2900 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2902 else if (!old_value)
2904 if (deformated || new_size)
2906 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2907 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2910 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
2914 uirow = MSI_CreateRecord(3);
2915 MSI_RecordSetStringW(uirow,2,deformated);
2916 MSI_RecordSetStringW(uirow,1,uikey);
2917 if (type == REG_SZ || type == REG_EXPAND_SZ)
2918 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
2919 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2920 msiobj_release( &uirow->hdr );
2922 msi_free(new_value);
2923 msi_free(old_value);
2924 msi_free(deformated);
2928 return ERROR_SUCCESS;
2931 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2933 static const WCHAR query[] = {
2934 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2935 '`','R','e','g','i','s','t','r','y','`',0};
2939 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2940 if (rc != ERROR_SUCCESS)
2941 return ERROR_SUCCESS;
2943 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2944 msiobj_release(&view->hdr);
2948 static void delete_key( HKEY root, const WCHAR *path )
2955 if (is_wow64) access |= KEY_WOW64_64KEY;
2957 if (!(subkey = strdupW( path ))) return;
2960 if ((p = strrchrW( subkey, '\\' ))) *p = 0;
2961 hkey = open_key( root, subkey, FALSE );
2964 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2966 res = RegDeleteKeyExW( root, subkey, access, 0 );
2969 TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
2972 if (p && p[1]) RegCloseKey( hkey );
2978 static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
2982 DWORD num_subkeys, num_values;
2984 if ((hkey = open_key( root, path, FALSE )))
2986 if ((res = RegDeleteValueW( hkey, value )))
2987 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2989 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2990 NULL, NULL, NULL, NULL );
2991 RegCloseKey( hkey );
2992 if (!res && !num_subkeys && !num_values)
2994 TRACE("removing empty key %s\n", debugstr_w(path));
2995 delete_key( root, path );
3000 static void delete_tree( HKEY root, const WCHAR *path )
3005 if (!(hkey = open_key( root, path, FALSE ))) return;
3006 res = RegDeleteTreeW( hkey, NULL );
3007 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
3008 delete_key( root, path );
3009 RegCloseKey( hkey );
3012 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
3014 MSIPACKAGE *package = param;
3015 LPCWSTR component, name, key_str, root_key_str;
3016 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3019 BOOL delete_key = FALSE;
3024 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
3026 component = MSI_RecordGetString( row, 6 );
3027 comp = msi_get_loaded_component( package, component );
3029 return ERROR_SUCCESS;
3031 comp->Action = msi_get_component_action( package, comp );
3032 if (comp->Action != INSTALLSTATE_ABSENT)
3034 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3035 return ERROR_SUCCESS;
3038 name = MSI_RecordGetString( row, 4 );
3039 if (MSI_RecordIsNull( row, 5 ) && name )
3041 if (name[0] == '+' && !name[1])
3042 return ERROR_SUCCESS;
3043 if ((name[0] == '-' || name[0] == '*') && !name[1])
3050 root = MSI_RecordGetInteger( row, 2 );
3051 key_str = MSI_RecordGetString( row, 3 );
3053 root_key_str = get_root_key( package, root, &hkey_root );
3055 return ERROR_SUCCESS;
3057 deformat_string( package, key_str, &deformated_key );
3058 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3059 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3060 strcpyW( ui_key_str, root_key_str );
3061 strcatW( ui_key_str, deformated_key );
3063 deformat_string( package, name, &deformated_name );
3065 keypath = get_keypath( comp, hkey_root, deformated_key );
3066 msi_free( deformated_key );
3067 if (delete_key) delete_tree( hkey_root, keypath );
3068 else delete_value( hkey_root, keypath, deformated_name );
3069 msi_free( keypath );
3071 uirow = MSI_CreateRecord( 2 );
3072 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3073 MSI_RecordSetStringW( uirow, 2, deformated_name );
3074 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3075 msiobj_release( &uirow->hdr );
3077 msi_free( ui_key_str );
3078 msi_free( deformated_name );
3079 return ERROR_SUCCESS;
3082 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
3084 MSIPACKAGE *package = param;
3085 LPCWSTR component, name, key_str, root_key_str;
3086 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3089 BOOL delete_key = FALSE;
3094 component = MSI_RecordGetString( row, 5 );
3095 comp = msi_get_loaded_component( package, component );
3097 return ERROR_SUCCESS;
3099 comp->Action = msi_get_component_action( package, comp );
3100 if (comp->Action != INSTALLSTATE_LOCAL)
3102 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3103 return ERROR_SUCCESS;
3106 if ((name = MSI_RecordGetString( row, 4 )))
3108 if (name[0] == '-' && !name[1])
3115 root = MSI_RecordGetInteger( row, 2 );
3116 key_str = MSI_RecordGetString( row, 3 );
3118 root_key_str = get_root_key( package, root, &hkey_root );
3120 return ERROR_SUCCESS;
3122 deformat_string( package, key_str, &deformated_key );
3123 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3124 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3125 strcpyW( ui_key_str, root_key_str );
3126 strcatW( ui_key_str, deformated_key );
3128 deformat_string( package, name, &deformated_name );
3130 keypath = get_keypath( comp, hkey_root, deformated_key );
3131 msi_free( deformated_key );
3132 if (delete_key) delete_tree( hkey_root, keypath );
3133 else delete_value( hkey_root, keypath, deformated_name );
3134 msi_free( keypath );
3136 uirow = MSI_CreateRecord( 2 );
3137 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3138 MSI_RecordSetStringW( uirow, 2, deformated_name );
3139 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3140 msiobj_release( &uirow->hdr );
3142 msi_free( ui_key_str );
3143 msi_free( deformated_name );
3144 return ERROR_SUCCESS;
3147 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3149 static const WCHAR registry_query[] = {
3150 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3151 '`','R','e','g','i','s','t','r','y','`',0};
3152 static const WCHAR remove_registry_query[] = {
3153 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3154 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
3158 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3159 if (rc == ERROR_SUCCESS)
3161 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3162 msiobj_release( &view->hdr );
3163 if (rc != ERROR_SUCCESS)
3166 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3167 if (rc == ERROR_SUCCESS)
3169 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3170 msiobj_release( &view->hdr );
3171 if (rc != ERROR_SUCCESS)
3174 return ERROR_SUCCESS;
3177 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3179 package->script->CurrentlyScripting = TRUE;
3181 return ERROR_SUCCESS;
3185 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3187 static const WCHAR query[]= {
3188 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3189 '`','R','e','g','i','s','t','r','y','`',0};
3191 DWORD total = 0, count = 0;
3193 MSIFEATURE *feature;
3197 TRACE("InstallValidate\n");
3199 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3200 if (rc == ERROR_SUCCESS)
3202 rc = MSI_IterateRecords( view, &count, NULL, package );
3203 msiobj_release( &view->hdr );
3204 if (rc != ERROR_SUCCESS)
3206 total += count * REG_PROGRESS_VALUE;
3208 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3209 total += COMPONENT_PROGRESS_VALUE;
3211 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3212 total += file->FileSize;
3214 msi_ui_progress( package, 0, total, 0, 0 );
3216 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3218 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3219 debugstr_w(feature->Feature), feature->Installed,
3220 feature->ActionRequest, feature->Action);
3222 return ERROR_SUCCESS;
3225 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3227 MSIPACKAGE* package = param;
3228 LPCWSTR cond = NULL;
3229 LPCWSTR message = NULL;
3232 static const WCHAR title[]=
3233 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3235 cond = MSI_RecordGetString(row,1);
3237 r = MSI_EvaluateConditionW(package,cond);
3238 if (r == MSICONDITION_FALSE)
3240 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3243 message = MSI_RecordGetString(row,2);
3244 deformat_string(package,message,&deformated);
3245 MessageBoxW(NULL,deformated,title,MB_OK);
3246 msi_free(deformated);
3249 return ERROR_INSTALL_FAILURE;
3252 return ERROR_SUCCESS;
3255 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3257 static const WCHAR query[] = {
3258 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3259 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3263 TRACE("Checking launch conditions\n");
3265 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3266 if (rc != ERROR_SUCCESS)
3267 return ERROR_SUCCESS;
3269 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3270 msiobj_release(&view->hdr);
3274 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3278 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3280 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3282 static const WCHAR query[] = {
3283 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3284 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3285 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3286 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3287 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3290 LPWSTR deformated, buffer, deformated_name;
3293 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3297 root = MSI_RecordGetInteger(row,2);
3298 key = MSI_RecordGetString(row, 3);
3299 name = MSI_RecordGetString(row, 4);
3300 deformat_string(package, key , &deformated);
3301 deformat_string(package, name, &deformated_name);
3303 len = strlenW(deformated) + 6;
3304 if (deformated_name)
3305 len+=strlenW(deformated_name);
3307 buffer = msi_alloc( len *sizeof(WCHAR));
3309 if (deformated_name)
3310 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3312 sprintfW(buffer,fmt,root,deformated);
3314 msi_free(deformated);
3315 msi_free(deformated_name);
3316 msiobj_release(&row->hdr);
3320 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3322 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3327 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3330 return strdupW( file->TargetPath );
3335 static HKEY openSharedDLLsKey(void)
3338 static const WCHAR path[] =
3339 {'S','o','f','t','w','a','r','e','\\',
3340 'M','i','c','r','o','s','o','f','t','\\',
3341 'W','i','n','d','o','w','s','\\',
3342 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3343 'S','h','a','r','e','d','D','L','L','s',0};
3345 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3349 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3354 DWORD sz = sizeof(count);
3357 hkey = openSharedDLLsKey();
3358 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3359 if (rc != ERROR_SUCCESS)
3365 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3369 hkey = openSharedDLLsKey();
3371 msi_reg_set_val_dword( hkey, path, count );
3373 RegDeleteValueW(hkey,path);
3378 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3380 MSIFEATURE *feature;
3384 /* only refcount DLLs */
3385 if (comp->KeyPath == NULL ||
3387 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3388 comp->Attributes & msidbComponentAttributesODBCDataSource)
3392 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3393 write = (count > 0);
3395 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3399 /* increment counts */
3400 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3404 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3407 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3409 if ( cl->component == comp )
3414 /* decrement counts */
3415 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3419 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3422 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3424 if ( cl->component == comp )
3429 /* ref count all the files in the component */
3434 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3436 if (file->Component == comp)
3437 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3441 /* add a count for permanent */
3442 if (comp->Attributes & msidbComponentAttributesPermanent)
3445 comp->RefCount = count;
3448 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3451 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3455 const WCHAR prefixW[] = {'<','\\',0};
3456 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3457 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3461 strcpyW( keypath, prefixW );
3462 strcatW( keypath, comp->assembly->display_name );
3466 return resolve_keypath( package, comp );
3469 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3471 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3478 squash_guid(package->ProductCode,squished_pc);
3479 msi_set_sourcedir_props(package, FALSE);
3481 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3484 INSTALLSTATE action;
3486 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3487 if (!comp->ComponentId)
3490 squash_guid( comp->ComponentId, squished_cc );
3491 msi_free( comp->FullKeypath );
3492 comp->FullKeypath = build_full_keypath( package, comp );
3494 ACTION_RefCountComponent( package, comp );
3496 if (package->need_rollback) action = comp->Installed;
3497 else action = comp->ActionRequest;
3499 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3500 debugstr_w(comp->Component), debugstr_w(squished_cc),
3501 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3503 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3505 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3506 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3508 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3510 if (rc != ERROR_SUCCESS)
3513 if (comp->Attributes & msidbComponentAttributesPermanent)
3515 static const WCHAR szPermKey[] =
3516 { '0','0','0','0','0','0','0','0','0','0','0','0',
3517 '0','0','0','0','0','0','0','0','0','0','0','0',
3518 '0','0','0','0','0','0','0','0',0 };
3520 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3522 if (action == INSTALLSTATE_LOCAL)
3523 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3529 WCHAR source[MAX_PATH];
3530 WCHAR base[MAX_PATH];
3533 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3534 static const WCHAR query[] = {
3535 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3536 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3537 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3538 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3539 '`','D','i','s','k','I','d','`',0};
3541 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3544 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3545 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3546 ptr2 = strrchrW(source, '\\') + 1;
3547 msiobj_release(&row->hdr);
3549 lstrcpyW(base, package->PackagePath);
3550 ptr = strrchrW(base, '\\');
3553 sourcepath = msi_resolve_file_source(package, file);
3554 ptr = sourcepath + lstrlenW(base);
3555 lstrcpyW(ptr2, ptr);
3556 msi_free(sourcepath);
3558 msi_reg_set_val_str(hkey, squished_pc, source);
3562 else if (action == INSTALLSTATE_ABSENT)
3564 if (comp->num_clients <= 0)
3566 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3567 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid );
3569 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
3574 uirow = MSI_CreateRecord(3);
3575 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3576 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3577 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3578 msi_ui_actiondata( package, szProcessComponents, uirow );
3579 msiobj_release( &uirow->hdr );
3581 return ERROR_SUCCESS;
3592 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3593 LPWSTR lpszName, LONG_PTR lParam)
3596 typelib_struct *tl_struct = (typelib_struct*) lParam;
3597 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3601 if (!IS_INTRESOURCE(lpszName))
3603 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3607 sz = strlenW(tl_struct->source)+4;
3608 sz *= sizeof(WCHAR);
3610 if ((INT_PTR)lpszName == 1)
3611 tl_struct->path = strdupW(tl_struct->source);
3614 tl_struct->path = msi_alloc(sz);
3615 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3618 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3619 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3622 msi_free(tl_struct->path);
3623 tl_struct->path = NULL;
3628 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3629 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3631 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3635 msi_free(tl_struct->path);
3636 tl_struct->path = NULL;
3638 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3639 ITypeLib_Release(tl_struct->ptLib);
3644 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3646 MSIPACKAGE* package = param;
3650 typelib_struct tl_struct;
3655 component = MSI_RecordGetString(row,3);
3656 comp = msi_get_loaded_component(package,component);
3658 return ERROR_SUCCESS;
3660 comp->Action = msi_get_component_action( package, comp );
3661 if (comp->Action != INSTALLSTATE_LOCAL)
3663 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3664 return ERROR_SUCCESS;
3667 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3669 TRACE("component has no key path\n");
3670 return ERROR_SUCCESS;
3672 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3674 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3678 guid = MSI_RecordGetString(row,1);
3679 CLSIDFromString( guid, &tl_struct.clsid);
3680 tl_struct.source = strdupW( file->TargetPath );
3681 tl_struct.path = NULL;
3683 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3684 (LONG_PTR)&tl_struct);
3688 LPCWSTR helpid, help_path = NULL;
3691 helpid = MSI_RecordGetString(row,6);
3693 if (helpid) help_path = msi_get_target_folder( package, helpid );
3694 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3697 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3699 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3701 ITypeLib_Release(tl_struct.ptLib);
3702 msi_free(tl_struct.path);
3704 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3706 FreeLibrary(module);
3707 msi_free(tl_struct.source);
3711 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3714 ERR("Failed to load type library: %08x\n", hr);
3715 return ERROR_INSTALL_FAILURE;
3718 ITypeLib_Release(tlib);
3721 return ERROR_SUCCESS;
3724 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3726 static const WCHAR query[] = {
3727 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3728 '`','T','y','p','e','L','i','b','`',0};
3732 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3733 if (rc != ERROR_SUCCESS)
3734 return ERROR_SUCCESS;
3736 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3737 msiobj_release(&view->hdr);
3741 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3743 MSIPACKAGE *package = param;
3744 LPCWSTR component, guid;
3752 component = MSI_RecordGetString( row, 3 );
3753 comp = msi_get_loaded_component( package, component );
3755 return ERROR_SUCCESS;
3757 comp->Action = msi_get_component_action( package, comp );
3758 if (comp->Action != INSTALLSTATE_ABSENT)
3760 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3761 return ERROR_SUCCESS;
3763 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3765 guid = MSI_RecordGetString( row, 1 );
3766 CLSIDFromString( guid, &libid );
3767 version = MSI_RecordGetInteger( row, 4 );
3768 language = MSI_RecordGetInteger( row, 2 );
3771 syskind = SYS_WIN64;
3773 syskind = SYS_WIN32;
3776 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3779 WARN("Failed to unregister typelib: %08x\n", hr);
3782 return ERROR_SUCCESS;
3785 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3787 static const WCHAR query[] = {
3788 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3789 '`','T','y','p','e','L','i','b','`',0};
3793 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3794 if (rc != ERROR_SUCCESS)
3795 return ERROR_SUCCESS;
3797 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3798 msiobj_release( &view->hdr );
3802 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3804 static const WCHAR szlnk[] = {'.','l','n','k',0};
3805 LPCWSTR directory, extension, link_folder;
3806 LPWSTR link_file, filename;
3808 directory = MSI_RecordGetString( row, 2 );
3809 link_folder = msi_get_target_folder( package, directory );
3812 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3815 /* may be needed because of a bug somewhere else */
3816 msi_create_full_path( link_folder );
3818 filename = msi_dup_record_field( row, 3 );
3819 msi_reduce_to_long_filename( filename );
3821 extension = strchrW( filename, '.' );
3822 if (!extension || strcmpiW( extension, szlnk ))
3824 int len = strlenW( filename );
3825 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3826 memcpy( filename + len, szlnk, sizeof(szlnk) );
3828 link_file = msi_build_directory_name( 2, link_folder, filename );
3829 msi_free( filename );
3834 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3836 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3837 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3838 WCHAR *folder, *dest, *path;
3840 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3841 folder = msi_dup_property( package->db, szWindowsFolder );
3844 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3845 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3846 msi_free( appdata );
3848 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3849 msi_create_full_path( dest );
3850 path = msi_build_directory_name( 2, dest, icon_name );
3856 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3858 MSIPACKAGE *package = param;
3859 LPWSTR link_file, deformated, path;
3860 LPCWSTR component, target;
3862 IShellLinkW *sl = NULL;
3863 IPersistFile *pf = NULL;
3866 component = MSI_RecordGetString(row, 4);
3867 comp = msi_get_loaded_component(package, component);
3869 return ERROR_SUCCESS;
3871 comp->Action = msi_get_component_action( package, comp );
3872 if (comp->Action != INSTALLSTATE_LOCAL)
3874 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3875 return ERROR_SUCCESS;
3877 msi_ui_actiondata( package, szCreateShortcuts, row );
3879 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3880 &IID_IShellLinkW, (LPVOID *) &sl );
3884 ERR("CLSID_ShellLink not available\n");
3888 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3891 ERR("QueryInterface(IID_IPersistFile) failed\n");
3895 target = MSI_RecordGetString(row, 5);
3896 if (strchrW(target, '['))
3898 deformat_string( package, target, &path );
3899 TRACE("target path is %s\n", debugstr_w(path));
3900 IShellLinkW_SetPath( sl, path );
3905 FIXME("poorly handled shortcut format, advertised shortcut\n");
3906 IShellLinkW_SetPath(sl,comp->FullKeypath);
3909 if (!MSI_RecordIsNull(row,6))
3911 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3912 deformat_string(package, arguments, &deformated);
3913 IShellLinkW_SetArguments(sl,deformated);
3914 msi_free(deformated);
3917 if (!MSI_RecordIsNull(row,7))
3919 LPCWSTR description = MSI_RecordGetString(row, 7);
3920 IShellLinkW_SetDescription(sl, description);
3923 if (!MSI_RecordIsNull(row,8))
3924 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3926 if (!MSI_RecordIsNull(row,9))
3929 LPCWSTR icon = MSI_RecordGetString(row, 9);
3931 path = msi_build_icon_path(package, icon);
3932 index = MSI_RecordGetInteger(row,10);
3934 /* no value means 0 */
3935 if (index == MSI_NULL_INTEGER)
3938 IShellLinkW_SetIconLocation(sl, path, index);
3942 if (!MSI_RecordIsNull(row,11))
3943 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3945 if (!MSI_RecordIsNull(row,12))
3947 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3948 full_path = msi_get_target_folder( package, wkdir );
3949 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3951 link_file = get_link_file(package, row);
3953 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3954 IPersistFile_Save(pf, link_file, FALSE);
3955 msi_free(link_file);
3959 IPersistFile_Release( pf );
3961 IShellLinkW_Release( sl );
3963 return ERROR_SUCCESS;
3966 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3968 static const WCHAR query[] = {
3969 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3970 '`','S','h','o','r','t','c','u','t','`',0};
3975 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3976 if (rc != ERROR_SUCCESS)
3977 return ERROR_SUCCESS;
3979 res = CoInitialize( NULL );
3981 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3982 msiobj_release(&view->hdr);
3984 if (SUCCEEDED(res)) CoUninitialize();
3988 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3990 MSIPACKAGE *package = param;
3995 component = MSI_RecordGetString( row, 4 );
3996 comp = msi_get_loaded_component( package, component );
3998 return ERROR_SUCCESS;
4000 comp->Action = msi_get_component_action( package, comp );
4001 if (comp->Action != INSTALLSTATE_ABSENT)
4003 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4004 return ERROR_SUCCESS;
4006 msi_ui_actiondata( package, szRemoveShortcuts, row );
4008 link_file = get_link_file( package, row );
4010 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
4011 if (!DeleteFileW( link_file ))
4013 WARN("Failed to remove shortcut file %u\n", GetLastError());
4015 msi_free( link_file );
4017 return ERROR_SUCCESS;
4020 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4022 static const WCHAR query[] = {
4023 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4024 '`','S','h','o','r','t','c','u','t','`',0};
4028 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4029 if (rc != ERROR_SUCCESS)
4030 return ERROR_SUCCESS;
4032 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
4033 msiobj_release( &view->hdr );
4037 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
4039 MSIPACKAGE* package = param;
4047 FileName = MSI_RecordGetString(row,1);
4050 ERR("Unable to get FileName\n");
4051 return ERROR_SUCCESS;
4054 FilePath = msi_build_icon_path(package, FileName);
4056 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4058 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4059 FILE_ATTRIBUTE_NORMAL, NULL);
4061 if (the_file == INVALID_HANDLE_VALUE)
4063 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4065 return ERROR_SUCCESS;
4072 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4073 if (rc != ERROR_SUCCESS)
4075 ERR("Failed to get stream\n");
4076 CloseHandle(the_file);
4077 DeleteFileW(FilePath);
4080 WriteFile(the_file,buffer,sz,&write,NULL);
4081 } while (sz == 1024);
4084 CloseHandle(the_file);
4086 return ERROR_SUCCESS;
4089 static UINT msi_publish_icons(MSIPACKAGE *package)
4091 static const WCHAR query[]= {
4092 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4093 '`','I','c','o','n','`',0};
4097 r = MSI_DatabaseOpenViewW(package->db, query, &view);
4098 if (r == ERROR_SUCCESS)
4100 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
4101 msiobj_release(&view->hdr);
4102 if (r != ERROR_SUCCESS)
4105 return ERROR_SUCCESS;
4108 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
4114 MSISOURCELISTINFO *info;
4116 r = RegCreateKeyW(hkey, szSourceList, &source);
4117 if (r != ERROR_SUCCESS)
4120 RegCloseKey(source);
4122 buffer = strrchrW(package->PackagePath, '\\') + 1;
4123 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4124 package->Context, MSICODE_PRODUCT,
4125 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4126 if (r != ERROR_SUCCESS)
4129 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4130 package->Context, MSICODE_PRODUCT,
4131 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4132 if (r != ERROR_SUCCESS)
4135 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4136 package->Context, MSICODE_PRODUCT,
4137 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4138 if (r != ERROR_SUCCESS)
4141 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4143 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4144 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4145 info->options, info->value);
4147 MsiSourceListSetInfoW(package->ProductCode, NULL,
4148 info->context, info->options,
4149 info->property, info->value);
4152 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4154 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4155 disk->context, disk->options,
4156 disk->disk_id, disk->volume_label, disk->disk_prompt);
4159 return ERROR_SUCCESS;
4162 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4164 MSIHANDLE hdb, suminfo;
4165 WCHAR guids[MAX_PATH];
4166 WCHAR packcode[SQUISH_GUID_SIZE];
4173 static const WCHAR szARPProductIcon[] =
4174 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4175 static const WCHAR szAssignment[] =
4176 {'A','s','s','i','g','n','m','e','n','t',0};
4177 static const WCHAR szAdvertiseFlags[] =
4178 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4179 static const WCHAR szClients[] =
4180 {'C','l','i','e','n','t','s',0};
4181 static const WCHAR szColon[] = {':',0};
4183 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4184 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4187 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4188 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4191 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4193 buffer = msi_dup_property(package->db, szARPProductIcon);
4196 LPWSTR path = msi_build_icon_path(package, buffer);
4197 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4202 buffer = msi_dup_property(package->db, szProductVersion);
4205 DWORD verdword = msi_version_str_to_dword(buffer);
4206 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4210 msi_reg_set_val_dword(hkey, szAssignment, 0);
4211 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4212 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4213 msi_reg_set_val_str(hkey, szClients, szColon);
4215 hdb = alloc_msihandle(&package->db->hdr);
4217 return ERROR_NOT_ENOUGH_MEMORY;
4219 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4220 MsiCloseHandle(hdb);
4221 if (r != ERROR_SUCCESS)
4225 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4226 NULL, guids, &size);
4227 if (r != ERROR_SUCCESS)
4230 ptr = strchrW(guids, ';');
4232 squash_guid(guids, packcode);
4233 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4236 MsiCloseHandle(suminfo);
4237 return ERROR_SUCCESS;
4240 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4245 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4247 upgrade = msi_dup_property(package->db, szUpgradeCode);
4249 return ERROR_SUCCESS;
4251 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4252 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4254 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4256 if (r != ERROR_SUCCESS)
4258 WARN("failed to open upgrade code key\n");
4260 return ERROR_SUCCESS;
4262 squash_guid(package->ProductCode, squashed_pc);
4263 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4266 return ERROR_SUCCESS;
4269 static BOOL msi_check_publish(MSIPACKAGE *package)
4271 MSIFEATURE *feature;
4273 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4275 feature->Action = msi_get_feature_action( package, feature );
4276 if (feature->Action == INSTALLSTATE_LOCAL)
4283 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4285 MSIFEATURE *feature;
4287 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4289 feature->Action = msi_get_feature_action( package, feature );
4290 if (feature->Action != INSTALLSTATE_ABSENT)
4297 static UINT msi_publish_patches( MSIPACKAGE *package )
4299 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4300 WCHAR patch_squashed[GUID_SIZE];
4301 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4303 MSIPATCHINFO *patch;
4305 WCHAR *p, *all_patches = NULL;
4308 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4309 if (r != ERROR_SUCCESS)
4310 return ERROR_FUNCTION_FAILED;
4312 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4313 if (res != ERROR_SUCCESS)
4315 r = ERROR_FUNCTION_FAILED;
4319 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4320 if (r != ERROR_SUCCESS)
4323 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4325 squash_guid( patch->patchcode, patch_squashed );
4326 len += strlenW( patch_squashed ) + 1;
4329 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4333 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4337 squash_guid( patch->patchcode, p );
4338 p += strlenW( p ) + 1;
4340 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4341 (const BYTE *)patch->transforms,
4342 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4343 if (res != ERROR_SUCCESS)
4346 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4347 if (r != ERROR_SUCCESS)
4350 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4351 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4352 RegCloseKey( patch_key );
4353 if (res != ERROR_SUCCESS)
4356 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4358 res = GetLastError();
4359 ERR("Unable to copy patch package %d\n", res);
4362 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4363 if (res != ERROR_SUCCESS)
4366 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4367 RegCloseKey( patch_key );
4368 if (res != ERROR_SUCCESS)
4372 all_patches[len] = 0;
4373 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4374 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4375 if (res != ERROR_SUCCESS)
4378 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4379 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4380 if (res != ERROR_SUCCESS)
4381 r = ERROR_FUNCTION_FAILED;
4384 RegCloseKey( product_patches_key );
4385 RegCloseKey( patches_key );
4386 RegCloseKey( product_key );
4387 msi_free( all_patches );
4391 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4394 HKEY hukey = NULL, hudkey = NULL;
4397 if (!list_empty(&package->patches))
4399 rc = msi_publish_patches(package);
4400 if (rc != ERROR_SUCCESS)
4404 /* FIXME: also need to publish if the product is in advertise mode */
4405 if (!msi_check_publish(package))
4406 return ERROR_SUCCESS;
4408 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4410 if (rc != ERROR_SUCCESS)
4413 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4414 NULL, &hudkey, TRUE);
4415 if (rc != ERROR_SUCCESS)
4418 rc = msi_publish_upgrade_code(package);
4419 if (rc != ERROR_SUCCESS)
4422 rc = msi_publish_product_properties(package, hukey);
4423 if (rc != ERROR_SUCCESS)
4426 rc = msi_publish_sourcelist(package, hukey);
4427 if (rc != ERROR_SUCCESS)
4430 rc = msi_publish_icons(package);
4433 uirow = MSI_CreateRecord( 1 );
4434 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4435 msi_ui_actiondata( package, szPublishProduct, uirow );
4436 msiobj_release( &uirow->hdr );
4439 RegCloseKey(hudkey);
4443 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4445 WCHAR *filename, *ptr, *folder, *ret;
4446 const WCHAR *dirprop;
4448 filename = msi_dup_record_field( row, 2 );
4449 if (filename && (ptr = strchrW( filename, '|' )))
4454 dirprop = MSI_RecordGetString( row, 3 );
4457 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4458 if (!folder) folder = msi_dup_property( package->db, dirprop );
4461 folder = msi_dup_property( package->db, szWindowsFolder );
4465 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4466 msi_free( filename );
4470 ret = msi_build_directory_name( 2, folder, ptr );
4472 msi_free( filename );
4477 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4479 MSIPACKAGE *package = param;
4480 LPCWSTR component, section, key, value, identifier;
4481 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4486 component = MSI_RecordGetString(row, 8);
4487 comp = msi_get_loaded_component(package,component);
4489 return ERROR_SUCCESS;
4491 comp->Action = msi_get_component_action( package, comp );
4492 if (comp->Action != INSTALLSTATE_LOCAL)
4494 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4495 return ERROR_SUCCESS;
4498 identifier = MSI_RecordGetString(row,1);
4499 section = MSI_RecordGetString(row,4);
4500 key = MSI_RecordGetString(row,5);
4501 value = MSI_RecordGetString(row,6);
4502 action = MSI_RecordGetInteger(row,7);
4504 deformat_string(package,section,&deformated_section);
4505 deformat_string(package,key,&deformated_key);
4506 deformat_string(package,value,&deformated_value);
4508 fullname = get_ini_file_name(package, row);
4512 TRACE("Adding value %s to section %s in %s\n",
4513 debugstr_w(deformated_key), debugstr_w(deformated_section),
4514 debugstr_w(fullname));
4515 WritePrivateProfileStringW(deformated_section, deformated_key,
4516 deformated_value, fullname);
4518 else if (action == 1)
4521 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4522 returned, 10, fullname);
4523 if (returned[0] == 0)
4525 TRACE("Adding value %s to section %s in %s\n",
4526 debugstr_w(deformated_key), debugstr_w(deformated_section),
4527 debugstr_w(fullname));
4529 WritePrivateProfileStringW(deformated_section, deformated_key,
4530 deformated_value, fullname);
4533 else if (action == 3)
4534 FIXME("Append to existing section not yet implemented\n");
4536 uirow = MSI_CreateRecord(4);
4537 MSI_RecordSetStringW(uirow,1,identifier);
4538 MSI_RecordSetStringW(uirow,2,deformated_section);
4539 MSI_RecordSetStringW(uirow,3,deformated_key);
4540 MSI_RecordSetStringW(uirow,4,deformated_value);
4541 msi_ui_actiondata( package, szWriteIniValues, uirow );
4542 msiobj_release( &uirow->hdr );
4545 msi_free(deformated_key);
4546 msi_free(deformated_value);
4547 msi_free(deformated_section);
4548 return ERROR_SUCCESS;
4551 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4553 static const WCHAR query[] = {
4554 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4555 '`','I','n','i','F','i','l','e','`',0};
4559 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4560 if (rc != ERROR_SUCCESS)
4561 return ERROR_SUCCESS;
4563 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4564 msiobj_release(&view->hdr);
4568 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4570 MSIPACKAGE *package = param;
4571 LPCWSTR component, section, key, value, identifier;
4572 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4577 component = MSI_RecordGetString( row, 8 );
4578 comp = msi_get_loaded_component( package, component );
4580 return ERROR_SUCCESS;
4582 comp->Action = msi_get_component_action( package, comp );
4583 if (comp->Action != INSTALLSTATE_ABSENT)
4585 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4586 return ERROR_SUCCESS;
4589 identifier = MSI_RecordGetString( row, 1 );
4590 section = MSI_RecordGetString( row, 4 );
4591 key = MSI_RecordGetString( row, 5 );
4592 value = MSI_RecordGetString( row, 6 );
4593 action = MSI_RecordGetInteger( row, 7 );
4595 deformat_string( package, section, &deformated_section );
4596 deformat_string( package, key, &deformated_key );
4597 deformat_string( package, value, &deformated_value );
4599 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4601 filename = get_ini_file_name( package, row );
4603 TRACE("Removing key %s from section %s in %s\n",
4604 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4606 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4608 WARN("Unable to remove key %u\n", GetLastError());
4610 msi_free( filename );
4613 FIXME("Unsupported action %d\n", action);
4616 uirow = MSI_CreateRecord( 4 );
4617 MSI_RecordSetStringW( uirow, 1, identifier );
4618 MSI_RecordSetStringW( uirow, 2, deformated_section );
4619 MSI_RecordSetStringW( uirow, 3, deformated_key );
4620 MSI_RecordSetStringW( uirow, 4, deformated_value );
4621 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4622 msiobj_release( &uirow->hdr );
4624 msi_free( deformated_key );
4625 msi_free( deformated_value );
4626 msi_free( deformated_section );
4627 return ERROR_SUCCESS;
4630 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4632 MSIPACKAGE *package = param;
4633 LPCWSTR component, section, key, value, identifier;
4634 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4639 component = MSI_RecordGetString( row, 8 );
4640 comp = msi_get_loaded_component( package, component );
4642 return ERROR_SUCCESS;
4644 comp->Action = msi_get_component_action( package, comp );
4645 if (comp->Action != INSTALLSTATE_LOCAL)
4647 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4648 return ERROR_SUCCESS;
4651 identifier = MSI_RecordGetString( row, 1 );
4652 section = MSI_RecordGetString( row, 4 );
4653 key = MSI_RecordGetString( row, 5 );
4654 value = MSI_RecordGetString( row, 6 );
4655 action = MSI_RecordGetInteger( row, 7 );
4657 deformat_string( package, section, &deformated_section );
4658 deformat_string( package, key, &deformated_key );
4659 deformat_string( package, value, &deformated_value );
4661 if (action == msidbIniFileActionRemoveLine)
4663 filename = get_ini_file_name( package, row );
4665 TRACE("Removing key %s from section %s in %s\n",
4666 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4668 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4670 WARN("Unable to remove key %u\n", GetLastError());
4672 msi_free( filename );
4675 FIXME("Unsupported action %d\n", action);
4677 uirow = MSI_CreateRecord( 4 );
4678 MSI_RecordSetStringW( uirow, 1, identifier );
4679 MSI_RecordSetStringW( uirow, 2, deformated_section );
4680 MSI_RecordSetStringW( uirow, 3, deformated_key );
4681 MSI_RecordSetStringW( uirow, 4, deformated_value );
4682 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4683 msiobj_release( &uirow->hdr );
4685 msi_free( deformated_key );
4686 msi_free( deformated_value );
4687 msi_free( deformated_section );
4688 return ERROR_SUCCESS;
4691 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4693 static const WCHAR query[] = {
4694 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4695 '`','I','n','i','F','i','l','e','`',0};
4696 static const WCHAR remove_query[] = {
4697 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4698 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4702 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4703 if (rc == ERROR_SUCCESS)
4705 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4706 msiobj_release( &view->hdr );
4707 if (rc != ERROR_SUCCESS)
4710 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4711 if (rc == ERROR_SUCCESS)
4713 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4714 msiobj_release( &view->hdr );
4715 if (rc != ERROR_SUCCESS)
4718 return ERROR_SUCCESS;
4721 static void register_dll( const WCHAR *dll, BOOL unregister )
4723 static const WCHAR regW[] =
4724 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"','%','s','\"',0};
4725 static const WCHAR unregW[] =
4726 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"','%','s','\"',0};
4727 PROCESS_INFORMATION pi;
4731 if (!(cmd = msi_alloc( strlenW(dll) * sizeof(WCHAR) + sizeof(unregW) ))) return;
4733 if (unregister) sprintfW( cmd, unregW, dll );
4734 else sprintfW( cmd, regW, dll );
4736 memset( &si, 0, sizeof(STARTUPINFOW) );
4737 if (CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
4739 CloseHandle( pi.hThread );
4740 msi_dialog_check_messages( pi.hProcess );
4741 CloseHandle( pi.hProcess );
4746 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4748 MSIPACKAGE *package = param;
4753 filename = MSI_RecordGetString( row, 1 );
4754 file = msi_get_loaded_file( package, filename );
4757 WARN("unable to find file %s\n", debugstr_w(filename));
4758 return ERROR_SUCCESS;
4760 file->Component->Action = msi_get_component_action( package, file->Component );
4761 if (file->Component->Action != INSTALLSTATE_LOCAL)
4763 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4764 return ERROR_SUCCESS;
4767 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4768 register_dll( file->TargetPath, FALSE );
4770 uirow = MSI_CreateRecord( 2 );
4771 MSI_RecordSetStringW( uirow, 1, file->File );
4772 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4773 msi_ui_actiondata( package, szSelfRegModules, uirow );
4774 msiobj_release( &uirow->hdr );
4776 return ERROR_SUCCESS;
4779 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4781 static const WCHAR query[] = {
4782 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4783 '`','S','e','l','f','R','e','g','`',0};
4787 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4788 if (rc != ERROR_SUCCESS)
4789 return ERROR_SUCCESS;
4791 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4792 msiobj_release(&view->hdr);
4796 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4798 MSIPACKAGE *package = param;
4803 filename = MSI_RecordGetString( row, 1 );
4804 file = msi_get_loaded_file( package, filename );
4807 WARN("unable to find file %s\n", debugstr_w(filename));
4808 return ERROR_SUCCESS;
4810 file->Component->Action = msi_get_component_action( package, file->Component );
4811 if (file->Component->Action != INSTALLSTATE_ABSENT)
4813 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4814 return ERROR_SUCCESS;
4817 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4818 register_dll( file->TargetPath, TRUE );
4820 uirow = MSI_CreateRecord( 2 );
4821 MSI_RecordSetStringW( uirow, 1, file->File );
4822 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4823 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4824 msiobj_release( &uirow->hdr );
4826 return ERROR_SUCCESS;
4829 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4831 static const WCHAR query[] = {
4832 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4833 '`','S','e','l','f','R','e','g','`',0};
4837 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4838 if (rc != ERROR_SUCCESS)
4839 return ERROR_SUCCESS;
4841 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4842 msiobj_release( &view->hdr );
4846 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4848 MSIFEATURE *feature;
4850 HKEY hkey = NULL, userdata = NULL;
4852 if (!msi_check_publish(package))
4853 return ERROR_SUCCESS;
4855 rc = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4857 if (rc != ERROR_SUCCESS)
4860 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4862 if (rc != ERROR_SUCCESS)
4865 /* here the guids are base 85 encoded */
4866 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4872 BOOL absent = FALSE;
4875 if (feature->Action != INSTALLSTATE_LOCAL &&
4876 feature->Action != INSTALLSTATE_SOURCE &&
4877 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4880 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4884 if (feature->Feature_Parent)
4885 size += strlenW( feature->Feature_Parent )+2;
4887 data = msi_alloc(size * sizeof(WCHAR));
4890 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4892 MSICOMPONENT* component = cl->component;
4896 if (component->ComponentId)
4898 TRACE("From %s\n",debugstr_w(component->ComponentId));
4899 CLSIDFromString(component->ComponentId, &clsid);
4900 encode_base85_guid(&clsid,buf);
4901 TRACE("to %s\n",debugstr_w(buf));
4906 if (feature->Feature_Parent)
4908 static const WCHAR sep[] = {'\2',0};
4910 strcatW(data,feature->Feature_Parent);
4913 msi_reg_set_val_str( userdata, feature->Feature, data );
4917 if (feature->Feature_Parent)
4918 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4921 size += sizeof(WCHAR);
4922 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4923 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4927 size += 2*sizeof(WCHAR);
4928 data = msi_alloc(size);
4931 if (feature->Feature_Parent)
4932 strcpyW( &data[1], feature->Feature_Parent );
4933 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4939 uirow = MSI_CreateRecord( 1 );
4940 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4941 msi_ui_actiondata( package, szPublishFeatures, uirow );
4942 msiobj_release( &uirow->hdr );
4943 /* FIXME: call msi_ui_progress? */
4948 RegCloseKey(userdata);
4952 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4958 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4960 r = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4962 if (r == ERROR_SUCCESS)
4964 RegDeleteValueW(hkey, feature->Feature);
4968 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4970 if (r == ERROR_SUCCESS)
4972 RegDeleteValueW(hkey, feature->Feature);
4976 uirow = MSI_CreateRecord( 1 );
4977 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4978 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4979 msiobj_release( &uirow->hdr );
4981 return ERROR_SUCCESS;
4984 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4986 MSIFEATURE *feature;
4988 if (!msi_check_unpublish(package))
4989 return ERROR_SUCCESS;
4991 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4993 msi_unpublish_feature(package, feature);
4996 return ERROR_SUCCESS;
4999 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
5003 WCHAR date[9], *val, *buffer;
5004 const WCHAR *prop, *key;
5006 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
5007 static const WCHAR modpath_fmt[] =
5008 {'M','s','i','E','x','e','c','.','e','x','e',' ',
5009 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
5010 static const WCHAR szModifyPath[] =
5011 {'M','o','d','i','f','y','P','a','t','h',0};
5012 static const WCHAR szUninstallString[] =
5013 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5014 static const WCHAR szEstimatedSize[] =
5015 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5016 static const WCHAR szDisplayVersion[] =
5017 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5018 static const WCHAR szInstallSource[] =
5019 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5020 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
5021 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5022 static const WCHAR szAuthorizedCDFPrefix[] =
5023 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5024 static const WCHAR szARPCONTACT[] =
5025 {'A','R','P','C','O','N','T','A','C','T',0};
5026 static const WCHAR szContact[] =
5027 {'C','o','n','t','a','c','t',0};
5028 static const WCHAR szARPCOMMENTS[] =
5029 {'A','R','P','C','O','M','M','E','N','T','S',0};
5030 static const WCHAR szComments[] =
5031 {'C','o','m','m','e','n','t','s',0};
5032 static const WCHAR szProductName[] =
5033 {'P','r','o','d','u','c','t','N','a','m','e',0};
5034 static const WCHAR szDisplayName[] =
5035 {'D','i','s','p','l','a','y','N','a','m','e',0};
5036 static const WCHAR szARPHELPLINK[] =
5037 {'A','R','P','H','E','L','P','L','I','N','K',0};
5038 static const WCHAR szHelpLink[] =
5039 {'H','e','l','p','L','i','n','k',0};
5040 static const WCHAR szARPHELPTELEPHONE[] =
5041 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5042 static const WCHAR szHelpTelephone[] =
5043 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5044 static const WCHAR szARPINSTALLLOCATION[] =
5045 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5046 static const WCHAR szManufacturer[] =
5047 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5048 static const WCHAR szPublisher[] =
5049 {'P','u','b','l','i','s','h','e','r',0};
5050 static const WCHAR szARPREADME[] =
5051 {'A','R','P','R','E','A','D','M','E',0};
5052 static const WCHAR szReadme[] =
5053 {'R','e','a','d','M','e',0};
5054 static const WCHAR szARPSIZE[] =
5055 {'A','R','P','S','I','Z','E',0};
5056 static const WCHAR szSize[] =
5057 {'S','i','z','e',0};
5058 static const WCHAR szARPURLINFOABOUT[] =
5059 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5060 static const WCHAR szURLInfoAbout[] =
5061 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5062 static const WCHAR szARPURLUPDATEINFO[] =
5063 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5064 static const WCHAR szURLUpdateInfo[] =
5065 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5066 static const WCHAR szARPSYSTEMCOMPONENT[] =
5067 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
5068 static const WCHAR szSystemComponent[] =
5069 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
5071 static const WCHAR *propval[] = {
5072 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
5073 szARPCONTACT, szContact,
5074 szARPCOMMENTS, szComments,
5075 szProductName, szDisplayName,
5076 szARPHELPLINK, szHelpLink,
5077 szARPHELPTELEPHONE, szHelpTelephone,
5078 szARPINSTALLLOCATION, szInstallLocation,
5079 szSourceDir, szInstallSource,
5080 szManufacturer, szPublisher,
5081 szARPREADME, szReadme,
5083 szARPURLINFOABOUT, szURLInfoAbout,
5084 szARPURLUPDATEINFO, szURLUpdateInfo,
5087 const WCHAR **p = propval;
5093 val = msi_dup_property(package->db, prop);
5094 msi_reg_set_val_str(hkey, key, val);
5098 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5099 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
5101 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
5103 size = deformat_string(package, modpath_fmt, &buffer) * sizeof(WCHAR);
5104 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5105 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5108 /* FIXME: Write real Estimated Size when we have it */
5109 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5111 GetLocalTime(&systime);
5112 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5113 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5115 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5116 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5118 buffer = msi_dup_property(package->db, szProductVersion);
5119 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5122 DWORD verdword = msi_version_str_to_dword(buffer);
5124 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5125 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5126 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5130 return ERROR_SUCCESS;
5133 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5135 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5137 LPWSTR upgrade_code;
5138 HKEY hkey, props, upgrade_key;
5141 /* FIXME: also need to publish if the product is in advertise mode */
5142 if (!msi_check_publish(package))
5143 return ERROR_SUCCESS;
5145 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
5146 if (rc != ERROR_SUCCESS)
5149 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
5150 if (rc != ERROR_SUCCESS)
5153 rc = msi_publish_install_properties(package, hkey);
5154 if (rc != ERROR_SUCCESS)
5157 rc = msi_publish_install_properties(package, props);
5158 if (rc != ERROR_SUCCESS)
5161 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5164 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
5165 if (rc == ERROR_SUCCESS)
5167 squash_guid( package->ProductCode, squashed_pc );
5168 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
5169 RegCloseKey( upgrade_key );
5171 msi_free( upgrade_code );
5173 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
5174 package->delete_on_close = FALSE;
5177 uirow = MSI_CreateRecord( 1 );
5178 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5179 msi_ui_actiondata( package, szRegisterProduct, uirow );
5180 msiobj_release( &uirow->hdr );
5183 return ERROR_SUCCESS;
5186 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5188 return execute_script(package, SCRIPT_INSTALL);
5191 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5193 MSIPACKAGE *package = param;
5194 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5195 WCHAR *p, *icon_path;
5197 if (!icon) return ERROR_SUCCESS;
5198 if ((icon_path = msi_build_icon_path( package, icon )))
5200 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5201 DeleteFileW( icon_path );
5202 if ((p = strrchrW( icon_path, '\\' )))
5205 RemoveDirectoryW( icon_path );
5207 msi_free( icon_path );
5209 return ERROR_SUCCESS;
5212 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5214 static const WCHAR query[]= {
5215 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
5219 r = MSI_DatabaseOpenViewW( package->db, query, &view );
5220 if (r == ERROR_SUCCESS)
5222 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5223 msiobj_release( &view->hdr );
5224 if (r != ERROR_SUCCESS)
5227 return ERROR_SUCCESS;
5230 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
5232 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
5233 WCHAR *upgrade, **features;
5234 BOOL full_uninstall = TRUE;
5235 MSIFEATURE *feature;
5236 MSIPATCHINFO *patch;
5239 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5241 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
5243 features = msi_split_string( remove, ',' );
5244 for (i = 0; features && features[i]; i++)
5246 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
5250 if (!full_uninstall)
5251 return ERROR_SUCCESS;
5253 MSIREG_DeleteProductKey(package->ProductCode);
5254 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5255 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5257 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5258 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5259 MSIREG_DeleteUserProductKey(package->ProductCode);
5260 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5262 upgrade = msi_dup_property(package->db, szUpgradeCode);
5265 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5266 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5270 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5272 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5273 if (!strcmpW( package->ProductCode, patch->products ))
5275 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5276 patch->delete_on_close = TRUE;
5278 /* FIXME: remove local patch package if this is the last product */
5280 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5281 package->delete_on_close = TRUE;
5283 msi_unpublish_icons( package );
5284 return ERROR_SUCCESS;
5287 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5292 /* turn off scheduling */
5293 package->script->CurrentlyScripting= FALSE;
5295 /* first do the same as an InstallExecute */
5296 rc = ACTION_InstallExecute(package);
5297 if (rc != ERROR_SUCCESS)
5300 /* then handle commit actions */
5301 rc = execute_script(package, SCRIPT_COMMIT);
5302 if (rc != ERROR_SUCCESS)
5305 remove = msi_dup_property(package->db, szRemove);
5306 rc = msi_unpublish_product(package, remove);
5311 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5313 static const WCHAR RunOnce[] = {
5314 'S','o','f','t','w','a','r','e','\\',
5315 'M','i','c','r','o','s','o','f','t','\\',
5316 'W','i','n','d','o','w','s','\\',
5317 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5318 'R','u','n','O','n','c','e',0};
5319 static const WCHAR InstallRunOnce[] = {
5320 'S','o','f','t','w','a','r','e','\\',
5321 'M','i','c','r','o','s','o','f','t','\\',
5322 'W','i','n','d','o','w','s','\\',
5323 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5324 'I','n','s','t','a','l','l','e','r','\\',
5325 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5327 static const WCHAR msiexec_fmt[] = {
5329 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5330 '\"','%','s','\"',0};
5331 static const WCHAR install_fmt[] = {
5332 '/','I',' ','\"','%','s','\"',' ',
5333 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5334 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5335 WCHAR buffer[256], sysdir[MAX_PATH];
5337 WCHAR squished_pc[100];
5339 squash_guid(package->ProductCode,squished_pc);
5341 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5342 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5343 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5346 msi_reg_set_val_str( hkey, squished_pc, buffer );
5349 TRACE("Reboot command %s\n",debugstr_w(buffer));
5351 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5352 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5354 msi_reg_set_val_str( hkey, squished_pc, buffer );
5357 return ERROR_INSTALL_SUSPEND;
5360 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5362 static const WCHAR query[] =
5363 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5364 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5365 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5366 MSIRECORD *rec, *row;
5372 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5374 rec = MSI_CreateRecord( count + 2 );
5375 str = MSI_RecordGetString( row, 1 );
5376 MSI_RecordSetStringW( rec, 0, str );
5377 msiobj_release( &row->hdr );
5378 MSI_RecordSetInteger( rec, 1, error );
5380 va_start( va, count );
5381 for (i = 0; i < count; i++)
5383 str = va_arg( va, const WCHAR *);
5384 MSI_RecordSetStringW( rec, i + 2, str );
5388 MSI_FormatRecordW( package, rec, NULL, &size );
5390 data = msi_alloc( size * sizeof(WCHAR) );
5391 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5393 msiobj_release( &rec->hdr );
5397 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5403 * We are currently doing what should be done here in the top level Install
5404 * however for Administrative and uninstalls this step will be needed
5406 if (!package->PackagePath)
5407 return ERROR_SUCCESS;
5409 msi_set_sourcedir_props(package, TRUE);
5411 attrib = GetFileAttributesW(package->db->path);
5412 if (attrib == INVALID_FILE_ATTRIBUTES)
5417 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5418 package->Context, MSICODE_PRODUCT,
5419 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5420 if (rc == ERROR_MORE_DATA)
5422 prompt = msi_alloc(size * sizeof(WCHAR));
5423 MsiSourceListGetInfoW(package->ProductCode, NULL,
5424 package->Context, MSICODE_PRODUCT,
5425 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5428 prompt = strdupW(package->db->path);
5430 msg = msi_build_error_string(package, 1302, 1, prompt);
5432 while(attrib == INVALID_FILE_ATTRIBUTES)
5434 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5438 return ERROR_INSTALL_USEREXIT;
5440 attrib = GetFileAttributesW(package->db->path);
5446 return ERROR_SUCCESS;
5451 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5454 LPWSTR buffer, productid = NULL;
5455 UINT i, rc = ERROR_SUCCESS;
5458 static const WCHAR szPropKeys[][80] =
5460 {'P','r','o','d','u','c','t','I','D',0},
5461 {'U','S','E','R','N','A','M','E',0},
5462 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5466 static const WCHAR szRegKeys[][80] =
5468 {'P','r','o','d','u','c','t','I','D',0},
5469 {'R','e','g','O','w','n','e','r',0},
5470 {'R','e','g','C','o','m','p','a','n','y',0},
5474 if (msi_check_unpublish(package))
5476 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5480 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5484 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5486 if (rc != ERROR_SUCCESS)
5489 for( i = 0; szPropKeys[i][0]; i++ )
5491 buffer = msi_dup_property( package->db, szPropKeys[i] );
5492 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5497 uirow = MSI_CreateRecord( 1 );
5498 MSI_RecordSetStringW( uirow, 1, productid );
5499 msi_ui_actiondata( package, szRegisterUser, uirow );
5500 msiobj_release( &uirow->hdr );
5502 msi_free(productid);
5508 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5512 package->script->InWhatSequence |= SEQUENCE_EXEC;
5513 rc = ACTION_ProcessExecSequence(package,FALSE);
5517 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5519 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5520 WCHAR productid_85[21], component_85[21], *ret;
5524 /* > is used if there is a component GUID and < if not. */
5526 productid_85[0] = 0;
5527 component_85[0] = 0;
5528 CLSIDFromString( package->ProductCode, &clsid );
5530 encode_base85_guid( &clsid, productid_85 );
5533 CLSIDFromString( component->ComponentId, &clsid );
5534 encode_base85_guid( &clsid, component_85 );
5537 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5538 debugstr_w(component_85));
5540 sz = 20 + strlenW( feature ) + 20 + 3;
5541 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5542 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5546 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5548 MSIPACKAGE *package = param;
5549 LPCWSTR compgroupid, component, feature, qualifier, text;
5550 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5559 feature = MSI_RecordGetString(rec, 5);
5560 feat = msi_get_loaded_feature(package, feature);
5562 return ERROR_SUCCESS;
5564 feat->Action = msi_get_feature_action( package, feat );
5565 if (feat->Action != INSTALLSTATE_LOCAL &&
5566 feat->Action != INSTALLSTATE_SOURCE &&
5567 feat->Action != INSTALLSTATE_ADVERTISED)
5569 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5570 return ERROR_SUCCESS;
5573 component = MSI_RecordGetString(rec, 3);
5574 comp = msi_get_loaded_component(package, component);
5576 return ERROR_SUCCESS;
5578 compgroupid = MSI_RecordGetString(rec,1);
5579 qualifier = MSI_RecordGetString(rec,2);
5581 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5582 if (rc != ERROR_SUCCESS)
5585 advertise = msi_create_component_advertise_string( package, comp, feature );
5586 text = MSI_RecordGetString( rec, 4 );
5589 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5590 strcpyW( p, advertise );
5592 msi_free( advertise );
5595 existing = msi_reg_get_val_str( hkey, qualifier );
5597 sz = strlenW( advertise ) + 1;
5600 for (p = existing; *p; p += len)
5602 len = strlenW( p ) + 1;
5603 if (strcmpW( advertise, p )) sz += len;
5606 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5608 rc = ERROR_OUTOFMEMORY;
5614 for (p = existing; *p; p += len)
5616 len = strlenW( p ) + 1;
5617 if (strcmpW( advertise, p ))
5619 memcpy( q, p, len * sizeof(WCHAR) );
5624 strcpyW( q, advertise );
5625 q[strlenW( q ) + 1] = 0;
5627 msi_reg_set_val_multi_str( hkey, qualifier, output );
5632 msi_free( advertise );
5633 msi_free( existing );
5636 uirow = MSI_CreateRecord( 2 );
5637 MSI_RecordSetStringW( uirow, 1, compgroupid );
5638 MSI_RecordSetStringW( uirow, 2, qualifier);
5639 msi_ui_actiondata( package, szPublishComponents, uirow );
5640 msiobj_release( &uirow->hdr );
5641 /* FIXME: call ui_progress? */
5647 * At present I am ignorning the advertised components part of this and only
5648 * focusing on the qualified component sets
5650 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5652 static const WCHAR query[] = {
5653 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5654 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5658 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5659 if (rc != ERROR_SUCCESS)
5660 return ERROR_SUCCESS;
5662 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5663 msiobj_release(&view->hdr);
5667 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5669 static const WCHAR szInstallerComponents[] = {
5670 'S','o','f','t','w','a','r','e','\\',
5671 'M','i','c','r','o','s','o','f','t','\\',
5672 'I','n','s','t','a','l','l','e','r','\\',
5673 'C','o','m','p','o','n','e','n','t','s','\\',0};
5675 MSIPACKAGE *package = param;
5676 LPCWSTR compgroupid, component, feature, qualifier;
5680 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5683 feature = MSI_RecordGetString( rec, 5 );
5684 feat = msi_get_loaded_feature( package, feature );
5686 return ERROR_SUCCESS;
5688 feat->Action = msi_get_feature_action( package, feat );
5689 if (feat->Action != INSTALLSTATE_ABSENT)
5691 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5692 return ERROR_SUCCESS;
5695 component = MSI_RecordGetString( rec, 3 );
5696 comp = msi_get_loaded_component( package, component );
5698 return ERROR_SUCCESS;
5700 compgroupid = MSI_RecordGetString( rec, 1 );
5701 qualifier = MSI_RecordGetString( rec, 2 );
5703 squash_guid( compgroupid, squashed );
5704 strcpyW( keypath, szInstallerComponents );
5705 strcatW( keypath, squashed );
5707 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5708 if (res != ERROR_SUCCESS)
5710 WARN("Unable to delete component key %d\n", res);
5713 uirow = MSI_CreateRecord( 2 );
5714 MSI_RecordSetStringW( uirow, 1, compgroupid );
5715 MSI_RecordSetStringW( uirow, 2, qualifier );
5716 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5717 msiobj_release( &uirow->hdr );
5719 return ERROR_SUCCESS;
5722 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5724 static const WCHAR query[] = {
5725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5726 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5730 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5731 if (rc != ERROR_SUCCESS)
5732 return ERROR_SUCCESS;
5734 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5735 msiobj_release( &view->hdr );
5739 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5741 static const WCHAR query[] =
5742 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5743 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5744 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5745 MSIPACKAGE *package = param;
5746 MSICOMPONENT *component;
5749 SC_HANDLE hscm = NULL, service = NULL;
5751 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5752 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5753 DWORD serv_type, start_type, err_control;
5754 SERVICE_DESCRIPTIONW sd = {NULL};
5755 UINT ret = ERROR_SUCCESS;
5757 comp = MSI_RecordGetString( rec, 12 );
5758 component = msi_get_loaded_component( package, comp );
5761 WARN("service component not found\n");
5764 component->Action = msi_get_component_action( package, component );
5765 if (component->Action != INSTALLSTATE_LOCAL)
5767 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5770 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5773 ERR("Failed to open the SC Manager!\n");
5777 start_type = MSI_RecordGetInteger(rec, 5);
5778 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5781 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5782 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5783 serv_type = MSI_RecordGetInteger(rec, 4);
5784 err_control = MSI_RecordGetInteger(rec, 6);
5785 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5786 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5787 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5788 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5789 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5790 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5792 /* fetch the service path */
5793 row = MSI_QueryGetRecord(package->db, query, comp);
5796 ERR("Query failed\n");
5799 key = MSI_RecordGetString(row, 6);
5800 file = msi_get_loaded_file(package, key);
5801 msiobj_release(&row->hdr);
5804 ERR("Failed to load the service file\n");
5808 if (!args || !args[0]) image_path = file->TargetPath;
5811 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5812 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5814 ret = ERROR_OUTOFMEMORY;
5818 strcpyW(image_path, file->TargetPath);
5819 strcatW(image_path, szSpace);
5820 strcatW(image_path, args);
5822 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5823 start_type, err_control, image_path, load_order,
5824 NULL, depends, serv_name, pass);
5828 if (GetLastError() != ERROR_SERVICE_EXISTS)
5829 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5831 else if (sd.lpDescription)
5833 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5834 WARN("failed to set service description %u\n", GetLastError());
5837 if (image_path != file->TargetPath) msi_free(image_path);
5839 CloseServiceHandle(service);
5840 CloseServiceHandle(hscm);
5843 msi_free(sd.lpDescription);
5844 msi_free(load_order);
5845 msi_free(serv_name);
5853 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5855 static const WCHAR query[] = {
5856 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5857 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5861 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5862 if (rc != ERROR_SUCCESS)
5863 return ERROR_SUCCESS;
5865 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5866 msiobj_release(&view->hdr);
5870 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5871 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5873 LPCWSTR *vector, *temp_vector;
5877 static const WCHAR separator[] = {'[','~',']',0};
5880 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5885 vector = msi_alloc(sizeof(LPWSTR));
5893 vector[*numargs - 1] = p;
5895 if ((q = strstrW(p, separator)))
5899 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5905 vector = temp_vector;
5914 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5916 MSIPACKAGE *package = param;
5919 SC_HANDLE scm = NULL, service = NULL;
5920 LPCWSTR component, *vector = NULL;
5921 LPWSTR name, args, display_name = NULL;
5922 DWORD event, numargs, len, wait, dummy;
5923 UINT r = ERROR_FUNCTION_FAILED;
5924 SERVICE_STATUS_PROCESS status;
5925 ULONGLONG start_time;
5927 component = MSI_RecordGetString(rec, 6);
5928 comp = msi_get_loaded_component(package, component);
5930 return ERROR_SUCCESS;
5932 comp->Action = msi_get_component_action( package, comp );
5933 if (comp->Action != INSTALLSTATE_LOCAL)
5935 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5936 return ERROR_SUCCESS;
5939 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5940 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5941 event = MSI_RecordGetInteger(rec, 3);
5942 wait = MSI_RecordGetInteger(rec, 5);
5944 if (!(event & msidbServiceControlEventStart))
5950 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5953 ERR("Failed to open the service control manager\n");
5958 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5959 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5961 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5962 GetServiceDisplayNameW( scm, name, display_name, &len );
5965 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5968 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5972 vector = msi_service_args_to_vector(args, &numargs);
5974 if (!StartServiceW(service, numargs, vector) &&
5975 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5977 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5984 /* wait for at most 30 seconds for the service to be up and running */
5985 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5986 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5988 TRACE("failed to query service status (%u)\n", GetLastError());
5991 start_time = GetTickCount64();
5992 while (status.dwCurrentState == SERVICE_START_PENDING)
5994 if (GetTickCount64() - start_time > 30000) break;
5996 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5997 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5999 TRACE("failed to query service status (%u)\n", GetLastError());
6003 if (status.dwCurrentState != SERVICE_RUNNING)
6005 WARN("service failed to start %u\n", status.dwCurrentState);
6006 r = ERROR_FUNCTION_FAILED;
6011 uirow = MSI_CreateRecord( 2 );
6012 MSI_RecordSetStringW( uirow, 1, display_name );
6013 MSI_RecordSetStringW( uirow, 2, name );
6014 msi_ui_actiondata( package, szStartServices, uirow );
6015 msiobj_release( &uirow->hdr );
6017 CloseServiceHandle(service);
6018 CloseServiceHandle(scm);
6023 msi_free(display_name);
6027 static UINT ACTION_StartServices( MSIPACKAGE *package )
6029 static const WCHAR query[] = {
6030 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6031 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6035 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6036 if (rc != ERROR_SUCCESS)
6037 return ERROR_SUCCESS;
6039 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
6040 msiobj_release(&view->hdr);
6044 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6046 DWORD i, needed, count;
6047 ENUM_SERVICE_STATUSW *dependencies;
6050 BOOL stopped, ret = FALSE;
6052 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6053 0, &needed, &count))
6056 if (GetLastError() != ERROR_MORE_DATA)
6059 dependencies = msi_alloc(needed);
6063 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6064 needed, &needed, &count))
6067 for (i = 0; i < count; i++)
6069 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6070 SERVICE_STOP | SERVICE_QUERY_STATUS);
6074 stopped = ControlService(depserv, SERVICE_CONTROL_STOP, &ss);
6075 CloseServiceHandle(depserv);
6083 msi_free(dependencies);
6087 static UINT stop_service( LPCWSTR name )
6089 SC_HANDLE scm = NULL, service = NULL;
6090 SERVICE_STATUS status;
6091 SERVICE_STATUS_PROCESS ssp;
6094 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6097 WARN("Failed to open the SCM: %d\n", GetLastError());
6101 service = OpenServiceW(scm, name,
6103 SERVICE_QUERY_STATUS |
6104 SERVICE_ENUMERATE_DEPENDENTS);
6107 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
6111 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
6112 sizeof(SERVICE_STATUS_PROCESS), &needed))
6114 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
6118 if (ssp.dwCurrentState == SERVICE_STOPPED)
6121 stop_service_dependents(scm, service);
6123 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6124 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
6127 CloseServiceHandle(service);
6128 CloseServiceHandle(scm);
6130 return ERROR_SUCCESS;
6133 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6135 MSIPACKAGE *package = param;
6139 LPWSTR name = NULL, display_name = NULL;
6143 event = MSI_RecordGetInteger( rec, 3 );
6144 if (!(event & msidbServiceControlEventStop))
6145 return ERROR_SUCCESS;
6147 component = MSI_RecordGetString( rec, 6 );
6148 comp = msi_get_loaded_component( package, component );
6150 return ERROR_SUCCESS;
6152 comp->Action = msi_get_component_action( package, comp );
6153 if (comp->Action != INSTALLSTATE_ABSENT)
6155 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6156 return ERROR_SUCCESS;
6159 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6162 ERR("Failed to open the service control manager\n");
6167 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6168 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6170 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6171 GetServiceDisplayNameW( scm, name, display_name, &len );
6173 CloseServiceHandle( scm );
6175 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6176 stop_service( name );
6179 uirow = MSI_CreateRecord( 2 );
6180 MSI_RecordSetStringW( uirow, 1, display_name );
6181 MSI_RecordSetStringW( uirow, 2, name );
6182 msi_ui_actiondata( package, szStopServices, uirow );
6183 msiobj_release( &uirow->hdr );
6186 msi_free( display_name );
6187 return ERROR_SUCCESS;
6190 static UINT ACTION_StopServices( MSIPACKAGE *package )
6192 static const WCHAR query[] = {
6193 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6194 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6198 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6199 if (rc != ERROR_SUCCESS)
6200 return ERROR_SUCCESS;
6202 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6203 msiobj_release(&view->hdr);
6207 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6209 MSIPACKAGE *package = param;
6212 LPWSTR name = NULL, display_name = NULL;
6214 SC_HANDLE scm = NULL, service = NULL;
6216 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6218 return ERROR_SUCCESS;
6220 event = MSI_RecordGetInteger( rec, 3 );
6221 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6223 comp->Action = msi_get_component_action( package, comp );
6224 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6225 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6227 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6229 return ERROR_SUCCESS;
6231 stop_service( name );
6233 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6236 WARN("Failed to open the SCM: %d\n", GetLastError());
6241 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6242 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6244 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6245 GetServiceDisplayNameW( scm, name, display_name, &len );
6248 service = OpenServiceW( scm, name, DELETE );
6251 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6255 if (!DeleteService( service ))
6256 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6259 uirow = MSI_CreateRecord( 2 );
6260 MSI_RecordSetStringW( uirow, 1, display_name );
6261 MSI_RecordSetStringW( uirow, 2, name );
6262 msi_ui_actiondata( package, szDeleteServices, uirow );
6263 msiobj_release( &uirow->hdr );
6265 CloseServiceHandle( service );
6266 CloseServiceHandle( scm );
6268 msi_free( display_name );
6270 return ERROR_SUCCESS;
6273 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6275 static const WCHAR query[] = {
6276 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6277 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6281 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6282 if (rc != ERROR_SUCCESS)
6283 return ERROR_SUCCESS;
6285 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6286 msiobj_release( &view->hdr );
6290 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6292 MSIPACKAGE *package = param;
6293 LPWSTR driver, driver_path, ptr;
6294 WCHAR outpath[MAX_PATH];
6295 MSIFILE *driver_file = NULL, *setup_file = NULL;
6298 LPCWSTR desc, file_key, component;
6300 UINT r = ERROR_SUCCESS;
6302 static const WCHAR driver_fmt[] = {
6303 'D','r','i','v','e','r','=','%','s',0};
6304 static const WCHAR setup_fmt[] = {
6305 'S','e','t','u','p','=','%','s',0};
6306 static const WCHAR usage_fmt[] = {
6307 'F','i','l','e','U','s','a','g','e','=','1',0};
6309 component = MSI_RecordGetString( rec, 2 );
6310 comp = msi_get_loaded_component( package, component );
6312 return ERROR_SUCCESS;
6314 comp->Action = msi_get_component_action( package, comp );
6315 if (comp->Action != INSTALLSTATE_LOCAL)
6317 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6318 return ERROR_SUCCESS;
6320 desc = MSI_RecordGetString(rec, 3);
6322 file_key = MSI_RecordGetString( rec, 4 );
6323 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6325 file_key = MSI_RecordGetString( rec, 5 );
6326 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6330 ERR("ODBC Driver entry not found!\n");
6331 return ERROR_FUNCTION_FAILED;
6334 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6336 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6337 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6339 driver = msi_alloc(len * sizeof(WCHAR));
6341 return ERROR_OUTOFMEMORY;
6344 lstrcpyW(ptr, desc);
6345 ptr += lstrlenW(ptr) + 1;
6347 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6352 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6356 lstrcpyW(ptr, usage_fmt);
6357 ptr += lstrlenW(ptr) + 1;
6360 if (!driver_file->TargetPath)
6362 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6363 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6365 driver_path = strdupW(driver_file->TargetPath);
6366 ptr = strrchrW(driver_path, '\\');
6367 if (ptr) *ptr = '\0';
6369 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6370 NULL, ODBC_INSTALL_COMPLETE, &usage))
6372 ERR("Failed to install SQL driver!\n");
6373 r = ERROR_FUNCTION_FAILED;
6376 uirow = MSI_CreateRecord( 5 );
6377 MSI_RecordSetStringW( uirow, 1, desc );
6378 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6379 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6380 msi_ui_actiondata( package, szInstallODBC, uirow );
6381 msiobj_release( &uirow->hdr );
6384 msi_free(driver_path);
6389 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6391 MSIPACKAGE *package = param;
6392 LPWSTR translator, translator_path, ptr;
6393 WCHAR outpath[MAX_PATH];
6394 MSIFILE *translator_file = NULL, *setup_file = NULL;
6397 LPCWSTR desc, file_key, component;
6399 UINT r = ERROR_SUCCESS;
6401 static const WCHAR translator_fmt[] = {
6402 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6403 static const WCHAR setup_fmt[] = {
6404 'S','e','t','u','p','=','%','s',0};
6406 component = MSI_RecordGetString( rec, 2 );
6407 comp = msi_get_loaded_component( package, component );
6409 return ERROR_SUCCESS;
6411 comp->Action = msi_get_component_action( package, comp );
6412 if (comp->Action != INSTALLSTATE_LOCAL)
6414 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6415 return ERROR_SUCCESS;
6417 desc = MSI_RecordGetString(rec, 3);
6419 file_key = MSI_RecordGetString( rec, 4 );
6420 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6422 file_key = MSI_RecordGetString( rec, 5 );
6423 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6425 if (!translator_file)
6427 ERR("ODBC Translator entry not found!\n");
6428 return ERROR_FUNCTION_FAILED;
6431 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6433 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6435 translator = msi_alloc(len * sizeof(WCHAR));
6437 return ERROR_OUTOFMEMORY;
6440 lstrcpyW(ptr, desc);
6441 ptr += lstrlenW(ptr) + 1;
6443 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6448 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6453 translator_path = strdupW(translator_file->TargetPath);
6454 ptr = strrchrW(translator_path, '\\');
6455 if (ptr) *ptr = '\0';
6457 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6458 NULL, ODBC_INSTALL_COMPLETE, &usage))
6460 ERR("Failed to install SQL translator!\n");
6461 r = ERROR_FUNCTION_FAILED;
6464 uirow = MSI_CreateRecord( 5 );
6465 MSI_RecordSetStringW( uirow, 1, desc );
6466 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6467 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6468 msi_ui_actiondata( package, szInstallODBC, uirow );
6469 msiobj_release( &uirow->hdr );
6471 msi_free(translator);
6472 msi_free(translator_path);
6477 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6479 MSIPACKAGE *package = param;
6482 LPCWSTR desc, driver, component;
6483 WORD request = ODBC_ADD_SYS_DSN;
6486 UINT r = ERROR_SUCCESS;
6489 static const WCHAR attrs_fmt[] = {
6490 'D','S','N','=','%','s',0 };
6492 component = MSI_RecordGetString( rec, 2 );
6493 comp = msi_get_loaded_component( package, component );
6495 return ERROR_SUCCESS;
6497 comp->Action = msi_get_component_action( package, comp );
6498 if (comp->Action != INSTALLSTATE_LOCAL)
6500 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6501 return ERROR_SUCCESS;
6504 desc = MSI_RecordGetString(rec, 3);
6505 driver = MSI_RecordGetString(rec, 4);
6506 registration = MSI_RecordGetInteger(rec, 5);
6508 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6509 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6511 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6512 attrs = msi_alloc(len * sizeof(WCHAR));
6514 return ERROR_OUTOFMEMORY;
6516 len = sprintfW(attrs, attrs_fmt, desc);
6519 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6521 ERR("Failed to install SQL data source!\n");
6522 r = ERROR_FUNCTION_FAILED;
6525 uirow = MSI_CreateRecord( 5 );
6526 MSI_RecordSetStringW( uirow, 1, desc );
6527 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6528 MSI_RecordSetInteger( uirow, 3, request );
6529 msi_ui_actiondata( package, szInstallODBC, uirow );
6530 msiobj_release( &uirow->hdr );
6537 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6539 static const WCHAR driver_query[] = {
6540 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6541 'O','D','B','C','D','r','i','v','e','r',0};
6542 static const WCHAR translator_query[] = {
6543 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6544 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6545 static const WCHAR source_query[] = {
6546 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6547 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6551 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6552 if (rc == ERROR_SUCCESS)
6554 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6555 msiobj_release(&view->hdr);
6556 if (rc != ERROR_SUCCESS)
6559 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6560 if (rc == ERROR_SUCCESS)
6562 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6563 msiobj_release(&view->hdr);
6564 if (rc != ERROR_SUCCESS)
6567 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6568 if (rc == ERROR_SUCCESS)
6570 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6571 msiobj_release(&view->hdr);
6572 if (rc != ERROR_SUCCESS)
6575 return ERROR_SUCCESS;
6578 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6580 MSIPACKAGE *package = param;
6584 LPCWSTR desc, component;
6586 component = MSI_RecordGetString( rec, 2 );
6587 comp = msi_get_loaded_component( package, component );
6589 return ERROR_SUCCESS;
6591 comp->Action = msi_get_component_action( package, comp );
6592 if (comp->Action != INSTALLSTATE_ABSENT)
6594 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6595 return ERROR_SUCCESS;
6598 desc = MSI_RecordGetString( rec, 3 );
6599 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6601 WARN("Failed to remove ODBC driver\n");
6605 FIXME("Usage count reached 0\n");
6608 uirow = MSI_CreateRecord( 2 );
6609 MSI_RecordSetStringW( uirow, 1, desc );
6610 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6611 msi_ui_actiondata( package, szRemoveODBC, uirow );
6612 msiobj_release( &uirow->hdr );
6614 return ERROR_SUCCESS;
6617 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6619 MSIPACKAGE *package = param;
6623 LPCWSTR desc, component;
6625 component = MSI_RecordGetString( rec, 2 );
6626 comp = msi_get_loaded_component( package, component );
6628 return ERROR_SUCCESS;
6630 comp->Action = msi_get_component_action( package, comp );
6631 if (comp->Action != INSTALLSTATE_ABSENT)
6633 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6634 return ERROR_SUCCESS;
6637 desc = MSI_RecordGetString( rec, 3 );
6638 if (!SQLRemoveTranslatorW( desc, &usage ))
6640 WARN("Failed to remove ODBC translator\n");
6644 FIXME("Usage count reached 0\n");
6647 uirow = MSI_CreateRecord( 2 );
6648 MSI_RecordSetStringW( uirow, 1, desc );
6649 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6650 msi_ui_actiondata( package, szRemoveODBC, uirow );
6651 msiobj_release( &uirow->hdr );
6653 return ERROR_SUCCESS;
6656 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6658 MSIPACKAGE *package = param;
6662 LPCWSTR desc, driver, component;
6663 WORD request = ODBC_REMOVE_SYS_DSN;
6667 static const WCHAR attrs_fmt[] = {
6668 'D','S','N','=','%','s',0 };
6670 component = MSI_RecordGetString( rec, 2 );
6671 comp = msi_get_loaded_component( package, component );
6673 return ERROR_SUCCESS;
6675 comp->Action = msi_get_component_action( package, comp );
6676 if (comp->Action != INSTALLSTATE_ABSENT)
6678 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6679 return ERROR_SUCCESS;
6682 desc = MSI_RecordGetString( rec, 3 );
6683 driver = MSI_RecordGetString( rec, 4 );
6684 registration = MSI_RecordGetInteger( rec, 5 );
6686 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6687 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6689 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6690 attrs = msi_alloc( len * sizeof(WCHAR) );
6692 return ERROR_OUTOFMEMORY;
6694 FIXME("Use ODBCSourceAttribute table\n");
6696 len = sprintfW( attrs, attrs_fmt, desc );
6699 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6701 WARN("Failed to remove ODBC data source\n");
6705 uirow = MSI_CreateRecord( 3 );
6706 MSI_RecordSetStringW( uirow, 1, desc );
6707 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6708 MSI_RecordSetInteger( uirow, 3, request );
6709 msi_ui_actiondata( package, szRemoveODBC, uirow );
6710 msiobj_release( &uirow->hdr );
6712 return ERROR_SUCCESS;
6715 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6717 static const WCHAR driver_query[] = {
6718 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6719 'O','D','B','C','D','r','i','v','e','r',0};
6720 static const WCHAR translator_query[] = {
6721 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6722 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6723 static const WCHAR source_query[] = {
6724 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6725 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6729 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6730 if (rc == ERROR_SUCCESS)
6732 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6733 msiobj_release( &view->hdr );
6734 if (rc != ERROR_SUCCESS)
6737 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6738 if (rc == ERROR_SUCCESS)
6740 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6741 msiobj_release( &view->hdr );
6742 if (rc != ERROR_SUCCESS)
6745 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6746 if (rc == ERROR_SUCCESS)
6748 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6749 msiobj_release( &view->hdr );
6750 if (rc != ERROR_SUCCESS)
6753 return ERROR_SUCCESS;
6756 #define ENV_ACT_SETALWAYS 0x1
6757 #define ENV_ACT_SETABSENT 0x2
6758 #define ENV_ACT_REMOVE 0x4
6759 #define ENV_ACT_REMOVEMATCH 0x8
6761 #define ENV_MOD_MACHINE 0x20000000
6762 #define ENV_MOD_APPEND 0x40000000
6763 #define ENV_MOD_PREFIX 0x80000000
6764 #define ENV_MOD_MASK 0xC0000000
6766 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6768 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6770 LPCWSTR cptr = *name;
6772 static const WCHAR prefix[] = {'[','~',']',0};
6773 static const int prefix_len = 3;
6779 *flags |= ENV_ACT_SETALWAYS;
6780 else if (*cptr == '+')
6781 *flags |= ENV_ACT_SETABSENT;
6782 else if (*cptr == '-')
6783 *flags |= ENV_ACT_REMOVE;
6784 else if (*cptr == '!')
6785 *flags |= ENV_ACT_REMOVEMATCH;
6786 else if (*cptr == '*')
6787 *flags |= ENV_MOD_MACHINE;
6797 ERR("Missing environment variable\n");
6798 return ERROR_FUNCTION_FAILED;
6803 LPCWSTR ptr = *value;
6804 if (!strncmpW(ptr, prefix, prefix_len))
6806 if (ptr[prefix_len] == szSemiColon[0])
6808 *flags |= ENV_MOD_APPEND;
6809 *value += lstrlenW(prefix);
6816 else if (lstrlenW(*value) >= prefix_len)
6818 ptr += lstrlenW(ptr) - prefix_len;
6819 if (!strcmpW( ptr, prefix ))
6821 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6823 *flags |= ENV_MOD_PREFIX;
6824 /* the "[~]" will be removed by deformat_string */;
6834 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6835 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6836 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6837 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6839 ERR("Invalid flags: %08x\n", *flags);
6840 return ERROR_FUNCTION_FAILED;
6844 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6846 return ERROR_SUCCESS;
6849 static UINT open_env_key( DWORD flags, HKEY *key )
6851 static const WCHAR user_env[] =
6852 {'E','n','v','i','r','o','n','m','e','n','t',0};
6853 static const WCHAR machine_env[] =
6854 {'S','y','s','t','e','m','\\',
6855 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6856 'C','o','n','t','r','o','l','\\',
6857 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6858 'E','n','v','i','r','o','n','m','e','n','t',0};
6863 if (flags & ENV_MOD_MACHINE)
6866 root = HKEY_LOCAL_MACHINE;
6871 root = HKEY_CURRENT_USER;
6874 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6875 if (res != ERROR_SUCCESS)
6877 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6878 return ERROR_FUNCTION_FAILED;
6881 return ERROR_SUCCESS;
6884 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6886 MSIPACKAGE *package = param;
6887 LPCWSTR name, value, component;
6888 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6889 DWORD flags, type, size;
6896 component = MSI_RecordGetString(rec, 4);
6897 comp = msi_get_loaded_component(package, component);
6899 return ERROR_SUCCESS;
6901 comp->Action = msi_get_component_action( package, comp );
6902 if (comp->Action != INSTALLSTATE_LOCAL)
6904 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6905 return ERROR_SUCCESS;
6907 name = MSI_RecordGetString(rec, 2);
6908 value = MSI_RecordGetString(rec, 3);
6910 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6912 res = env_parse_flags(&name, &value, &flags);
6913 if (res != ERROR_SUCCESS || !value)
6916 if (value && !deformat_string(package, value, &deformatted))
6918 res = ERROR_OUTOFMEMORY;
6922 value = deformatted;
6924 res = open_env_key( flags, &env );
6925 if (res != ERROR_SUCCESS)
6928 if (flags & ENV_MOD_MACHINE)
6929 action |= 0x20000000;
6933 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6934 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6935 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6938 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6942 /* Nothing to do. */
6945 res = ERROR_SUCCESS;
6949 /* If we are appending but the string was empty, strip ; */
6950 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6952 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6953 newval = strdupW(value);
6956 res = ERROR_OUTOFMEMORY;
6964 /* Contrary to MSDN, +-variable to [~];path works */
6965 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6967 res = ERROR_SUCCESS;
6971 data = msi_alloc(size);
6975 return ERROR_OUTOFMEMORY;
6978 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6979 if (res != ERROR_SUCCESS)
6982 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6985 res = RegDeleteValueW(env, name);
6986 if (res != ERROR_SUCCESS)
6987 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6991 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6992 if (flags & ENV_MOD_MASK)
6996 if (flags & ENV_MOD_APPEND) multiplier++;
6997 if (flags & ENV_MOD_PREFIX) multiplier++;
6998 mod_size = lstrlenW(value) * multiplier;
6999 size += mod_size * sizeof(WCHAR);
7002 newval = msi_alloc(size);
7006 res = ERROR_OUTOFMEMORY;
7010 if (flags & ENV_MOD_PREFIX)
7012 lstrcpyW(newval, value);
7013 ptr = newval + lstrlenW(value);
7014 action |= 0x80000000;
7017 lstrcpyW(ptr, data);
7019 if (flags & ENV_MOD_APPEND)
7021 lstrcatW(newval, value);
7022 action |= 0x40000000;
7025 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
7026 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
7029 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7033 uirow = MSI_CreateRecord( 3 );
7034 MSI_RecordSetStringW( uirow, 1, name );
7035 MSI_RecordSetStringW( uirow, 2, newval );
7036 MSI_RecordSetInteger( uirow, 3, action );
7037 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
7038 msiobj_release( &uirow->hdr );
7040 if (env) RegCloseKey(env);
7041 msi_free(deformatted);
7047 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7049 static const WCHAR query[] = {
7050 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7051 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7055 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
7056 if (rc != ERROR_SUCCESS)
7057 return ERROR_SUCCESS;
7059 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7060 msiobj_release(&view->hdr);
7064 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7066 MSIPACKAGE *package = param;
7067 LPCWSTR name, value, component;
7068 LPWSTR deformatted = NULL;
7077 component = MSI_RecordGetString( rec, 4 );
7078 comp = msi_get_loaded_component( package, component );
7080 return ERROR_SUCCESS;
7082 comp->Action = msi_get_component_action( package, comp );
7083 if (comp->Action != INSTALLSTATE_ABSENT)
7085 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
7086 return ERROR_SUCCESS;
7088 name = MSI_RecordGetString( rec, 2 );
7089 value = MSI_RecordGetString( rec, 3 );
7091 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7093 r = env_parse_flags( &name, &value, &flags );
7094 if (r != ERROR_SUCCESS)
7097 if (!(flags & ENV_ACT_REMOVE))
7099 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7100 return ERROR_SUCCESS;
7103 if (value && !deformat_string( package, value, &deformatted ))
7104 return ERROR_OUTOFMEMORY;
7106 value = deformatted;
7108 r = open_env_key( flags, &env );
7109 if (r != ERROR_SUCCESS)
7115 if (flags & ENV_MOD_MACHINE)
7116 action |= 0x20000000;
7118 TRACE("Removing %s\n", debugstr_w(name));
7120 res = RegDeleteValueW( env, name );
7121 if (res != ERROR_SUCCESS)
7123 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
7128 uirow = MSI_CreateRecord( 3 );
7129 MSI_RecordSetStringW( uirow, 1, name );
7130 MSI_RecordSetStringW( uirow, 2, value );
7131 MSI_RecordSetInteger( uirow, 3, action );
7132 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
7133 msiobj_release( &uirow->hdr );
7135 if (env) RegCloseKey( env );
7136 msi_free( deformatted );
7140 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7142 static const WCHAR query[] = {
7143 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7144 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7148 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
7149 if (rc != ERROR_SUCCESS)
7150 return ERROR_SUCCESS;
7152 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7153 msiobj_release( &view->hdr );
7157 UINT msi_validate_product_id( MSIPACKAGE *package )
7159 LPWSTR key, template, id;
7160 UINT r = ERROR_SUCCESS;
7162 id = msi_dup_property( package->db, szProductID );
7166 return ERROR_SUCCESS;
7168 template = msi_dup_property( package->db, szPIDTemplate );
7169 key = msi_dup_property( package->db, szPIDKEY );
7170 if (key && template)
7172 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7173 r = msi_set_property( package->db, szProductID, key, -1 );
7175 msi_free( template );
7180 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7182 return msi_validate_product_id( package );
7185 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7188 package->need_reboot_at_end = 1;
7189 return ERROR_SUCCESS;
7192 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7194 static const WCHAR szAvailableFreeReg[] =
7195 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7197 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7199 TRACE("%p %d kilobytes\n", package, space);
7201 uirow = MSI_CreateRecord( 1 );
7202 MSI_RecordSetInteger( uirow, 1, space );
7203 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
7204 msiobj_release( &uirow->hdr );
7206 return ERROR_SUCCESS;
7209 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7211 TRACE("%p\n", package);
7213 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7214 return ERROR_SUCCESS;
7217 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7219 FIXME("%p\n", package);
7220 return ERROR_SUCCESS;
7223 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7225 static const WCHAR driver_query[] = {
7226 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7227 'O','D','B','C','D','r','i','v','e','r',0};
7228 static const WCHAR translator_query[] = {
7229 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7230 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
7234 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7235 if (r == ERROR_SUCCESS)
7238 r = MSI_IterateRecords( view, &count, NULL, package );
7239 msiobj_release( &view->hdr );
7240 if (r != ERROR_SUCCESS)
7242 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7244 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7245 if (r == ERROR_SUCCESS)
7248 r = MSI_IterateRecords( view, &count, NULL, package );
7249 msiobj_release( &view->hdr );
7250 if (r != ERROR_SUCCESS)
7252 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7254 return ERROR_SUCCESS;
7257 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7259 static const WCHAR fmtW[] =
7260 {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0};
7261 MSIPACKAGE *package = param;
7262 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7263 UINT len = sizeof(fmtW)/sizeof(fmtW[0]);
7264 WCHAR *product, *features, *cmd;
7266 PROCESS_INFORMATION info;
7269 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7271 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7273 len += strlenW( product );
7275 len += strlenW( features );
7277 len += sizeof(szAll) / sizeof(szAll[0]);
7279 if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
7281 msi_free( product );
7282 msi_free( features );
7283 return ERROR_OUTOFMEMORY;
7285 sprintfW( cmd, fmtW, product, features ? features : szAll );
7286 msi_free( product );
7287 msi_free( features );
7289 memset( &si, 0, sizeof(STARTUPINFOW) );
7290 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7292 if (!ret) return GetLastError();
7293 CloseHandle( info.hThread );
7295 WaitForSingleObject( info.hProcess, INFINITE );
7296 CloseHandle( info.hProcess );
7297 return ERROR_SUCCESS;
7300 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7302 static const WCHAR query[] = {
7303 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7307 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7308 if (r == ERROR_SUCCESS)
7310 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7311 msiobj_release( &view->hdr );
7312 if (r != ERROR_SUCCESS)
7315 return ERROR_SUCCESS;
7318 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7320 MSIPACKAGE *package = param;
7321 int attributes = MSI_RecordGetInteger( rec, 5 );
7323 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7325 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7326 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7327 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7328 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7332 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7334 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7335 if (r != ERROR_SUCCESS)
7336 return ERROR_SUCCESS;
7340 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7341 if (r != ERROR_SUCCESS)
7342 return ERROR_SUCCESS;
7344 RegCloseKey( hkey );
7346 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7347 debugstr_w(upgrade_code), debugstr_w(version_min),
7348 debugstr_w(version_max), debugstr_w(language));
7350 return ERROR_SUCCESS;
7353 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7355 static const WCHAR query[] = {
7356 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7357 'U','p','g','r','a','d','e',0};
7361 if (msi_get_property_int( package->db, szInstalled, 0 ))
7363 TRACE("product is installed, skipping action\n");
7364 return ERROR_SUCCESS;
7366 if (msi_get_property_int( package->db, szPreselected, 0 ))
7368 TRACE("Preselected property is set, not migrating feature states\n");
7369 return ERROR_SUCCESS;
7371 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7372 if (r == ERROR_SUCCESS)
7374 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7375 msiobj_release( &view->hdr );
7376 if (r != ERROR_SUCCESS)
7379 return ERROR_SUCCESS;
7382 static void bind_image( const char *filename, const char *path )
7384 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7386 WARN("failed to bind image %u\n", GetLastError());
7390 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7394 MSIPACKAGE *package = param;
7395 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7396 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7397 char *filenameA, *pathA;
7398 WCHAR *pathW, **path_list;
7400 if (!(file = msi_get_loaded_file( package, key )))
7402 WARN("file %s not found\n", debugstr_w(key));
7403 return ERROR_SUCCESS;
7405 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7406 path_list = msi_split_string( paths, ';' );
7407 if (!path_list) bind_image( filenameA, NULL );
7410 for (i = 0; path_list[i] && path_list[i][0]; i++)
7412 deformat_string( package, path_list[i], &pathW );
7413 if ((pathA = strdupWtoA( pathW )))
7415 bind_image( filenameA, pathA );
7421 msi_free( path_list );
7422 msi_free( filenameA );
7423 return ERROR_SUCCESS;
7426 static UINT ACTION_BindImage( MSIPACKAGE *package )
7428 static const WCHAR query[] = {
7429 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7430 'B','i','n','d','I','m','a','g','e',0};
7434 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7435 if (r == ERROR_SUCCESS)
7437 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7438 msiobj_release( &view->hdr );
7439 if (r != ERROR_SUCCESS)
7442 return ERROR_SUCCESS;
7445 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7447 static const WCHAR query[] = {
7448 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7453 r = MSI_OpenQuery( package->db, &view, query, table );
7454 if (r == ERROR_SUCCESS)
7456 r = MSI_IterateRecords(view, &count, NULL, package);
7457 msiobj_release(&view->hdr);
7458 if (r != ERROR_SUCCESS)
7461 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7462 return ERROR_SUCCESS;
7465 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7467 static const WCHAR table[] = {
7468 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7469 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7472 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7474 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7475 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7478 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7480 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7481 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7484 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7486 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7487 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7490 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7492 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7493 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7498 const WCHAR *action;
7499 UINT (*handler)(MSIPACKAGE *);
7500 const WCHAR *action_rollback;
7504 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7505 { szAppSearch, ACTION_AppSearch, NULL },
7506 { szBindImage, ACTION_BindImage, NULL },
7507 { szCCPSearch, ACTION_CCPSearch, NULL },
7508 { szCostFinalize, ACTION_CostFinalize, NULL },
7509 { szCostInitialize, ACTION_CostInitialize, NULL },
7510 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7511 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7512 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7513 { szDisableRollback, ACTION_DisableRollback, NULL },
7514 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7515 { szExecuteAction, ACTION_ExecuteAction, NULL },
7516 { szFileCost, ACTION_FileCost, NULL },
7517 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7518 { szForceReboot, ACTION_ForceReboot, NULL },
7519 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7520 { szInstallExecute, ACTION_InstallExecute, NULL },
7521 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7522 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7523 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7524 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7525 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7526 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7527 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7528 { szInstallValidate, ACTION_InstallValidate, NULL },
7529 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7530 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7531 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7532 { szMoveFiles, ACTION_MoveFiles, NULL },
7533 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7534 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7535 { szPatchFiles, ACTION_PatchFiles, NULL },
7536 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7537 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7538 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7539 { szPublishProduct, ACTION_PublishProduct, NULL },
7540 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7541 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7542 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7543 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7544 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7545 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7546 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7547 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7548 { szRegisterUser, ACTION_RegisterUser, NULL },
7549 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7550 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7551 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7552 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7553 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7554 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7555 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7556 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7557 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7558 { szResolveSource, ACTION_ResolveSource, NULL },
7559 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7560 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7561 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7562 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7563 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7564 { szStartServices, ACTION_StartServices, szStopServices },
7565 { szStopServices, ACTION_StopServices, szStartServices },
7566 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7567 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7568 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7569 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7570 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7571 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7572 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7573 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7574 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7575 { szValidateProductID, ACTION_ValidateProductID, NULL },
7576 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7577 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7578 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7579 { NULL, NULL, NULL }
7582 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7588 while (StandardActions[i].action != NULL)
7590 if (!strcmpW( StandardActions[i].action, action ))
7592 ui_actionstart( package, action );
7593 if (StandardActions[i].handler)
7595 ui_actioninfo( package, action, TRUE, 0 );
7596 *rc = StandardActions[i].handler( package );
7597 ui_actioninfo( package, action, FALSE, *rc );
7599 if (StandardActions[i].action_rollback && !package->need_rollback)
7601 TRACE("scheduling rollback action\n");
7602 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7607 FIXME("unhandled standard action %s\n", debugstr_w(action));
7608 *rc = ERROR_SUCCESS;
7618 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7620 UINT rc = ERROR_SUCCESS;
7623 TRACE("Performing action (%s)\n", debugstr_w(action));
7625 handled = ACTION_HandleStandardAction(package, action, &rc);
7628 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7632 WARN("unhandled msi action %s\n", debugstr_w(action));
7633 rc = ERROR_FUNCTION_NOT_CALLED;
7639 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7641 UINT rc = ERROR_SUCCESS;
7642 BOOL handled = FALSE;
7644 TRACE("Performing action (%s)\n", debugstr_w(action));
7646 package->action_progress_increment = 0;
7647 handled = ACTION_HandleStandardAction(package, action, &rc);
7650 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7652 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7657 WARN("unhandled msi action %s\n", debugstr_w(action));
7658 rc = ERROR_FUNCTION_NOT_CALLED;
7664 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7666 UINT rc = ERROR_SUCCESS;
7669 static const WCHAR query[] =
7670 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7671 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7672 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7673 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7674 static const WCHAR ui_query[] =
7675 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7676 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7677 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7678 ' ', '=',' ','%','i',0};
7680 if (needs_ui_sequence(package))
7681 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7683 row = MSI_QueryGetRecord(package->db, query, seq);
7687 LPCWSTR action, cond;
7689 TRACE("Running the actions\n");
7691 /* check conditions */
7692 cond = MSI_RecordGetString(row, 2);
7694 /* this is a hack to skip errors in the condition code */
7695 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7697 msiobj_release(&row->hdr);
7698 return ERROR_SUCCESS;
7701 action = MSI_RecordGetString(row, 1);
7704 ERR("failed to fetch action\n");
7705 msiobj_release(&row->hdr);
7706 return ERROR_FUNCTION_FAILED;
7709 if (needs_ui_sequence(package))
7710 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7712 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7714 msiobj_release(&row->hdr);
7720 /****************************************************
7721 * TOP level entry points
7722 *****************************************************/
7724 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7725 LPCWSTR szCommandLine )
7727 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7728 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7729 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7730 WCHAR *reinstall, *remove, *patch;
7734 msi_set_property( package->db, szAction, szInstall, -1 );
7736 package->script->InWhatSequence = SEQUENCE_INSTALL;
7743 dir = strdupW(szPackagePath);
7744 p = strrchrW(dir, '\\');
7748 file = szPackagePath + (p - dir);
7753 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7754 GetCurrentDirectoryW(MAX_PATH, dir);
7755 lstrcatW(dir, szBackSlash);
7756 file = szPackagePath;
7759 msi_free( package->PackagePath );
7760 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7761 if (!package->PackagePath)
7764 return ERROR_OUTOFMEMORY;
7767 lstrcpyW(package->PackagePath, dir);
7768 lstrcatW(package->PackagePath, file);
7771 msi_set_sourcedir_props(package, FALSE);
7774 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7775 if (rc != ERROR_SUCCESS)
7778 msi_apply_transforms( package );
7779 msi_apply_patches( package );
7781 patch = msi_dup_property( package->db, szPatch );
7782 remove = msi_dup_property( package->db, szRemove );
7783 reinstall = msi_dup_property( package->db, szReinstall );
7784 if (msi_get_property_int( package->db, szInstalled, 0 ) && !remove && !reinstall && !patch)
7786 TRACE("setting REINSTALL property to ALL\n");
7787 msi_set_property( package->db, szReinstall, szAll, -1 );
7788 package->full_reinstall = 1;
7791 /* properties may have been added by a transform */
7792 msi_clone_properties( package );
7794 msi_parse_command_line( package, szCommandLine, FALSE );
7795 msi_adjust_privilege_properties( package );
7796 msi_set_context( package );
7798 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7800 TRACE("disabling rollback\n");
7801 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7804 if (needs_ui_sequence( package))
7806 package->script->InWhatSequence |= SEQUENCE_UI;
7807 rc = ACTION_ProcessUISequence(package);
7808 ui_exists = ui_sequence_exists(package);
7809 if (rc == ERROR_SUCCESS || !ui_exists)
7811 package->script->InWhatSequence |= SEQUENCE_EXEC;
7812 rc = ACTION_ProcessExecSequence(package, ui_exists);
7816 rc = ACTION_ProcessExecSequence(package, FALSE);
7818 package->script->CurrentlyScripting = FALSE;
7820 /* process the ending type action */
7821 if (rc == ERROR_SUCCESS)
7822 ACTION_PerformActionSequence(package, -1);
7823 else if (rc == ERROR_INSTALL_USEREXIT)
7824 ACTION_PerformActionSequence(package, -2);
7825 else if (rc == ERROR_INSTALL_SUSPEND)
7826 ACTION_PerformActionSequence(package, -4);
7829 ACTION_PerformActionSequence(package, -3);
7830 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7832 package->need_rollback = TRUE;
7836 /* finish up running custom actions */
7837 ACTION_FinishCustomActions(package);
7839 if (package->need_rollback && !reinstall)
7841 WARN("installation failed, running rollback script\n");
7842 execute_script( package, SCRIPT_ROLLBACK );
7844 msi_free( reinstall );
7848 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7849 return ERROR_SUCCESS_REBOOT_REQUIRED;