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 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
691 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
693 if (!strcmpW( dir, folder->Directory )) return folder;
699 * Recursively create all directories in the path.
700 * shamelessly stolen from setupapi/queue.c
702 BOOL msi_create_full_path( const WCHAR *path )
708 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
709 strcpyW( new_path, path );
711 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
712 new_path[len - 1] = 0;
714 while (!CreateDirectoryW( new_path, NULL ))
717 DWORD last_error = GetLastError();
718 if (last_error == ERROR_ALREADY_EXISTS) break;
719 if (last_error != ERROR_PATH_NOT_FOUND)
724 if (!(slash = strrchrW( new_path, '\\' )))
729 len = slash - new_path;
731 if (!msi_create_full_path( new_path ))
736 new_path[len] = '\\';
738 msi_free( new_path );
742 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
746 row = MSI_CreateRecord( 4 );
747 MSI_RecordSetInteger( row, 1, a );
748 MSI_RecordSetInteger( row, 2, b );
749 MSI_RecordSetInteger( row, 3, c );
750 MSI_RecordSetInteger( row, 4, d );
751 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
752 msiobj_release( &row->hdr );
754 msi_dialog_check_messages( NULL );
757 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
759 static const WCHAR query[] =
760 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
761 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
762 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
767 if (!package->LastAction || strcmpW( package->LastAction, action ))
769 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
771 if (MSI_RecordIsNull( row, 3 ))
773 msiobj_release( &row->hdr );
776 /* update the cached action format */
777 msi_free( package->ActionFormat );
778 package->ActionFormat = msi_dup_record_field( row, 3 );
779 msi_free( package->LastAction );
780 package->LastAction = strdupW( action );
781 msiobj_release( &row->hdr );
784 MSI_RecordSetStringW( record, 0, package->ActionFormat );
785 MSI_FormatRecordW( package, record, message, &size );
786 row = MSI_CreateRecord( 1 );
787 MSI_RecordSetStringW( row, 1, message );
788 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
789 msiobj_release( &row->hdr );
792 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
796 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
797 return INSTALLSTATE_UNKNOWN;
799 if (package->need_rollback) return comp->Installed;
800 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
802 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
803 return INSTALLSTATE_UNKNOWN;
805 return comp->ActionRequest;
808 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
810 if (package->need_rollback) return feature->Installed;
811 return feature->ActionRequest;
814 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
816 MSIPACKAGE *package = param;
817 LPCWSTR dir, component, full_path;
822 component = MSI_RecordGetString(row, 2);
824 return ERROR_SUCCESS;
826 comp = msi_get_loaded_component(package, component);
828 return ERROR_SUCCESS;
830 comp->Action = msi_get_component_action( package, comp );
831 if (comp->Action != INSTALLSTATE_LOCAL)
833 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
834 return ERROR_SUCCESS;
837 dir = MSI_RecordGetString(row,1);
840 ERR("Unable to get folder id\n");
841 return ERROR_SUCCESS;
844 uirow = MSI_CreateRecord(1);
845 MSI_RecordSetStringW(uirow, 1, dir);
846 msi_ui_actiondata(package, szCreateFolders, uirow);
847 msiobj_release(&uirow->hdr);
849 full_path = msi_get_target_folder( package, dir );
852 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
853 return ERROR_SUCCESS;
855 TRACE("folder is %s\n", debugstr_w(full_path));
857 folder = msi_get_loaded_folder( package, dir );
858 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
859 folder->State = FOLDER_STATE_CREATED;
860 return ERROR_SUCCESS;
863 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
865 static const WCHAR query[] = {
866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
867 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
871 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
872 if (rc != ERROR_SUCCESS)
873 return ERROR_SUCCESS;
875 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
876 msiobj_release(&view->hdr);
880 static void remove_persistent_folder( MSIFOLDER *folder )
884 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
886 remove_persistent_folder( fl->folder );
888 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
890 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
894 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
896 MSIPACKAGE *package = param;
897 LPCWSTR dir, component, full_path;
902 component = MSI_RecordGetString(row, 2);
904 return ERROR_SUCCESS;
906 comp = msi_get_loaded_component(package, component);
908 return ERROR_SUCCESS;
910 comp->Action = msi_get_component_action( package, comp );
911 if (comp->Action != INSTALLSTATE_ABSENT)
913 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
914 return ERROR_SUCCESS;
917 dir = MSI_RecordGetString( row, 1 );
920 ERR("Unable to get folder id\n");
921 return ERROR_SUCCESS;
924 full_path = msi_get_target_folder( package, dir );
927 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
928 return ERROR_SUCCESS;
930 TRACE("folder is %s\n", debugstr_w(full_path));
932 uirow = MSI_CreateRecord( 1 );
933 MSI_RecordSetStringW( uirow, 1, dir );
934 msi_ui_actiondata( package, szRemoveFolders, uirow );
935 msiobj_release( &uirow->hdr );
937 folder = msi_get_loaded_folder( package, dir );
938 remove_persistent_folder( folder );
939 return ERROR_SUCCESS;
942 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
944 static const WCHAR query[] = {
945 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
946 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
950 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
951 if (rc != ERROR_SUCCESS)
952 return ERROR_SUCCESS;
954 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
955 msiobj_release( &view->hdr );
959 static UINT load_component( MSIRECORD *row, LPVOID param )
961 MSIPACKAGE *package = param;
964 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
966 return ERROR_FUNCTION_FAILED;
968 list_add_tail( &package->components, &comp->entry );
970 /* fill in the data */
971 comp->Component = msi_dup_record_field( row, 1 );
973 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
975 comp->ComponentId = msi_dup_record_field( row, 2 );
976 comp->Directory = msi_dup_record_field( row, 3 );
977 comp->Attributes = MSI_RecordGetInteger(row,4);
978 comp->Condition = msi_dup_record_field( row, 5 );
979 comp->KeyPath = msi_dup_record_field( row, 6 );
981 comp->Installed = INSTALLSTATE_UNKNOWN;
982 comp->Action = INSTALLSTATE_UNKNOWN;
983 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
985 comp->assembly = msi_load_assembly( package, comp );
986 return ERROR_SUCCESS;
989 UINT msi_load_all_components( MSIPACKAGE *package )
991 static const WCHAR query[] = {
992 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
993 '`','C','o','m','p','o','n','e','n','t','`',0};
997 if (!list_empty(&package->components))
998 return ERROR_SUCCESS;
1000 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1001 if (r != ERROR_SUCCESS)
1004 if (!msi_init_assembly_caches( package ))
1006 ERR("can't initialize assembly caches\n");
1007 msiobj_release( &view->hdr );
1008 return ERROR_FUNCTION_FAILED;
1011 r = MSI_IterateRecords(view, NULL, load_component, package);
1012 msiobj_release(&view->hdr);
1017 MSIPACKAGE *package;
1018 MSIFEATURE *feature;
1021 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1025 cl = msi_alloc( sizeof (*cl) );
1027 return ERROR_NOT_ENOUGH_MEMORY;
1028 cl->component = comp;
1029 list_add_tail( &feature->Components, &cl->entry );
1031 return ERROR_SUCCESS;
1034 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1038 fl = msi_alloc( sizeof(*fl) );
1040 return ERROR_NOT_ENOUGH_MEMORY;
1041 fl->feature = child;
1042 list_add_tail( &parent->Children, &fl->entry );
1044 return ERROR_SUCCESS;
1047 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1049 _ilfs* ilfs = param;
1053 component = MSI_RecordGetString(row,1);
1055 /* check to see if the component is already loaded */
1056 comp = msi_get_loaded_component( ilfs->package, component );
1059 WARN("ignoring unknown component %s\n", debugstr_w(component));
1060 return ERROR_SUCCESS;
1062 add_feature_component( ilfs->feature, comp );
1063 comp->Enabled = TRUE;
1065 return ERROR_SUCCESS;
1068 static UINT load_feature(MSIRECORD * row, LPVOID param)
1070 static const WCHAR query[] = {
1071 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1072 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1073 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1074 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1075 MSIPACKAGE *package = param;
1076 MSIFEATURE *feature;
1081 /* fill in the data */
1083 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1085 return ERROR_NOT_ENOUGH_MEMORY;
1087 list_init( &feature->Children );
1088 list_init( &feature->Components );
1090 feature->Feature = msi_dup_record_field( row, 1 );
1092 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1094 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1095 feature->Title = msi_dup_record_field( row, 3 );
1096 feature->Description = msi_dup_record_field( row, 4 );
1098 if (!MSI_RecordIsNull(row,5))
1099 feature->Display = MSI_RecordGetInteger(row,5);
1101 feature->Level= MSI_RecordGetInteger(row,6);
1102 feature->Directory = msi_dup_record_field( row, 7 );
1103 feature->Attributes = MSI_RecordGetInteger(row,8);
1105 feature->Installed = INSTALLSTATE_UNKNOWN;
1106 feature->Action = INSTALLSTATE_UNKNOWN;
1107 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1109 list_add_tail( &package->features, &feature->entry );
1111 /* load feature components */
1113 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1114 if (rc != ERROR_SUCCESS)
1115 return ERROR_SUCCESS;
1117 ilfs.package = package;
1118 ilfs.feature = feature;
1120 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1121 msiobj_release(&view->hdr);
1125 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1127 MSIPACKAGE *package = param;
1128 MSIFEATURE *parent, *child;
1130 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1132 return ERROR_FUNCTION_FAILED;
1134 if (!child->Feature_Parent)
1135 return ERROR_SUCCESS;
1137 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1139 return ERROR_FUNCTION_FAILED;
1141 add_feature_child( parent, child );
1142 return ERROR_SUCCESS;
1145 UINT msi_load_all_features( MSIPACKAGE *package )
1147 static const WCHAR query[] = {
1148 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1149 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1150 '`','D','i','s','p','l','a','y','`',0};
1154 if (!list_empty(&package->features))
1155 return ERROR_SUCCESS;
1157 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1158 if (r != ERROR_SUCCESS)
1161 r = MSI_IterateRecords( view, NULL, load_feature, package );
1162 if (r != ERROR_SUCCESS)
1164 msiobj_release( &view->hdr );
1167 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1168 msiobj_release( &view->hdr );
1172 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1183 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1185 static const WCHAR query[] = {
1186 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1187 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1188 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1189 MSIQUERY *view = NULL;
1190 MSIRECORD *row = NULL;
1193 TRACE("%s\n", debugstr_w(file->File));
1195 r = MSI_OpenQuery(package->db, &view, query, file->File);
1196 if (r != ERROR_SUCCESS)
1199 r = MSI_ViewExecute(view, NULL);
1200 if (r != ERROR_SUCCESS)
1203 r = MSI_ViewFetch(view, &row);
1204 if (r != ERROR_SUCCESS)
1207 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1208 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1209 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1210 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1211 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1214 if (view) msiobj_release(&view->hdr);
1215 if (row) msiobj_release(&row->hdr);
1219 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1222 static const WCHAR query[] = {
1223 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1224 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1225 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1227 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1230 WARN("query failed\n");
1231 return ERROR_FUNCTION_FAILED;
1234 file->disk_id = MSI_RecordGetInteger( row, 1 );
1235 msiobj_release( &row->hdr );
1236 return ERROR_SUCCESS;
1239 static UINT load_file(MSIRECORD *row, LPVOID param)
1241 MSIPACKAGE* package = param;
1245 /* fill in the data */
1247 file = msi_alloc_zero( sizeof (MSIFILE) );
1249 return ERROR_NOT_ENOUGH_MEMORY;
1251 file->File = msi_dup_record_field( row, 1 );
1253 component = MSI_RecordGetString( row, 2 );
1254 file->Component = msi_get_loaded_component( package, component );
1256 if (!file->Component)
1258 WARN("Component not found: %s\n", debugstr_w(component));
1259 msi_free(file->File);
1261 return ERROR_SUCCESS;
1264 file->FileName = msi_dup_record_field( row, 3 );
1265 msi_reduce_to_long_filename( file->FileName );
1267 file->ShortName = msi_dup_record_field( row, 3 );
1268 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1270 file->FileSize = MSI_RecordGetInteger( row, 4 );
1271 file->Version = msi_dup_record_field( row, 5 );
1272 file->Language = msi_dup_record_field( row, 6 );
1273 file->Attributes = MSI_RecordGetInteger( row, 7 );
1274 file->Sequence = MSI_RecordGetInteger( row, 8 );
1276 file->state = msifs_invalid;
1278 /* if the compressed bits are not set in the file attributes,
1279 * then read the information from the package word count property
1281 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1283 file->IsCompressed = FALSE;
1285 else if (file->Attributes &
1286 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1288 file->IsCompressed = TRUE;
1290 else if (file->Attributes & msidbFileAttributesNoncompressed)
1292 file->IsCompressed = FALSE;
1296 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1299 load_file_hash(package, file);
1300 load_file_disk_id(package, file);
1302 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1304 list_add_tail( &package->files, &file->entry );
1306 return ERROR_SUCCESS;
1309 static UINT load_all_files(MSIPACKAGE *package)
1311 static const WCHAR query[] = {
1312 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1313 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1314 '`','S','e','q','u','e','n','c','e','`', 0};
1318 if (!list_empty(&package->files))
1319 return ERROR_SUCCESS;
1321 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1322 if (rc != ERROR_SUCCESS)
1323 return ERROR_SUCCESS;
1325 rc = MSI_IterateRecords(view, NULL, load_file, package);
1326 msiobj_release(&view->hdr);
1330 static UINT load_media( MSIRECORD *row, LPVOID param )
1332 MSIPACKAGE *package = param;
1333 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1334 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1336 /* FIXME: load external cabinets and directory sources too */
1337 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1338 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1339 return ERROR_SUCCESS;
1342 static UINT load_all_media( MSIPACKAGE *package )
1344 static const WCHAR query[] = {
1345 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1346 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1347 '`','D','i','s','k','I','d','`',0};
1351 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1352 if (r != ERROR_SUCCESS)
1353 return ERROR_SUCCESS;
1355 r = MSI_IterateRecords( view, NULL, load_media, package );
1356 msiobj_release( &view->hdr );
1360 static UINT load_patch(MSIRECORD *row, LPVOID param)
1362 MSIPACKAGE *package = param;
1363 MSIFILEPATCH *patch;
1366 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1368 return ERROR_NOT_ENOUGH_MEMORY;
1370 file_key = msi_dup_record_field( row, 1 );
1371 patch->File = msi_get_loaded_file( package, file_key );
1376 ERR("Failed to find target for patch in File table\n");
1378 return ERROR_FUNCTION_FAILED;
1381 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1383 /* FIXME: The database should be properly transformed */
1384 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1386 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1387 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1388 patch->IsApplied = FALSE;
1391 * Header field - for patch validation.
1392 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1395 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1397 list_add_tail( &package->filepatches, &patch->entry );
1399 return ERROR_SUCCESS;
1402 static UINT load_all_patches(MSIPACKAGE *package)
1404 static const WCHAR query[] = {
1405 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1406 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1407 '`','S','e','q','u','e','n','c','e','`',0};
1411 if (!list_empty(&package->filepatches))
1412 return ERROR_SUCCESS;
1414 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1415 if (rc != ERROR_SUCCESS)
1416 return ERROR_SUCCESS;
1418 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1419 msiobj_release(&view->hdr);
1423 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1425 static const WCHAR query[] = {
1426 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1427 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1428 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1431 folder->persistent = FALSE;
1432 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1434 if (!MSI_ViewExecute( view, NULL ))
1437 if (!MSI_ViewFetch( view, &rec ))
1439 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1440 folder->persistent = TRUE;
1441 msiobj_release( &rec->hdr );
1444 msiobj_release( &view->hdr );
1446 return ERROR_SUCCESS;
1449 static UINT load_folder( MSIRECORD *row, LPVOID param )
1451 MSIPACKAGE *package = param;
1452 static WCHAR szEmpty[] = { 0 };
1453 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1456 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1457 list_init( &folder->children );
1458 folder->Directory = msi_dup_record_field( row, 1 );
1459 folder->Parent = msi_dup_record_field( row, 2 );
1460 p = msi_dup_record_field(row, 3);
1462 TRACE("%s\n", debugstr_w(folder->Directory));
1464 /* split src and target dir */
1466 src_short = folder_split_path( p, ':' );
1468 /* split the long and short paths */
1469 tgt_long = folder_split_path( tgt_short, '|' );
1470 src_long = folder_split_path( src_short, '|' );
1472 /* check for no-op dirs */
1473 if (tgt_short && !strcmpW( szDot, tgt_short ))
1474 tgt_short = szEmpty;
1475 if (src_short && !strcmpW( szDot, src_short ))
1476 src_short = szEmpty;
1479 tgt_long = tgt_short;
1482 src_short = tgt_short;
1483 src_long = tgt_long;
1487 src_long = src_short;
1489 /* FIXME: use the target short path too */
1490 folder->TargetDefault = strdupW(tgt_long);
1491 folder->SourceShortPath = strdupW(src_short);
1492 folder->SourceLongPath = strdupW(src_long);
1495 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1496 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1497 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1499 load_folder_persistence( package, folder );
1501 list_add_tail( &package->folders, &folder->entry );
1502 return ERROR_SUCCESS;
1505 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1509 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1511 list_add_tail( &parent->children, &fl->entry );
1512 return ERROR_SUCCESS;
1515 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1517 MSIPACKAGE *package = param;
1518 MSIFOLDER *parent, *child;
1520 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1521 return ERROR_FUNCTION_FAILED;
1523 if (!child->Parent) return ERROR_SUCCESS;
1525 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1526 return ERROR_FUNCTION_FAILED;
1528 return add_folder_child( parent, child );
1531 static UINT load_all_folders( MSIPACKAGE *package )
1533 static const WCHAR query[] = {
1534 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1535 '`','D','i','r','e','c','t','o','r','y','`',0};
1539 if (!list_empty(&package->folders))
1540 return ERROR_SUCCESS;
1542 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1543 if (r != ERROR_SUCCESS)
1546 r = MSI_IterateRecords( view, NULL, load_folder, package );
1547 if (r != ERROR_SUCCESS)
1549 msiobj_release( &view->hdr );
1552 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1553 msiobj_release( &view->hdr );
1557 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1559 msi_set_property( package->db, szCostingComplete, szZero, -1 );
1560 msi_set_property( package->db, szRootDrive, szCRoot, -1 );
1562 load_all_folders( package );
1563 msi_load_all_components( package );
1564 msi_load_all_features( package );
1565 load_all_files( package );
1566 load_all_patches( package );
1567 load_all_media( package );
1569 return ERROR_SUCCESS;
1572 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1574 const WCHAR *action = package->script->Actions[script][index];
1575 ui_actionstart( package, action );
1576 TRACE("executing %s\n", debugstr_w(action));
1577 return ACTION_PerformAction( package, action, script );
1580 static UINT execute_script( MSIPACKAGE *package, UINT script )
1582 UINT i, rc = ERROR_SUCCESS;
1584 TRACE("executing script %u\n", script);
1586 if (!package->script)
1588 ERR("no script!\n");
1589 return ERROR_FUNCTION_FAILED;
1591 if (script == SCRIPT_ROLLBACK)
1593 for (i = package->script->ActionCount[script]; i > 0; i--)
1595 rc = execute_script_action( package, script, i - 1 );
1596 if (rc != ERROR_SUCCESS) break;
1601 for (i = 0; i < package->script->ActionCount[script]; i++)
1603 rc = execute_script_action( package, script, i );
1604 if (rc != ERROR_SUCCESS) break;
1607 msi_free_action_script(package, script);
1611 static UINT ACTION_FileCost(MSIPACKAGE *package)
1613 return ERROR_SUCCESS;
1616 static void get_client_counts( MSIPACKAGE *package )
1621 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1623 if (!comp->ComponentId) continue;
1625 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE ) &&
1626 MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ))
1628 comp->num_clients = 0;
1631 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
1632 NULL, NULL, NULL, NULL );
1633 RegCloseKey( hkey );
1637 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1642 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1644 if (!comp->ComponentId) continue;
1646 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1647 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1649 if (r == ERROR_SUCCESS) continue;
1651 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1652 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1654 if (r == ERROR_SUCCESS) continue;
1656 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1657 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1659 if (r == ERROR_SUCCESS) continue;
1661 comp->Installed = INSTALLSTATE_ABSENT;
1665 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1667 MSIFEATURE *feature;
1669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1671 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1673 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1674 feature->Installed = INSTALLSTATE_ABSENT;
1676 feature->Installed = state;
1680 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1682 return (feature->Level > 0 && feature->Level <= level);
1685 static BOOL process_state_property(MSIPACKAGE* package, int level,
1686 LPCWSTR property, INSTALLSTATE state)
1689 MSIFEATURE *feature;
1691 override = msi_dup_property( package->db, property );
1695 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1697 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1700 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1702 if (!strcmpiW( override, szAll ))
1704 if (feature->Installed != state)
1706 feature->Action = state;
1707 feature->ActionRequest = state;
1712 LPWSTR ptr = override;
1713 LPWSTR ptr2 = strchrW(override,',');
1717 int len = ptr2 - ptr;
1719 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1720 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1722 if (feature->Installed != state)
1724 feature->Action = state;
1725 feature->ActionRequest = state;
1732 ptr2 = strchrW(ptr,',');
1743 static BOOL process_overrides( MSIPACKAGE *package, int level )
1745 static const WCHAR szAddLocal[] =
1746 {'A','D','D','L','O','C','A','L',0};
1747 static const WCHAR szAddSource[] =
1748 {'A','D','D','S','O','U','R','C','E',0};
1749 static const WCHAR szAdvertise[] =
1750 {'A','D','V','E','R','T','I','S','E',0};
1753 /* all these activation/deactivation things happen in order and things
1754 * later on the list override things earlier on the list.
1756 * 0 INSTALLLEVEL processing
1769 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1770 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1771 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1772 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1773 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1775 if (ret && !package->full_reinstall)
1776 msi_set_property( package->db, szPreselected, szOne, -1 );
1781 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1784 MSICOMPONENT* component;
1785 MSIFEATURE *feature;
1787 TRACE("Checking Install Level\n");
1789 level = msi_get_property_int(package->db, szInstallLevel, 1);
1791 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1793 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1795 if (!is_feature_selected( feature, level )) continue;
1797 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1799 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1801 feature->Action = INSTALLSTATE_SOURCE;
1802 feature->ActionRequest = INSTALLSTATE_SOURCE;
1804 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1806 feature->Action = INSTALLSTATE_ADVERTISED;
1807 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1811 feature->Action = INSTALLSTATE_LOCAL;
1812 feature->ActionRequest = INSTALLSTATE_LOCAL;
1816 /* disable child features of unselected parent or follow parent */
1817 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1821 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1823 if (!is_feature_selected( feature, level ))
1825 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1826 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1828 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1830 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1831 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1832 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1833 fl->feature->Action = feature->Action;
1834 fl->feature->ActionRequest = feature->ActionRequest;
1839 else /* preselected */
1841 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1843 if (!is_feature_selected( feature, level )) continue;
1845 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1847 if (feature->Installed == INSTALLSTATE_ABSENT)
1849 feature->Action = INSTALLSTATE_UNKNOWN;
1850 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1854 feature->Action = feature->Installed;
1855 feature->ActionRequest = feature->Installed;
1859 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1863 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1865 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1866 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1868 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1869 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1870 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1871 fl->feature->Action = feature->Action;
1872 fl->feature->ActionRequest = feature->ActionRequest;
1878 /* now we want to set component state based based on feature state */
1879 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1883 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1884 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1885 feature->ActionRequest, feature->Action);
1887 if (!is_feature_selected( feature, level )) continue;
1889 /* features with components that have compressed files are made local */
1890 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1892 if (cl->component->ForceLocalState &&
1893 feature->ActionRequest == INSTALLSTATE_SOURCE)
1895 feature->Action = INSTALLSTATE_LOCAL;
1896 feature->ActionRequest = INSTALLSTATE_LOCAL;
1901 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1903 component = cl->component;
1905 switch (feature->ActionRequest)
1907 case INSTALLSTATE_ABSENT:
1908 component->anyAbsent = 1;
1910 case INSTALLSTATE_ADVERTISED:
1911 component->hasAdvertiseFeature = 1;
1913 case INSTALLSTATE_SOURCE:
1914 component->hasSourceFeature = 1;
1916 case INSTALLSTATE_LOCAL:
1917 component->hasLocalFeature = 1;
1919 case INSTALLSTATE_DEFAULT:
1920 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1921 component->hasAdvertiseFeature = 1;
1922 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1923 component->hasSourceFeature = 1;
1925 component->hasLocalFeature = 1;
1933 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1935 /* check if it's local or source */
1936 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1937 (component->hasLocalFeature || component->hasSourceFeature))
1939 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1940 !component->ForceLocalState)
1942 component->Action = INSTALLSTATE_SOURCE;
1943 component->ActionRequest = INSTALLSTATE_SOURCE;
1947 component->Action = INSTALLSTATE_LOCAL;
1948 component->ActionRequest = INSTALLSTATE_LOCAL;
1953 /* if any feature is local, the component must be local too */
1954 if (component->hasLocalFeature)
1956 component->Action = INSTALLSTATE_LOCAL;
1957 component->ActionRequest = INSTALLSTATE_LOCAL;
1960 if (component->hasSourceFeature)
1962 component->Action = INSTALLSTATE_SOURCE;
1963 component->ActionRequest = INSTALLSTATE_SOURCE;
1966 if (component->hasAdvertiseFeature)
1968 component->Action = INSTALLSTATE_ADVERTISED;
1969 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1972 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1973 if (component->anyAbsent && component->ComponentId)
1975 component->Action = INSTALLSTATE_ABSENT;
1976 component->ActionRequest = INSTALLSTATE_ABSENT;
1980 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1982 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1984 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1985 component->Action = INSTALLSTATE_LOCAL;
1986 component->ActionRequest = INSTALLSTATE_LOCAL;
1989 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1990 component->Installed == INSTALLSTATE_SOURCE &&
1991 component->hasSourceFeature)
1993 component->Action = INSTALLSTATE_UNKNOWN;
1994 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1997 TRACE("component %s (installed %d request %d action %d)\n",
1998 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2000 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
2001 component->num_clients++;
2002 else if (component->Action == INSTALLSTATE_ABSENT)
2003 component->num_clients--;
2006 return ERROR_SUCCESS;
2009 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2011 MSIPACKAGE *package = param;
2013 MSIFEATURE *feature;
2015 name = MSI_RecordGetString( row, 1 );
2017 feature = msi_get_loaded_feature( package, name );
2019 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2023 Condition = MSI_RecordGetString(row,3);
2025 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2027 int level = MSI_RecordGetInteger(row,2);
2028 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2029 feature->Level = level;
2032 return ERROR_SUCCESS;
2035 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2037 static const WCHAR name[] = {'\\',0};
2038 VS_FIXEDFILEINFO *ptr, *ret;
2040 DWORD versize, handle;
2043 versize = GetFileVersionInfoSizeW( filename, &handle );
2047 version = msi_alloc( versize );
2051 GetFileVersionInfoW( filename, 0, versize, version );
2053 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2055 msi_free( version );
2059 ret = msi_alloc( sz );
2060 memcpy( ret, ptr, sz );
2062 msi_free( version );
2066 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2070 msi_parse_version_string( version, &ms, &ls );
2072 if (fi->dwFileVersionMS > ms) return 1;
2073 else if (fi->dwFileVersionMS < ms) return -1;
2074 else if (fi->dwFileVersionLS > ls) return 1;
2075 else if (fi->dwFileVersionLS < ls) return -1;
2079 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2083 msi_parse_version_string( ver1, &ms1, NULL );
2084 msi_parse_version_string( ver2, &ms2, NULL );
2086 if (ms1 > ms2) return 1;
2087 else if (ms1 < ms2) return -1;
2091 DWORD msi_get_disk_file_size( LPCWSTR filename )
2096 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2097 if (file == INVALID_HANDLE_VALUE)
2098 return INVALID_FILE_SIZE;
2100 size = GetFileSize( file, NULL );
2101 TRACE("size is %u\n", size);
2102 CloseHandle( file );
2106 BOOL msi_file_hash_matches( MSIFILE *file )
2109 MSIFILEHASHINFO hash;
2111 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2112 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2113 if (r != ERROR_SUCCESS)
2116 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2119 static WCHAR *get_temp_dir( void )
2122 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2124 GetTempPathW( MAX_PATH, tmp );
2127 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2128 if (CreateDirectoryW( dir, NULL )) break;
2130 return strdupW( dir );
2134 * msi_build_directory_name()
2136 * This function is to save messing round with directory names
2137 * It handles adding backslashes between path segments,
2138 * and can add \ at the end of the directory name if told to.
2140 * It takes a variable number of arguments.
2141 * It always allocates a new string for the result, so make sure
2142 * to free the return value when finished with it.
2144 * The first arg is the number of path segments that follow.
2145 * The arguments following count are a list of path segments.
2146 * A path segment may be NULL.
2148 * Path segments will be added with a \ separating them.
2149 * A \ will not be added after the last segment, however if the
2150 * last segment is NULL, then the last character will be a \
2152 WCHAR *msi_build_directory_name( DWORD count, ... )
2158 va_start( va, count );
2159 for (i = 0; i < count; i++)
2161 const WCHAR *str = va_arg( va, const WCHAR * );
2162 if (str) sz += strlenW( str ) + 1;
2166 dir = msi_alloc( sz * sizeof(WCHAR) );
2169 va_start( va, count );
2170 for (i = 0; i < count; i++)
2172 const WCHAR *str = va_arg( va, const WCHAR * );
2174 strcatW( dir, str );
2175 if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2181 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2183 MSIASSEMBLY *assembly = file->Component->assembly;
2185 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2187 msi_free( file->TargetPath );
2188 if (assembly && !assembly->application)
2190 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2191 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2192 msi_track_tempfile( package, file->TargetPath );
2196 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2197 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2200 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2203 static UINT calculate_file_cost( MSIPACKAGE *package )
2205 VS_FIXEDFILEINFO *file_version;
2206 WCHAR *font_version;
2209 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2211 MSICOMPONENT *comp = file->Component;
2214 if (!comp->Enabled) continue;
2216 if (file->IsCompressed)
2217 comp->ForceLocalState = TRUE;
2219 set_target_path( package, file );
2221 if ((comp->assembly && !comp->assembly->installed) ||
2222 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2224 comp->Cost += file->FileSize;
2227 file_size = msi_get_disk_file_size( file->TargetPath );
2231 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2233 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2235 comp->Cost += file->FileSize - file_size;
2237 msi_free( file_version );
2240 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2242 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2244 comp->Cost += file->FileSize - file_size;
2246 msi_free( font_version );
2250 if (file_size != file->FileSize)
2252 comp->Cost += file->FileSize - file_size;
2255 return ERROR_SUCCESS;
2258 WCHAR *msi_normalize_path( const WCHAR *in )
2260 const WCHAR *p = in;
2262 int n, len = strlenW( in ) + 2;
2264 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2269 /* copy until the end of the string or a space */
2270 while (*p != ' ' && (*q = *p))
2273 /* reduce many backslashes to one */
2274 if (*p != '\\' || *q != '\\')
2278 /* quit at the end of the string */
2282 /* count the number of spaces */
2287 /* if it's leading or trailing space, skip it */
2288 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2290 else /* copy n spaces */
2291 while (n && (*q++ = *p++)) n--;
2293 while (q - ret > 0 && q[-1] == ' ') q--;
2294 if (q - ret > 0 && q[-1] != '\\')
2302 static WCHAR *get_install_location( MSIPACKAGE *package )
2307 if (!package->ProductCode) return NULL;
2308 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ))
2310 path = msi_reg_get_val_str( hkey, szInstallLocation );
2311 RegCloseKey( hkey );
2315 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2318 MSIFOLDER *folder, *parent, *child;
2319 WCHAR *path, *normalized_path;
2321 TRACE("resolving %s\n", debugstr_w(name));
2323 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2325 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2327 if (!(path = get_install_location( package )) &&
2328 (!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))))
2330 path = msi_dup_property( package->db, szRootDrive );
2333 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2335 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2337 parent = msi_get_loaded_folder( package, folder->Parent );
2338 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2341 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2343 normalized_path = msi_normalize_path( path );
2345 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2347 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2348 msi_free( normalized_path );
2351 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2352 msi_free( folder->ResolvedTarget );
2353 folder->ResolvedTarget = normalized_path;
2355 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2358 msi_resolve_target_folder( package, child->Directory, load_prop );
2360 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2363 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2365 static const WCHAR query[] = {
2366 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2367 '`','C','o','n','d','i','t','i','o','n','`',0};
2368 static const WCHAR szOutOfDiskSpace[] = {
2369 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2375 TRACE("Building directory properties\n");
2376 msi_resolve_target_folder( package, szTargetDir, TRUE );
2378 TRACE("Evaluating component conditions\n");
2379 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2381 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2383 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2384 comp->Enabled = FALSE;
2387 comp->Enabled = TRUE;
2389 get_client_counts( package );
2391 /* read components states from the registry */
2392 ACTION_GetComponentInstallStates(package);
2393 ACTION_GetFeatureInstallStates(package);
2395 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2397 TRACE("Evaluating feature conditions\n");
2399 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2400 if (rc == ERROR_SUCCESS)
2402 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2403 msiobj_release( &view->hdr );
2404 if (rc != ERROR_SUCCESS)
2409 TRACE("Calculating file cost\n");
2410 calculate_file_cost( package );
2412 msi_set_property( package->db, szCostingComplete, szOne, -1 );
2413 /* set default run level if not set */
2414 level = msi_dup_property( package->db, szInstallLevel );
2416 msi_set_property( package->db, szInstallLevel, szOne, -1 );
2419 /* FIXME: check volume disk space */
2420 msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
2422 return MSI_SetFeatureStates(package);
2425 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type, DWORD *size )
2431 *size = sizeof(WCHAR);
2433 if ((data = msi_alloc( *size ))) *(WCHAR *)data = 0;
2436 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2442 LPWSTR deformated = NULL;
2445 deformat_string(package, &value[2], &deformated);
2447 /* binary value type */
2451 *size = (strlenW(ptr)/2)+1;
2453 *size = strlenW(ptr)/2;
2455 data = msi_alloc(*size);
2461 /* if uneven pad with a zero in front */
2467 data[count] = (BYTE)strtol(byte,NULL,0);
2469 TRACE("Uneven byte count\n");
2477 data[count] = (BYTE)strtol(byte,NULL,0);
2480 msi_free(deformated);
2482 TRACE("Data %i bytes(%i)\n",*size,count);
2489 deformat_string(package, &value[1], &deformated);
2492 *size = sizeof(DWORD);
2493 data = msi_alloc(*size);
2499 if ( (*p < '0') || (*p > '9') )
2505 if (deformated[0] == '-')
2508 TRACE("DWORD %i\n",*(LPDWORD)data);
2510 msi_free(deformated);
2515 const WCHAR *ptr = value;
2519 if (value[0] == '#')
2522 if (value[1] == '%')
2525 *type = REG_EXPAND_SZ;
2528 len = deformat_string( package, ptr, (WCHAR **)&data );
2529 if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
2530 *size = (len + 1) * sizeof(WCHAR);
2535 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2542 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2544 *root_key = HKEY_LOCAL_MACHINE;
2549 *root_key = HKEY_CURRENT_USER;
2554 *root_key = HKEY_CLASSES_ROOT;
2558 *root_key = HKEY_CURRENT_USER;
2562 *root_key = HKEY_LOCAL_MACHINE;
2566 *root_key = HKEY_USERS;
2570 ERR("Unknown root %i\n", root);
2577 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2579 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2580 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2582 if ((is_64bit || is_wow64) &&
2583 !(comp->Attributes & msidbComponentAttributes64bit) &&
2584 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2589 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2590 if (!(path_32node = msi_alloc( size ))) return NULL;
2592 memcpy( path_32node, path, len * sizeof(WCHAR) );
2593 strcpyW( path_32node + len, szWow6432Node );
2594 strcatW( path_32node, szBackSlash );
2595 strcatW( path_32node, path + len );
2598 return strdupW( path );
2601 static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
2603 REGSAM access = KEY_ALL_ACCESS;
2604 WCHAR *subkey, *p, *q;
2605 HKEY hkey, ret = NULL;
2608 if (is_wow64) access |= KEY_WOW64_64KEY;
2610 if (!(subkey = strdupW( path ))) return NULL;
2612 if ((q = strchrW( p, '\\' ))) *q = 0;
2614 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2616 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2619 TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
2625 ret = open_key( hkey, q + 1, create );
2626 RegCloseKey( hkey );
2633 static BOOL is_special_entry( const WCHAR *name )
2635 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2638 static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count )
2640 const WCHAR *p = str;
2645 if (!str) return NULL;
2646 while ((p - str) < len)
2648 p += strlenW( p ) + 1;
2651 if (!(ret = msi_alloc( *count * sizeof(WCHAR *) ))) return NULL;
2653 while ((p - str) < len)
2655 if (!(ret[i] = strdupW( p )))
2657 for (; i >= 0; i--) msi_free( ret[i] );
2661 p += strlenW( p ) + 1;
2667 static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count,
2668 WCHAR **right, DWORD right_count, DWORD *size )
2673 *size = sizeof(WCHAR);
2674 for (i = 0; i < left_count; i++) *size += (strlenW( left[i] ) + 1) * sizeof(WCHAR);
2675 for (i = 0; i < right_count; i++) *size += (strlenW( right[i] ) + 1) * sizeof(WCHAR);
2677 if (!(ret = p = msi_alloc( *size ))) return NULL;
2679 for (i = 0; i < left_count; i++)
2681 strcpyW( p, left[i] );
2682 p += strlenW( p ) + 1;
2684 for (i = 0; i < right_count; i++)
2686 strcpyW( p, right[i] );
2687 p += strlenW( p ) + 1;
2693 static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
2694 WCHAR **new, DWORD new_count )
2696 DWORD ret = old_count;
2697 unsigned int i, j, k;
2699 for (i = 0; i < new_count; i++)
2701 for (j = 0; j < old_count; j++)
2703 if (old[j] && !strcmpW( new[i], old[j] ))
2706 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
2722 static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
2723 WCHAR **new, DWORD new_count, DWORD *size )
2727 case JOIN_OP_APPEND:
2728 old_count = remove_duplicate_values( old, old_count, new, new_count );
2729 return flatten_multi_string_values( old, old_count, new, new_count, size );
2731 case JOIN_OP_PREPEND:
2732 old_count = remove_duplicate_values( old, old_count, new, new_count );
2733 return flatten_multi_string_values( new, new_count, old, old_count, size );
2735 case JOIN_OP_REPLACE:
2736 return flatten_multi_string_values( new, new_count, NULL, 0, size );
2739 ERR("unhandled join op %u\n", op);
2744 static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size,
2745 BYTE *new_value, DWORD new_size, DWORD *size )
2747 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
2748 const WCHAR *new_ptr = NULL, *old_ptr = NULL;
2749 enum join_op op = JOIN_OP_REPLACE;
2750 WCHAR **old = NULL, **new = NULL;
2753 if (new_size / sizeof(WCHAR) - 1 > 1)
2755 new_ptr = (const WCHAR *)new_value;
2756 new_len = new_size / sizeof(WCHAR) - 1;
2758 if (!new_ptr[0] && new_ptr[new_len - 1])
2760 op = JOIN_OP_APPEND;
2764 else if (new_ptr[0] && !new_ptr[new_len - 1])
2766 op = JOIN_OP_PREPEND;
2769 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2771 op = JOIN_OP_REPLACE;
2775 new = split_multi_string_values( new_ptr, new_len, &new_count );
2777 if (old_size / sizeof(WCHAR) - 1 > 1)
2779 old_ptr = (const WCHAR *)old_value;
2780 old_len = old_size / sizeof(WCHAR) - 1;
2781 old = split_multi_string_values( old_ptr, old_len, &old_count );
2783 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
2784 for (i = 0; i < old_count; i++) msi_free( old[i] );
2785 for (i = 0; i < new_count; i++) msi_free( new[i] );
2791 static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
2794 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
2795 if (!(ret = msi_alloc( *size ))) return NULL;
2796 RegQueryValueExW( hkey, name, NULL, type, ret, size );
2800 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2802 MSIPACKAGE *package = param;
2803 BYTE *new_value, *old_value = NULL;
2804 HKEY root_key, hkey;
2805 DWORD type, old_type, new_size, old_size = 0;
2806 LPWSTR deformated, uikey, keypath;
2807 const WCHAR *szRoot, *component, *name, *key, *str;
2811 BOOL check_first = FALSE;
2814 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2816 component = MSI_RecordGetString(row, 6);
2817 comp = msi_get_loaded_component(package,component);
2819 return ERROR_SUCCESS;
2821 comp->Action = msi_get_component_action( package, comp );
2822 if (comp->Action != INSTALLSTATE_LOCAL)
2824 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2825 return ERROR_SUCCESS;
2828 name = MSI_RecordGetString(row, 4);
2829 if( MSI_RecordIsNull(row,5) && name )
2831 /* null values can have special meanings */
2832 if (name[0]=='-' && name[1] == 0)
2833 return ERROR_SUCCESS;
2834 if ((name[0] == '+' || name[0] == '*') && !name[1])
2838 root = MSI_RecordGetInteger(row,2);
2839 key = MSI_RecordGetString(row, 3);
2841 szRoot = get_root_key( package, root, &root_key );
2843 return ERROR_SUCCESS;
2845 deformat_string(package, key , &deformated);
2846 uikey = msi_alloc( (strlenW(deformated) + strlenW(szRoot) + 1) * sizeof(WCHAR) );
2847 strcpyW(uikey,szRoot);
2848 strcatW(uikey,deformated);
2850 keypath = get_keypath( comp, root_key, deformated );
2851 msi_free( deformated );
2852 if (!(hkey = open_key( root_key, keypath, TRUE )))
2854 ERR("Could not create key %s\n", debugstr_w(keypath));
2857 return ERROR_FUNCTION_FAILED;
2859 str = msi_record_get_string( row, 5, &len );
2860 if (str && len > strlenW( str ))
2862 type = REG_MULTI_SZ;
2863 new_size = (len + 1) * sizeof(WCHAR);
2864 new_value = (BYTE *)msi_strdupW( str, len );
2866 else new_value = parse_value( package, str, &type, &new_size );
2867 deformat_string(package, name, &deformated);
2869 if (!is_special_entry( name ))
2871 old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
2872 if (type == REG_MULTI_SZ)
2875 if (old_value && old_type != REG_MULTI_SZ)
2877 msi_free( old_value );
2881 new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size );
2882 msi_free( new_value );
2887 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2888 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2890 else if (!old_value)
2892 if (deformated || new_size)
2894 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2895 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2898 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
2902 uirow = MSI_CreateRecord(3);
2903 MSI_RecordSetStringW(uirow,2,deformated);
2904 MSI_RecordSetStringW(uirow,1,uikey);
2905 if (type == REG_SZ || type == REG_EXPAND_SZ)
2906 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
2907 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2908 msiobj_release( &uirow->hdr );
2910 msi_free(new_value);
2911 msi_free(old_value);
2912 msi_free(deformated);
2916 return ERROR_SUCCESS;
2919 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2921 static const WCHAR query[] = {
2922 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2923 '`','R','e','g','i','s','t','r','y','`',0};
2927 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2928 if (rc != ERROR_SUCCESS)
2929 return ERROR_SUCCESS;
2931 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2932 msiobj_release(&view->hdr);
2936 static void delete_key( HKEY root, const WCHAR *path )
2943 if (is_wow64) access |= KEY_WOW64_64KEY;
2945 if (!(subkey = strdupW( path ))) return;
2948 if ((p = strrchrW( subkey, '\\' ))) *p = 0;
2949 hkey = open_key( root, subkey, FALSE );
2952 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2954 res = RegDeleteKeyExW( root, subkey, access, 0 );
2957 TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
2960 if (p && p[1]) RegCloseKey( hkey );
2966 static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
2970 DWORD num_subkeys, num_values;
2972 if ((hkey = open_key( root, path, FALSE )))
2974 if ((res = RegDeleteValueW( hkey, value )))
2975 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2977 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2978 NULL, NULL, NULL, NULL );
2979 RegCloseKey( hkey );
2980 if (!res && !num_subkeys && !num_values)
2982 TRACE("removing empty key %s\n", debugstr_w(path));
2983 delete_key( root, path );
2988 static void delete_tree( HKEY root, const WCHAR *path )
2993 if (!(hkey = open_key( root, path, FALSE ))) return;
2994 res = RegDeleteTreeW( hkey, NULL );
2995 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
2996 delete_key( root, path );
2997 RegCloseKey( hkey );
3000 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
3002 MSIPACKAGE *package = param;
3003 LPCWSTR component, name, key_str, root_key_str;
3004 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3007 BOOL delete_key = FALSE;
3012 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
3014 component = MSI_RecordGetString( row, 6 );
3015 comp = msi_get_loaded_component( package, component );
3017 return ERROR_SUCCESS;
3019 comp->Action = msi_get_component_action( package, comp );
3020 if (comp->Action != INSTALLSTATE_ABSENT)
3022 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3023 return ERROR_SUCCESS;
3026 name = MSI_RecordGetString( row, 4 );
3027 if (MSI_RecordIsNull( row, 5 ) && name )
3029 if (name[0] == '+' && !name[1])
3030 return ERROR_SUCCESS;
3031 if ((name[0] == '-' || name[0] == '*') && !name[1])
3038 root = MSI_RecordGetInteger( row, 2 );
3039 key_str = MSI_RecordGetString( row, 3 );
3041 root_key_str = get_root_key( package, root, &hkey_root );
3043 return ERROR_SUCCESS;
3045 deformat_string( package, key_str, &deformated_key );
3046 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3047 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3048 strcpyW( ui_key_str, root_key_str );
3049 strcatW( ui_key_str, deformated_key );
3051 deformat_string( package, name, &deformated_name );
3053 keypath = get_keypath( comp, hkey_root, deformated_key );
3054 msi_free( deformated_key );
3055 if (delete_key) delete_tree( hkey_root, keypath );
3056 else delete_value( hkey_root, keypath, deformated_name );
3057 msi_free( keypath );
3059 uirow = MSI_CreateRecord( 2 );
3060 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3061 MSI_RecordSetStringW( uirow, 2, deformated_name );
3062 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3063 msiobj_release( &uirow->hdr );
3065 msi_free( ui_key_str );
3066 msi_free( deformated_name );
3067 return ERROR_SUCCESS;
3070 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
3072 MSIPACKAGE *package = param;
3073 LPCWSTR component, name, key_str, root_key_str;
3074 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3077 BOOL delete_key = FALSE;
3082 component = MSI_RecordGetString( row, 5 );
3083 comp = msi_get_loaded_component( package, component );
3085 return ERROR_SUCCESS;
3087 comp->Action = msi_get_component_action( package, comp );
3088 if (comp->Action != INSTALLSTATE_LOCAL)
3090 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3091 return ERROR_SUCCESS;
3094 if ((name = MSI_RecordGetString( row, 4 )))
3096 if (name[0] == '-' && !name[1])
3103 root = MSI_RecordGetInteger( row, 2 );
3104 key_str = MSI_RecordGetString( row, 3 );
3106 root_key_str = get_root_key( package, root, &hkey_root );
3108 return ERROR_SUCCESS;
3110 deformat_string( package, key_str, &deformated_key );
3111 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3112 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3113 strcpyW( ui_key_str, root_key_str );
3114 strcatW( ui_key_str, deformated_key );
3116 deformat_string( package, name, &deformated_name );
3118 keypath = get_keypath( comp, hkey_root, deformated_key );
3119 msi_free( deformated_key );
3120 if (delete_key) delete_tree( hkey_root, keypath );
3121 else delete_value( hkey_root, keypath, deformated_name );
3122 msi_free( keypath );
3124 uirow = MSI_CreateRecord( 2 );
3125 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3126 MSI_RecordSetStringW( uirow, 2, deformated_name );
3127 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3128 msiobj_release( &uirow->hdr );
3130 msi_free( ui_key_str );
3131 msi_free( deformated_name );
3132 return ERROR_SUCCESS;
3135 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3137 static const WCHAR registry_query[] = {
3138 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3139 '`','R','e','g','i','s','t','r','y','`',0};
3140 static const WCHAR remove_registry_query[] = {
3141 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3142 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
3146 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3147 if (rc == ERROR_SUCCESS)
3149 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3150 msiobj_release( &view->hdr );
3151 if (rc != ERROR_SUCCESS)
3154 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3155 if (rc == ERROR_SUCCESS)
3157 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3158 msiobj_release( &view->hdr );
3159 if (rc != ERROR_SUCCESS)
3162 return ERROR_SUCCESS;
3165 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3167 package->script->CurrentlyScripting = TRUE;
3169 return ERROR_SUCCESS;
3173 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3175 static const WCHAR query[]= {
3176 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3177 '`','R','e','g','i','s','t','r','y','`',0};
3179 DWORD total = 0, count = 0;
3181 MSIFEATURE *feature;
3185 TRACE("InstallValidate\n");
3187 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3188 if (rc == ERROR_SUCCESS)
3190 rc = MSI_IterateRecords( view, &count, NULL, package );
3191 msiobj_release( &view->hdr );
3192 if (rc != ERROR_SUCCESS)
3194 total += count * REG_PROGRESS_VALUE;
3196 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3197 total += COMPONENT_PROGRESS_VALUE;
3199 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3200 total += file->FileSize;
3202 msi_ui_progress( package, 0, total, 0, 0 );
3204 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3206 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3207 debugstr_w(feature->Feature), feature->Installed,
3208 feature->ActionRequest, feature->Action);
3210 return ERROR_SUCCESS;
3213 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3215 MSIPACKAGE* package = param;
3216 LPCWSTR cond = NULL;
3217 LPCWSTR message = NULL;
3220 static const WCHAR title[]=
3221 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3223 cond = MSI_RecordGetString(row,1);
3225 r = MSI_EvaluateConditionW(package,cond);
3226 if (r == MSICONDITION_FALSE)
3228 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3231 message = MSI_RecordGetString(row,2);
3232 deformat_string(package,message,&deformated);
3233 MessageBoxW(NULL,deformated,title,MB_OK);
3234 msi_free(deformated);
3237 return ERROR_INSTALL_FAILURE;
3240 return ERROR_SUCCESS;
3243 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3245 static const WCHAR query[] = {
3246 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3247 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3251 TRACE("Checking launch conditions\n");
3253 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3254 if (rc != ERROR_SUCCESS)
3255 return ERROR_SUCCESS;
3257 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3258 msiobj_release(&view->hdr);
3262 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3266 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3268 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3270 static const WCHAR query[] = {
3271 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3272 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3273 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3274 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3275 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3278 LPWSTR deformated, buffer, deformated_name;
3281 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3285 root = MSI_RecordGetInteger(row,2);
3286 key = MSI_RecordGetString(row, 3);
3287 name = MSI_RecordGetString(row, 4);
3288 deformat_string(package, key , &deformated);
3289 deformat_string(package, name, &deformated_name);
3291 len = strlenW(deformated) + 6;
3292 if (deformated_name)
3293 len+=strlenW(deformated_name);
3295 buffer = msi_alloc( len *sizeof(WCHAR));
3297 if (deformated_name)
3298 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3300 sprintfW(buffer,fmt,root,deformated);
3302 msi_free(deformated);
3303 msi_free(deformated_name);
3304 msiobj_release(&row->hdr);
3308 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3310 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3315 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3318 return strdupW( file->TargetPath );
3323 static HKEY openSharedDLLsKey(void)
3326 static const WCHAR path[] =
3327 {'S','o','f','t','w','a','r','e','\\',
3328 'M','i','c','r','o','s','o','f','t','\\',
3329 'W','i','n','d','o','w','s','\\',
3330 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3331 'S','h','a','r','e','d','D','L','L','s',0};
3333 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3337 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3342 DWORD sz = sizeof(count);
3345 hkey = openSharedDLLsKey();
3346 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3347 if (rc != ERROR_SUCCESS)
3353 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3357 hkey = openSharedDLLsKey();
3359 msi_reg_set_val_dword( hkey, path, count );
3361 RegDeleteValueW(hkey,path);
3366 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3368 MSIFEATURE *feature;
3372 /* only refcount DLLs */
3373 if (comp->KeyPath == NULL ||
3375 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3376 comp->Attributes & msidbComponentAttributesODBCDataSource)
3380 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3381 write = (count > 0);
3383 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3387 /* increment counts */
3388 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3392 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3395 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3397 if ( cl->component == comp )
3402 /* decrement counts */
3403 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3407 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3410 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3412 if ( cl->component == comp )
3417 /* ref count all the files in the component */
3422 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3424 if (file->Component == comp)
3425 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3429 /* add a count for permanent */
3430 if (comp->Attributes & msidbComponentAttributesPermanent)
3433 comp->RefCount = count;
3436 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3439 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3443 const WCHAR prefixW[] = {'<','\\',0};
3444 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3445 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3449 strcpyW( keypath, prefixW );
3450 strcatW( keypath, comp->assembly->display_name );
3454 return resolve_keypath( package, comp );
3457 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3459 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3466 squash_guid(package->ProductCode,squished_pc);
3467 msi_set_sourcedir_props(package, FALSE);
3469 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3472 INSTALLSTATE action;
3474 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3475 if (!comp->ComponentId)
3478 squash_guid( comp->ComponentId, squished_cc );
3479 msi_free( comp->FullKeypath );
3480 comp->FullKeypath = build_full_keypath( package, comp );
3482 ACTION_RefCountComponent( package, comp );
3484 if (package->need_rollback) action = comp->Installed;
3485 else action = comp->ActionRequest;
3487 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3488 debugstr_w(comp->Component), debugstr_w(squished_cc),
3489 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3491 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3493 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3494 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3496 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3498 if (rc != ERROR_SUCCESS)
3501 if (comp->Attributes & msidbComponentAttributesPermanent)
3503 static const WCHAR szPermKey[] =
3504 { '0','0','0','0','0','0','0','0','0','0','0','0',
3505 '0','0','0','0','0','0','0','0','0','0','0','0',
3506 '0','0','0','0','0','0','0','0',0 };
3508 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3510 if (action == INSTALLSTATE_LOCAL)
3511 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3517 WCHAR source[MAX_PATH];
3518 WCHAR base[MAX_PATH];
3521 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3522 static const WCHAR query[] = {
3523 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3524 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3525 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3526 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3527 '`','D','i','s','k','I','d','`',0};
3529 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3532 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3533 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3534 ptr2 = strrchrW(source, '\\') + 1;
3535 msiobj_release(&row->hdr);
3537 lstrcpyW(base, package->PackagePath);
3538 ptr = strrchrW(base, '\\');
3541 sourcepath = msi_resolve_file_source(package, file);
3542 ptr = sourcepath + lstrlenW(base);
3543 lstrcpyW(ptr2, ptr);
3544 msi_free(sourcepath);
3546 msi_reg_set_val_str(hkey, squished_pc, source);
3550 else if (action == INSTALLSTATE_ABSENT)
3552 if (comp->num_clients <= 0)
3554 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3555 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid );
3557 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
3562 uirow = MSI_CreateRecord(3);
3563 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3564 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3565 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3566 msi_ui_actiondata( package, szProcessComponents, uirow );
3567 msiobj_release( &uirow->hdr );
3569 return ERROR_SUCCESS;
3580 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3581 LPWSTR lpszName, LONG_PTR lParam)
3584 typelib_struct *tl_struct = (typelib_struct*) lParam;
3585 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3589 if (!IS_INTRESOURCE(lpszName))
3591 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3595 sz = strlenW(tl_struct->source)+4;
3596 sz *= sizeof(WCHAR);
3598 if ((INT_PTR)lpszName == 1)
3599 tl_struct->path = strdupW(tl_struct->source);
3602 tl_struct->path = msi_alloc(sz);
3603 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3606 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3607 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3610 msi_free(tl_struct->path);
3611 tl_struct->path = NULL;
3616 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3617 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3619 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3623 msi_free(tl_struct->path);
3624 tl_struct->path = NULL;
3626 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3627 ITypeLib_Release(tl_struct->ptLib);
3632 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3634 MSIPACKAGE* package = param;
3638 typelib_struct tl_struct;
3643 component = MSI_RecordGetString(row,3);
3644 comp = msi_get_loaded_component(package,component);
3646 return ERROR_SUCCESS;
3648 comp->Action = msi_get_component_action( package, comp );
3649 if (comp->Action != INSTALLSTATE_LOCAL)
3651 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3652 return ERROR_SUCCESS;
3655 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3657 TRACE("component has no key path\n");
3658 return ERROR_SUCCESS;
3660 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3662 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3666 guid = MSI_RecordGetString(row,1);
3667 CLSIDFromString( guid, &tl_struct.clsid);
3668 tl_struct.source = strdupW( file->TargetPath );
3669 tl_struct.path = NULL;
3671 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3672 (LONG_PTR)&tl_struct);
3676 LPCWSTR helpid, help_path = NULL;
3679 helpid = MSI_RecordGetString(row,6);
3681 if (helpid) help_path = msi_get_target_folder( package, helpid );
3682 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3685 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3687 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3689 ITypeLib_Release(tl_struct.ptLib);
3690 msi_free(tl_struct.path);
3692 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3694 FreeLibrary(module);
3695 msi_free(tl_struct.source);
3699 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3702 ERR("Failed to load type library: %08x\n", hr);
3703 return ERROR_INSTALL_FAILURE;
3706 ITypeLib_Release(tlib);
3709 return ERROR_SUCCESS;
3712 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3714 static const WCHAR query[] = {
3715 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3716 '`','T','y','p','e','L','i','b','`',0};
3720 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3721 if (rc != ERROR_SUCCESS)
3722 return ERROR_SUCCESS;
3724 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3725 msiobj_release(&view->hdr);
3729 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3731 MSIPACKAGE *package = param;
3732 LPCWSTR component, guid;
3740 component = MSI_RecordGetString( row, 3 );
3741 comp = msi_get_loaded_component( package, component );
3743 return ERROR_SUCCESS;
3745 comp->Action = msi_get_component_action( package, comp );
3746 if (comp->Action != INSTALLSTATE_ABSENT)
3748 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3749 return ERROR_SUCCESS;
3751 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3753 guid = MSI_RecordGetString( row, 1 );
3754 CLSIDFromString( guid, &libid );
3755 version = MSI_RecordGetInteger( row, 4 );
3756 language = MSI_RecordGetInteger( row, 2 );
3759 syskind = SYS_WIN64;
3761 syskind = SYS_WIN32;
3764 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3767 WARN("Failed to unregister typelib: %08x\n", hr);
3770 return ERROR_SUCCESS;
3773 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3775 static const WCHAR query[] = {
3776 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3777 '`','T','y','p','e','L','i','b','`',0};
3781 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3782 if (rc != ERROR_SUCCESS)
3783 return ERROR_SUCCESS;
3785 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3786 msiobj_release( &view->hdr );
3790 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3792 static const WCHAR szlnk[] = {'.','l','n','k',0};
3793 LPCWSTR directory, extension, link_folder;
3794 LPWSTR link_file, filename;
3796 directory = MSI_RecordGetString( row, 2 );
3797 link_folder = msi_get_target_folder( package, directory );
3800 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3803 /* may be needed because of a bug somewhere else */
3804 msi_create_full_path( link_folder );
3806 filename = msi_dup_record_field( row, 3 );
3807 msi_reduce_to_long_filename( filename );
3809 extension = strchrW( filename, '.' );
3810 if (!extension || strcmpiW( extension, szlnk ))
3812 int len = strlenW( filename );
3813 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3814 memcpy( filename + len, szlnk, sizeof(szlnk) );
3816 link_file = msi_build_directory_name( 2, link_folder, filename );
3817 msi_free( filename );
3822 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3824 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3825 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3826 WCHAR *folder, *dest, *path;
3828 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3829 folder = msi_dup_property( package->db, szWindowsFolder );
3832 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3833 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3834 msi_free( appdata );
3836 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3837 msi_create_full_path( dest );
3838 path = msi_build_directory_name( 2, dest, icon_name );
3844 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3846 MSIPACKAGE *package = param;
3847 LPWSTR link_file, deformated, path;
3848 LPCWSTR component, target;
3850 IShellLinkW *sl = NULL;
3851 IPersistFile *pf = NULL;
3854 component = MSI_RecordGetString(row, 4);
3855 comp = msi_get_loaded_component(package, component);
3857 return ERROR_SUCCESS;
3859 comp->Action = msi_get_component_action( package, comp );
3860 if (comp->Action != INSTALLSTATE_LOCAL)
3862 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3863 return ERROR_SUCCESS;
3865 msi_ui_actiondata( package, szCreateShortcuts, row );
3867 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3868 &IID_IShellLinkW, (LPVOID *) &sl );
3872 ERR("CLSID_ShellLink not available\n");
3876 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3879 ERR("QueryInterface(IID_IPersistFile) failed\n");
3883 target = MSI_RecordGetString(row, 5);
3884 if (strchrW(target, '['))
3886 deformat_string( package, target, &path );
3887 TRACE("target path is %s\n", debugstr_w(path));
3888 IShellLinkW_SetPath( sl, path );
3893 FIXME("poorly handled shortcut format, advertised shortcut\n");
3894 IShellLinkW_SetPath(sl,comp->FullKeypath);
3897 if (!MSI_RecordIsNull(row,6))
3899 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3900 deformat_string(package, arguments, &deformated);
3901 IShellLinkW_SetArguments(sl,deformated);
3902 msi_free(deformated);
3905 if (!MSI_RecordIsNull(row,7))
3907 LPCWSTR description = MSI_RecordGetString(row, 7);
3908 IShellLinkW_SetDescription(sl, description);
3911 if (!MSI_RecordIsNull(row,8))
3912 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3914 if (!MSI_RecordIsNull(row,9))
3917 LPCWSTR icon = MSI_RecordGetString(row, 9);
3919 path = msi_build_icon_path(package, icon);
3920 index = MSI_RecordGetInteger(row,10);
3922 /* no value means 0 */
3923 if (index == MSI_NULL_INTEGER)
3926 IShellLinkW_SetIconLocation(sl, path, index);
3930 if (!MSI_RecordIsNull(row,11))
3931 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3933 if (!MSI_RecordIsNull(row,12))
3935 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3936 full_path = msi_get_target_folder( package, wkdir );
3937 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3939 link_file = get_link_file(package, row);
3941 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3942 IPersistFile_Save(pf, link_file, FALSE);
3943 msi_free(link_file);
3947 IPersistFile_Release( pf );
3949 IShellLinkW_Release( sl );
3951 return ERROR_SUCCESS;
3954 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3956 static const WCHAR query[] = {
3957 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3958 '`','S','h','o','r','t','c','u','t','`',0};
3963 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3964 if (rc != ERROR_SUCCESS)
3965 return ERROR_SUCCESS;
3967 res = CoInitialize( NULL );
3969 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3970 msiobj_release(&view->hdr);
3972 if (SUCCEEDED(res)) CoUninitialize();
3976 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3978 MSIPACKAGE *package = param;
3983 component = MSI_RecordGetString( row, 4 );
3984 comp = msi_get_loaded_component( package, component );
3986 return ERROR_SUCCESS;
3988 comp->Action = msi_get_component_action( package, comp );
3989 if (comp->Action != INSTALLSTATE_ABSENT)
3991 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3992 return ERROR_SUCCESS;
3994 msi_ui_actiondata( package, szRemoveShortcuts, row );
3996 link_file = get_link_file( package, row );
3998 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3999 if (!DeleteFileW( link_file ))
4001 WARN("Failed to remove shortcut file %u\n", GetLastError());
4003 msi_free( link_file );
4005 return ERROR_SUCCESS;
4008 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4010 static const WCHAR query[] = {
4011 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4012 '`','S','h','o','r','t','c','u','t','`',0};
4016 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4017 if (rc != ERROR_SUCCESS)
4018 return ERROR_SUCCESS;
4020 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
4021 msiobj_release( &view->hdr );
4025 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
4027 MSIPACKAGE* package = param;
4035 FileName = MSI_RecordGetString(row,1);
4038 ERR("Unable to get FileName\n");
4039 return ERROR_SUCCESS;
4042 FilePath = msi_build_icon_path(package, FileName);
4044 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4046 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4047 FILE_ATTRIBUTE_NORMAL, NULL);
4049 if (the_file == INVALID_HANDLE_VALUE)
4051 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4053 return ERROR_SUCCESS;
4060 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4061 if (rc != ERROR_SUCCESS)
4063 ERR("Failed to get stream\n");
4064 CloseHandle(the_file);
4065 DeleteFileW(FilePath);
4068 WriteFile(the_file,buffer,sz,&write,NULL);
4069 } while (sz == 1024);
4072 CloseHandle(the_file);
4074 return ERROR_SUCCESS;
4077 static UINT msi_publish_icons(MSIPACKAGE *package)
4079 static const WCHAR query[]= {
4080 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4081 '`','I','c','o','n','`',0};
4085 r = MSI_DatabaseOpenViewW(package->db, query, &view);
4086 if (r == ERROR_SUCCESS)
4088 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
4089 msiobj_release(&view->hdr);
4090 if (r != ERROR_SUCCESS)
4093 return ERROR_SUCCESS;
4096 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
4102 MSISOURCELISTINFO *info;
4104 r = RegCreateKeyW(hkey, szSourceList, &source);
4105 if (r != ERROR_SUCCESS)
4108 RegCloseKey(source);
4110 buffer = strrchrW(package->PackagePath, '\\') + 1;
4111 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4112 package->Context, MSICODE_PRODUCT,
4113 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4114 if (r != ERROR_SUCCESS)
4117 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4118 package->Context, MSICODE_PRODUCT,
4119 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4120 if (r != ERROR_SUCCESS)
4123 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4124 package->Context, MSICODE_PRODUCT,
4125 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4126 if (r != ERROR_SUCCESS)
4129 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4131 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4132 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4133 info->options, info->value);
4135 MsiSourceListSetInfoW(package->ProductCode, NULL,
4136 info->context, info->options,
4137 info->property, info->value);
4140 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4142 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4143 disk->context, disk->options,
4144 disk->disk_id, disk->volume_label, disk->disk_prompt);
4147 return ERROR_SUCCESS;
4150 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4152 MSIHANDLE hdb, suminfo;
4153 WCHAR guids[MAX_PATH];
4154 WCHAR packcode[SQUISH_GUID_SIZE];
4161 static const WCHAR szARPProductIcon[] =
4162 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4163 static const WCHAR szAssignment[] =
4164 {'A','s','s','i','g','n','m','e','n','t',0};
4165 static const WCHAR szAdvertiseFlags[] =
4166 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4167 static const WCHAR szClients[] =
4168 {'C','l','i','e','n','t','s',0};
4169 static const WCHAR szColon[] = {':',0};
4171 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4172 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4175 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4176 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4179 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4181 buffer = msi_dup_property(package->db, szARPProductIcon);
4184 LPWSTR path = msi_build_icon_path(package, buffer);
4185 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4190 buffer = msi_dup_property(package->db, szProductVersion);
4193 DWORD verdword = msi_version_str_to_dword(buffer);
4194 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4198 msi_reg_set_val_dword(hkey, szAssignment, 0);
4199 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4200 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4201 msi_reg_set_val_str(hkey, szClients, szColon);
4203 hdb = alloc_msihandle(&package->db->hdr);
4205 return ERROR_NOT_ENOUGH_MEMORY;
4207 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4208 MsiCloseHandle(hdb);
4209 if (r != ERROR_SUCCESS)
4213 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4214 NULL, guids, &size);
4215 if (r != ERROR_SUCCESS)
4218 ptr = strchrW(guids, ';');
4220 squash_guid(guids, packcode);
4221 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4224 MsiCloseHandle(suminfo);
4225 return ERROR_SUCCESS;
4228 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4233 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4235 upgrade = msi_dup_property(package->db, szUpgradeCode);
4237 return ERROR_SUCCESS;
4239 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4240 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4242 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4244 if (r != ERROR_SUCCESS)
4246 WARN("failed to open upgrade code key\n");
4248 return ERROR_SUCCESS;
4250 squash_guid(package->ProductCode, squashed_pc);
4251 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4254 return ERROR_SUCCESS;
4257 static BOOL msi_check_publish(MSIPACKAGE *package)
4259 MSIFEATURE *feature;
4261 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4263 feature->Action = msi_get_feature_action( package, feature );
4264 if (feature->Action == INSTALLSTATE_LOCAL)
4271 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4273 MSIFEATURE *feature;
4275 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4277 feature->Action = msi_get_feature_action( package, feature );
4278 if (feature->Action != INSTALLSTATE_ABSENT)
4285 static UINT msi_publish_patches( MSIPACKAGE *package )
4287 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4288 WCHAR patch_squashed[GUID_SIZE];
4289 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4291 MSIPATCHINFO *patch;
4293 WCHAR *p, *all_patches = NULL;
4296 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4297 if (r != ERROR_SUCCESS)
4298 return ERROR_FUNCTION_FAILED;
4300 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4301 if (res != ERROR_SUCCESS)
4303 r = ERROR_FUNCTION_FAILED;
4307 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4308 if (r != ERROR_SUCCESS)
4311 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4313 squash_guid( patch->patchcode, patch_squashed );
4314 len += strlenW( patch_squashed ) + 1;
4317 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4321 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4325 squash_guid( patch->patchcode, p );
4326 p += strlenW( p ) + 1;
4328 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4329 (const BYTE *)patch->transforms,
4330 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4331 if (res != ERROR_SUCCESS)
4334 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4335 if (r != ERROR_SUCCESS)
4338 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4339 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4340 RegCloseKey( patch_key );
4341 if (res != ERROR_SUCCESS)
4344 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4346 res = GetLastError();
4347 ERR("Unable to copy patch package %d\n", res);
4350 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4351 if (res != ERROR_SUCCESS)
4354 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4355 RegCloseKey( patch_key );
4356 if (res != ERROR_SUCCESS)
4360 all_patches[len] = 0;
4361 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4362 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4363 if (res != ERROR_SUCCESS)
4366 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4367 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4368 if (res != ERROR_SUCCESS)
4369 r = ERROR_FUNCTION_FAILED;
4372 RegCloseKey( product_patches_key );
4373 RegCloseKey( patches_key );
4374 RegCloseKey( product_key );
4375 msi_free( all_patches );
4379 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4382 HKEY hukey = NULL, hudkey = NULL;
4385 if (!list_empty(&package->patches))
4387 rc = msi_publish_patches(package);
4388 if (rc != ERROR_SUCCESS)
4392 /* FIXME: also need to publish if the product is in advertise mode */
4393 if (!msi_check_publish(package))
4394 return ERROR_SUCCESS;
4396 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4398 if (rc != ERROR_SUCCESS)
4401 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4402 NULL, &hudkey, TRUE);
4403 if (rc != ERROR_SUCCESS)
4406 rc = msi_publish_upgrade_code(package);
4407 if (rc != ERROR_SUCCESS)
4410 rc = msi_publish_product_properties(package, hukey);
4411 if (rc != ERROR_SUCCESS)
4414 rc = msi_publish_sourcelist(package, hukey);
4415 if (rc != ERROR_SUCCESS)
4418 rc = msi_publish_icons(package);
4421 uirow = MSI_CreateRecord( 1 );
4422 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4423 msi_ui_actiondata( package, szPublishProduct, uirow );
4424 msiobj_release( &uirow->hdr );
4427 RegCloseKey(hudkey);
4431 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4433 WCHAR *filename, *ptr, *folder, *ret;
4434 const WCHAR *dirprop;
4436 filename = msi_dup_record_field( row, 2 );
4437 if (filename && (ptr = strchrW( filename, '|' )))
4442 dirprop = MSI_RecordGetString( row, 3 );
4445 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4446 if (!folder) folder = msi_dup_property( package->db, dirprop );
4449 folder = msi_dup_property( package->db, szWindowsFolder );
4453 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4454 msi_free( filename );
4458 ret = msi_build_directory_name( 2, folder, ptr );
4460 msi_free( filename );
4465 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4467 MSIPACKAGE *package = param;
4468 LPCWSTR component, section, key, value, identifier;
4469 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4474 component = MSI_RecordGetString(row, 8);
4475 comp = msi_get_loaded_component(package,component);
4477 return ERROR_SUCCESS;
4479 comp->Action = msi_get_component_action( package, comp );
4480 if (comp->Action != INSTALLSTATE_LOCAL)
4482 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4483 return ERROR_SUCCESS;
4486 identifier = MSI_RecordGetString(row,1);
4487 section = MSI_RecordGetString(row,4);
4488 key = MSI_RecordGetString(row,5);
4489 value = MSI_RecordGetString(row,6);
4490 action = MSI_RecordGetInteger(row,7);
4492 deformat_string(package,section,&deformated_section);
4493 deformat_string(package,key,&deformated_key);
4494 deformat_string(package,value,&deformated_value);
4496 fullname = get_ini_file_name(package, row);
4500 TRACE("Adding value %s to section %s in %s\n",
4501 debugstr_w(deformated_key), debugstr_w(deformated_section),
4502 debugstr_w(fullname));
4503 WritePrivateProfileStringW(deformated_section, deformated_key,
4504 deformated_value, fullname);
4506 else if (action == 1)
4509 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4510 returned, 10, fullname);
4511 if (returned[0] == 0)
4513 TRACE("Adding value %s to section %s in %s\n",
4514 debugstr_w(deformated_key), debugstr_w(deformated_section),
4515 debugstr_w(fullname));
4517 WritePrivateProfileStringW(deformated_section, deformated_key,
4518 deformated_value, fullname);
4521 else if (action == 3)
4522 FIXME("Append to existing section not yet implemented\n");
4524 uirow = MSI_CreateRecord(4);
4525 MSI_RecordSetStringW(uirow,1,identifier);
4526 MSI_RecordSetStringW(uirow,2,deformated_section);
4527 MSI_RecordSetStringW(uirow,3,deformated_key);
4528 MSI_RecordSetStringW(uirow,4,deformated_value);
4529 msi_ui_actiondata( package, szWriteIniValues, uirow );
4530 msiobj_release( &uirow->hdr );
4533 msi_free(deformated_key);
4534 msi_free(deformated_value);
4535 msi_free(deformated_section);
4536 return ERROR_SUCCESS;
4539 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4541 static const WCHAR query[] = {
4542 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4543 '`','I','n','i','F','i','l','e','`',0};
4547 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4548 if (rc != ERROR_SUCCESS)
4549 return ERROR_SUCCESS;
4551 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4552 msiobj_release(&view->hdr);
4556 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4558 MSIPACKAGE *package = param;
4559 LPCWSTR component, section, key, value, identifier;
4560 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4565 component = MSI_RecordGetString( row, 8 );
4566 comp = msi_get_loaded_component( package, component );
4568 return ERROR_SUCCESS;
4570 comp->Action = msi_get_component_action( package, comp );
4571 if (comp->Action != INSTALLSTATE_ABSENT)
4573 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4574 return ERROR_SUCCESS;
4577 identifier = MSI_RecordGetString( row, 1 );
4578 section = MSI_RecordGetString( row, 4 );
4579 key = MSI_RecordGetString( row, 5 );
4580 value = MSI_RecordGetString( row, 6 );
4581 action = MSI_RecordGetInteger( row, 7 );
4583 deformat_string( package, section, &deformated_section );
4584 deformat_string( package, key, &deformated_key );
4585 deformat_string( package, value, &deformated_value );
4587 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4589 filename = get_ini_file_name( package, row );
4591 TRACE("Removing key %s from section %s in %s\n",
4592 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4594 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4596 WARN("Unable to remove key %u\n", GetLastError());
4598 msi_free( filename );
4601 FIXME("Unsupported action %d\n", action);
4604 uirow = MSI_CreateRecord( 4 );
4605 MSI_RecordSetStringW( uirow, 1, identifier );
4606 MSI_RecordSetStringW( uirow, 2, deformated_section );
4607 MSI_RecordSetStringW( uirow, 3, deformated_key );
4608 MSI_RecordSetStringW( uirow, 4, deformated_value );
4609 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4610 msiobj_release( &uirow->hdr );
4612 msi_free( deformated_key );
4613 msi_free( deformated_value );
4614 msi_free( deformated_section );
4615 return ERROR_SUCCESS;
4618 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4620 MSIPACKAGE *package = param;
4621 LPCWSTR component, section, key, value, identifier;
4622 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4627 component = MSI_RecordGetString( row, 8 );
4628 comp = msi_get_loaded_component( package, component );
4630 return ERROR_SUCCESS;
4632 comp->Action = msi_get_component_action( package, comp );
4633 if (comp->Action != INSTALLSTATE_LOCAL)
4635 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4636 return ERROR_SUCCESS;
4639 identifier = MSI_RecordGetString( row, 1 );
4640 section = MSI_RecordGetString( row, 4 );
4641 key = MSI_RecordGetString( row, 5 );
4642 value = MSI_RecordGetString( row, 6 );
4643 action = MSI_RecordGetInteger( row, 7 );
4645 deformat_string( package, section, &deformated_section );
4646 deformat_string( package, key, &deformated_key );
4647 deformat_string( package, value, &deformated_value );
4649 if (action == msidbIniFileActionRemoveLine)
4651 filename = get_ini_file_name( package, row );
4653 TRACE("Removing key %s from section %s in %s\n",
4654 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4656 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4658 WARN("Unable to remove key %u\n", GetLastError());
4660 msi_free( filename );
4663 FIXME("Unsupported action %d\n", action);
4665 uirow = MSI_CreateRecord( 4 );
4666 MSI_RecordSetStringW( uirow, 1, identifier );
4667 MSI_RecordSetStringW( uirow, 2, deformated_section );
4668 MSI_RecordSetStringW( uirow, 3, deformated_key );
4669 MSI_RecordSetStringW( uirow, 4, deformated_value );
4670 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4671 msiobj_release( &uirow->hdr );
4673 msi_free( deformated_key );
4674 msi_free( deformated_value );
4675 msi_free( deformated_section );
4676 return ERROR_SUCCESS;
4679 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4681 static const WCHAR query[] = {
4682 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4683 '`','I','n','i','F','i','l','e','`',0};
4684 static const WCHAR remove_query[] = {
4685 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4686 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4690 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4691 if (rc == ERROR_SUCCESS)
4693 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4694 msiobj_release( &view->hdr );
4695 if (rc != ERROR_SUCCESS)
4698 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4699 if (rc == ERROR_SUCCESS)
4701 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4702 msiobj_release( &view->hdr );
4703 if (rc != ERROR_SUCCESS)
4706 return ERROR_SUCCESS;
4709 static void register_dll( const WCHAR *dll, BOOL unregister )
4711 static const WCHAR regW[] =
4712 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"','%','s','\"',0};
4713 static const WCHAR unregW[] =
4714 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"','%','s','\"',0};
4715 PROCESS_INFORMATION pi;
4719 if (!(cmd = msi_alloc( strlenW(dll) * sizeof(WCHAR) + sizeof(unregW) ))) return;
4721 if (unregister) sprintfW( cmd, unregW, dll );
4722 else sprintfW( cmd, regW, dll );
4724 memset( &si, 0, sizeof(STARTUPINFOW) );
4725 if (CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
4727 CloseHandle( pi.hThread );
4728 msi_dialog_check_messages( pi.hProcess );
4729 CloseHandle( pi.hProcess );
4734 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4736 MSIPACKAGE *package = param;
4741 filename = MSI_RecordGetString( row, 1 );
4742 file = msi_get_loaded_file( package, filename );
4745 WARN("unable to find file %s\n", debugstr_w(filename));
4746 return ERROR_SUCCESS;
4748 file->Component->Action = msi_get_component_action( package, file->Component );
4749 if (file->Component->Action != INSTALLSTATE_LOCAL)
4751 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4752 return ERROR_SUCCESS;
4755 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4756 register_dll( file->TargetPath, FALSE );
4758 uirow = MSI_CreateRecord( 2 );
4759 MSI_RecordSetStringW( uirow, 1, file->File );
4760 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4761 msi_ui_actiondata( package, szSelfRegModules, uirow );
4762 msiobj_release( &uirow->hdr );
4764 return ERROR_SUCCESS;
4767 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4769 static const WCHAR query[] = {
4770 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4771 '`','S','e','l','f','R','e','g','`',0};
4775 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4776 if (rc != ERROR_SUCCESS)
4777 return ERROR_SUCCESS;
4779 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4780 msiobj_release(&view->hdr);
4784 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4786 MSIPACKAGE *package = param;
4791 filename = MSI_RecordGetString( row, 1 );
4792 file = msi_get_loaded_file( package, filename );
4795 WARN("unable to find file %s\n", debugstr_w(filename));
4796 return ERROR_SUCCESS;
4798 file->Component->Action = msi_get_component_action( package, file->Component );
4799 if (file->Component->Action != INSTALLSTATE_ABSENT)
4801 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4802 return ERROR_SUCCESS;
4805 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4806 register_dll( file->TargetPath, TRUE );
4808 uirow = MSI_CreateRecord( 2 );
4809 MSI_RecordSetStringW( uirow, 1, file->File );
4810 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4811 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4812 msiobj_release( &uirow->hdr );
4814 return ERROR_SUCCESS;
4817 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4819 static const WCHAR query[] = {
4820 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4821 '`','S','e','l','f','R','e','g','`',0};
4825 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4826 if (rc != ERROR_SUCCESS)
4827 return ERROR_SUCCESS;
4829 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4830 msiobj_release( &view->hdr );
4834 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4836 MSIFEATURE *feature;
4838 HKEY hkey = NULL, userdata = NULL;
4840 if (!msi_check_publish(package))
4841 return ERROR_SUCCESS;
4843 rc = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4845 if (rc != ERROR_SUCCESS)
4848 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4850 if (rc != ERROR_SUCCESS)
4853 /* here the guids are base 85 encoded */
4854 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4860 BOOL absent = FALSE;
4863 if (feature->Action != INSTALLSTATE_LOCAL &&
4864 feature->Action != INSTALLSTATE_SOURCE &&
4865 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4868 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4872 if (feature->Feature_Parent)
4873 size += strlenW( feature->Feature_Parent )+2;
4875 data = msi_alloc(size * sizeof(WCHAR));
4878 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4880 MSICOMPONENT* component = cl->component;
4884 if (component->ComponentId)
4886 TRACE("From %s\n",debugstr_w(component->ComponentId));
4887 CLSIDFromString(component->ComponentId, &clsid);
4888 encode_base85_guid(&clsid,buf);
4889 TRACE("to %s\n",debugstr_w(buf));
4894 if (feature->Feature_Parent)
4896 static const WCHAR sep[] = {'\2',0};
4898 strcatW(data,feature->Feature_Parent);
4901 msi_reg_set_val_str( userdata, feature->Feature, data );
4905 if (feature->Feature_Parent)
4906 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4909 size += sizeof(WCHAR);
4910 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4911 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4915 size += 2*sizeof(WCHAR);
4916 data = msi_alloc(size);
4919 if (feature->Feature_Parent)
4920 strcpyW( &data[1], feature->Feature_Parent );
4921 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4927 uirow = MSI_CreateRecord( 1 );
4928 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4929 msi_ui_actiondata( package, szPublishFeatures, uirow );
4930 msiobj_release( &uirow->hdr );
4931 /* FIXME: call msi_ui_progress? */
4936 RegCloseKey(userdata);
4940 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4946 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4948 r = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4950 if (r == ERROR_SUCCESS)
4952 RegDeleteValueW(hkey, feature->Feature);
4956 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4958 if (r == ERROR_SUCCESS)
4960 RegDeleteValueW(hkey, feature->Feature);
4964 uirow = MSI_CreateRecord( 1 );
4965 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4966 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4967 msiobj_release( &uirow->hdr );
4969 return ERROR_SUCCESS;
4972 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4974 MSIFEATURE *feature;
4976 if (!msi_check_unpublish(package))
4977 return ERROR_SUCCESS;
4979 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4981 msi_unpublish_feature(package, feature);
4984 return ERROR_SUCCESS;
4987 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4991 WCHAR date[9], *val, *buffer;
4992 const WCHAR *prop, *key;
4994 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4995 static const WCHAR modpath_fmt[] =
4996 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4997 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4998 static const WCHAR szModifyPath[] =
4999 {'M','o','d','i','f','y','P','a','t','h',0};
5000 static const WCHAR szUninstallString[] =
5001 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5002 static const WCHAR szEstimatedSize[] =
5003 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5004 static const WCHAR szDisplayVersion[] =
5005 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5006 static const WCHAR szInstallSource[] =
5007 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5008 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
5009 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5010 static const WCHAR szAuthorizedCDFPrefix[] =
5011 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5012 static const WCHAR szARPCONTACT[] =
5013 {'A','R','P','C','O','N','T','A','C','T',0};
5014 static const WCHAR szContact[] =
5015 {'C','o','n','t','a','c','t',0};
5016 static const WCHAR szARPCOMMENTS[] =
5017 {'A','R','P','C','O','M','M','E','N','T','S',0};
5018 static const WCHAR szComments[] =
5019 {'C','o','m','m','e','n','t','s',0};
5020 static const WCHAR szProductName[] =
5021 {'P','r','o','d','u','c','t','N','a','m','e',0};
5022 static const WCHAR szDisplayName[] =
5023 {'D','i','s','p','l','a','y','N','a','m','e',0};
5024 static const WCHAR szARPHELPLINK[] =
5025 {'A','R','P','H','E','L','P','L','I','N','K',0};
5026 static const WCHAR szHelpLink[] =
5027 {'H','e','l','p','L','i','n','k',0};
5028 static const WCHAR szARPHELPTELEPHONE[] =
5029 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5030 static const WCHAR szHelpTelephone[] =
5031 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5032 static const WCHAR szARPINSTALLLOCATION[] =
5033 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5034 static const WCHAR szManufacturer[] =
5035 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5036 static const WCHAR szPublisher[] =
5037 {'P','u','b','l','i','s','h','e','r',0};
5038 static const WCHAR szARPREADME[] =
5039 {'A','R','P','R','E','A','D','M','E',0};
5040 static const WCHAR szReadme[] =
5041 {'R','e','a','d','M','e',0};
5042 static const WCHAR szARPSIZE[] =
5043 {'A','R','P','S','I','Z','E',0};
5044 static const WCHAR szSize[] =
5045 {'S','i','z','e',0};
5046 static const WCHAR szARPURLINFOABOUT[] =
5047 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5048 static const WCHAR szURLInfoAbout[] =
5049 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5050 static const WCHAR szARPURLUPDATEINFO[] =
5051 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5052 static const WCHAR szURLUpdateInfo[] =
5053 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5054 static const WCHAR szARPSYSTEMCOMPONENT[] =
5055 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
5056 static const WCHAR szSystemComponent[] =
5057 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
5059 static const WCHAR *propval[] = {
5060 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
5061 szARPCONTACT, szContact,
5062 szARPCOMMENTS, szComments,
5063 szProductName, szDisplayName,
5064 szARPHELPLINK, szHelpLink,
5065 szARPHELPTELEPHONE, szHelpTelephone,
5066 szARPINSTALLLOCATION, szInstallLocation,
5067 szSourceDir, szInstallSource,
5068 szManufacturer, szPublisher,
5069 szARPREADME, szReadme,
5071 szARPURLINFOABOUT, szURLInfoAbout,
5072 szARPURLUPDATEINFO, szURLUpdateInfo,
5075 const WCHAR **p = propval;
5081 val = msi_dup_property(package->db, prop);
5082 msi_reg_set_val_str(hkey, key, val);
5086 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5087 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
5089 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
5091 size = deformat_string(package, modpath_fmt, &buffer) * sizeof(WCHAR);
5092 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5093 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5096 /* FIXME: Write real Estimated Size when we have it */
5097 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5099 GetLocalTime(&systime);
5100 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5101 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5103 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5104 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5106 buffer = msi_dup_property(package->db, szProductVersion);
5107 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5110 DWORD verdword = msi_version_str_to_dword(buffer);
5112 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5113 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5114 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5118 return ERROR_SUCCESS;
5121 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5123 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5125 LPWSTR upgrade_code;
5126 HKEY hkey, props, upgrade_key;
5129 /* FIXME: also need to publish if the product is in advertise mode */
5130 if (!msi_check_publish(package))
5131 return ERROR_SUCCESS;
5133 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
5134 if (rc != ERROR_SUCCESS)
5137 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
5138 if (rc != ERROR_SUCCESS)
5141 rc = msi_publish_install_properties(package, hkey);
5142 if (rc != ERROR_SUCCESS)
5145 rc = msi_publish_install_properties(package, props);
5146 if (rc != ERROR_SUCCESS)
5149 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5152 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
5153 if (rc == ERROR_SUCCESS)
5155 squash_guid( package->ProductCode, squashed_pc );
5156 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
5157 RegCloseKey( upgrade_key );
5159 msi_free( upgrade_code );
5161 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
5162 package->delete_on_close = FALSE;
5165 uirow = MSI_CreateRecord( 1 );
5166 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5167 msi_ui_actiondata( package, szRegisterProduct, uirow );
5168 msiobj_release( &uirow->hdr );
5171 return ERROR_SUCCESS;
5174 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5176 return execute_script(package, SCRIPT_INSTALL);
5179 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5181 MSIPACKAGE *package = param;
5182 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5183 WCHAR *p, *icon_path;
5185 if (!icon) return ERROR_SUCCESS;
5186 if ((icon_path = msi_build_icon_path( package, icon )))
5188 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5189 DeleteFileW( icon_path );
5190 if ((p = strrchrW( icon_path, '\\' )))
5193 RemoveDirectoryW( icon_path );
5195 msi_free( icon_path );
5197 return ERROR_SUCCESS;
5200 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5202 static const WCHAR query[]= {
5203 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
5207 r = MSI_DatabaseOpenViewW( package->db, query, &view );
5208 if (r == ERROR_SUCCESS)
5210 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5211 msiobj_release( &view->hdr );
5212 if (r != ERROR_SUCCESS)
5215 return ERROR_SUCCESS;
5218 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
5220 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
5221 WCHAR *upgrade, **features;
5222 BOOL full_uninstall = TRUE;
5223 MSIFEATURE *feature;
5224 MSIPATCHINFO *patch;
5227 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5229 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
5231 features = msi_split_string( remove, ',' );
5232 for (i = 0; features && features[i]; i++)
5234 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
5238 if (!full_uninstall)
5239 return ERROR_SUCCESS;
5241 MSIREG_DeleteProductKey(package->ProductCode);
5242 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5243 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5245 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5246 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5247 MSIREG_DeleteUserProductKey(package->ProductCode);
5248 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5250 upgrade = msi_dup_property(package->db, szUpgradeCode);
5253 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5254 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5258 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5260 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5261 if (!strcmpW( package->ProductCode, patch->products ))
5263 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5264 patch->delete_on_close = TRUE;
5266 /* FIXME: remove local patch package if this is the last product */
5268 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5269 package->delete_on_close = TRUE;
5271 msi_unpublish_icons( package );
5272 return ERROR_SUCCESS;
5275 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5280 /* turn off scheduling */
5281 package->script->CurrentlyScripting= FALSE;
5283 /* first do the same as an InstallExecute */
5284 rc = ACTION_InstallExecute(package);
5285 if (rc != ERROR_SUCCESS)
5288 /* then handle commit actions */
5289 rc = execute_script(package, SCRIPT_COMMIT);
5290 if (rc != ERROR_SUCCESS)
5293 remove = msi_dup_property(package->db, szRemove);
5294 rc = msi_unpublish_product(package, remove);
5299 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5301 static const WCHAR RunOnce[] = {
5302 'S','o','f','t','w','a','r','e','\\',
5303 'M','i','c','r','o','s','o','f','t','\\',
5304 'W','i','n','d','o','w','s','\\',
5305 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5306 'R','u','n','O','n','c','e',0};
5307 static const WCHAR InstallRunOnce[] = {
5308 'S','o','f','t','w','a','r','e','\\',
5309 'M','i','c','r','o','s','o','f','t','\\',
5310 'W','i','n','d','o','w','s','\\',
5311 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5312 'I','n','s','t','a','l','l','e','r','\\',
5313 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5315 static const WCHAR msiexec_fmt[] = {
5317 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5318 '\"','%','s','\"',0};
5319 static const WCHAR install_fmt[] = {
5320 '/','I',' ','\"','%','s','\"',' ',
5321 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5322 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5323 WCHAR buffer[256], sysdir[MAX_PATH];
5325 WCHAR squished_pc[100];
5327 squash_guid(package->ProductCode,squished_pc);
5329 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5330 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5331 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5334 msi_reg_set_val_str( hkey, squished_pc, buffer );
5337 TRACE("Reboot command %s\n",debugstr_w(buffer));
5339 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5340 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5342 msi_reg_set_val_str( hkey, squished_pc, buffer );
5345 return ERROR_INSTALL_SUSPEND;
5348 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5350 static const WCHAR query[] =
5351 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5352 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5353 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5354 MSIRECORD *rec, *row;
5360 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5362 rec = MSI_CreateRecord( count + 2 );
5363 str = MSI_RecordGetString( row, 1 );
5364 MSI_RecordSetStringW( rec, 0, str );
5365 msiobj_release( &row->hdr );
5366 MSI_RecordSetInteger( rec, 1, error );
5368 va_start( va, count );
5369 for (i = 0; i < count; i++)
5371 str = va_arg( va, const WCHAR *);
5372 MSI_RecordSetStringW( rec, i + 2, str );
5376 MSI_FormatRecordW( package, rec, NULL, &size );
5378 data = msi_alloc( size * sizeof(WCHAR) );
5379 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5381 msiobj_release( &rec->hdr );
5385 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5391 * We are currently doing what should be done here in the top level Install
5392 * however for Administrative and uninstalls this step will be needed
5394 if (!package->PackagePath)
5395 return ERROR_SUCCESS;
5397 msi_set_sourcedir_props(package, TRUE);
5399 attrib = GetFileAttributesW(package->db->path);
5400 if (attrib == INVALID_FILE_ATTRIBUTES)
5405 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5406 package->Context, MSICODE_PRODUCT,
5407 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5408 if (rc == ERROR_MORE_DATA)
5410 prompt = msi_alloc(size * sizeof(WCHAR));
5411 MsiSourceListGetInfoW(package->ProductCode, NULL,
5412 package->Context, MSICODE_PRODUCT,
5413 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5416 prompt = strdupW(package->db->path);
5418 msg = msi_build_error_string(package, 1302, 1, prompt);
5420 while(attrib == INVALID_FILE_ATTRIBUTES)
5422 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5426 return ERROR_INSTALL_USEREXIT;
5428 attrib = GetFileAttributesW(package->db->path);
5434 return ERROR_SUCCESS;
5439 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5442 LPWSTR buffer, productid = NULL;
5443 UINT i, rc = ERROR_SUCCESS;
5446 static const WCHAR szPropKeys[][80] =
5448 {'P','r','o','d','u','c','t','I','D',0},
5449 {'U','S','E','R','N','A','M','E',0},
5450 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5454 static const WCHAR szRegKeys[][80] =
5456 {'P','r','o','d','u','c','t','I','D',0},
5457 {'R','e','g','O','w','n','e','r',0},
5458 {'R','e','g','C','o','m','p','a','n','y',0},
5462 if (msi_check_unpublish(package))
5464 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5468 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5472 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5474 if (rc != ERROR_SUCCESS)
5477 for( i = 0; szPropKeys[i][0]; i++ )
5479 buffer = msi_dup_property( package->db, szPropKeys[i] );
5480 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5485 uirow = MSI_CreateRecord( 1 );
5486 MSI_RecordSetStringW( uirow, 1, productid );
5487 msi_ui_actiondata( package, szRegisterUser, uirow );
5488 msiobj_release( &uirow->hdr );
5490 msi_free(productid);
5496 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5500 package->script->InWhatSequence |= SEQUENCE_EXEC;
5501 rc = ACTION_ProcessExecSequence(package,FALSE);
5505 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5507 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5508 WCHAR productid_85[21], component_85[21], *ret;
5512 /* > is used if there is a component GUID and < if not. */
5514 productid_85[0] = 0;
5515 component_85[0] = 0;
5516 CLSIDFromString( package->ProductCode, &clsid );
5518 encode_base85_guid( &clsid, productid_85 );
5521 CLSIDFromString( component->ComponentId, &clsid );
5522 encode_base85_guid( &clsid, component_85 );
5525 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5526 debugstr_w(component_85));
5528 sz = 20 + strlenW( feature ) + 20 + 3;
5529 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5530 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5534 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5536 MSIPACKAGE *package = param;
5537 LPCWSTR compgroupid, component, feature, qualifier, text;
5538 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5547 feature = MSI_RecordGetString(rec, 5);
5548 feat = msi_get_loaded_feature(package, feature);
5550 return ERROR_SUCCESS;
5552 feat->Action = msi_get_feature_action( package, feat );
5553 if (feat->Action != INSTALLSTATE_LOCAL &&
5554 feat->Action != INSTALLSTATE_SOURCE &&
5555 feat->Action != INSTALLSTATE_ADVERTISED)
5557 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5558 return ERROR_SUCCESS;
5561 component = MSI_RecordGetString(rec, 3);
5562 comp = msi_get_loaded_component(package, component);
5564 return ERROR_SUCCESS;
5566 compgroupid = MSI_RecordGetString(rec,1);
5567 qualifier = MSI_RecordGetString(rec,2);
5569 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5570 if (rc != ERROR_SUCCESS)
5573 advertise = msi_create_component_advertise_string( package, comp, feature );
5574 text = MSI_RecordGetString( rec, 4 );
5577 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5578 strcpyW( p, advertise );
5580 msi_free( advertise );
5583 existing = msi_reg_get_val_str( hkey, qualifier );
5585 sz = strlenW( advertise ) + 1;
5588 for (p = existing; *p; p += len)
5590 len = strlenW( p ) + 1;
5591 if (strcmpW( advertise, p )) sz += len;
5594 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5596 rc = ERROR_OUTOFMEMORY;
5602 for (p = existing; *p; p += len)
5604 len = strlenW( p ) + 1;
5605 if (strcmpW( advertise, p ))
5607 memcpy( q, p, len * sizeof(WCHAR) );
5612 strcpyW( q, advertise );
5613 q[strlenW( q ) + 1] = 0;
5615 msi_reg_set_val_multi_str( hkey, qualifier, output );
5620 msi_free( advertise );
5621 msi_free( existing );
5624 uirow = MSI_CreateRecord( 2 );
5625 MSI_RecordSetStringW( uirow, 1, compgroupid );
5626 MSI_RecordSetStringW( uirow, 2, qualifier);
5627 msi_ui_actiondata( package, szPublishComponents, uirow );
5628 msiobj_release( &uirow->hdr );
5629 /* FIXME: call ui_progress? */
5635 * At present I am ignorning the advertised components part of this and only
5636 * focusing on the qualified component sets
5638 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5640 static const WCHAR query[] = {
5641 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5642 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5646 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5647 if (rc != ERROR_SUCCESS)
5648 return ERROR_SUCCESS;
5650 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5651 msiobj_release(&view->hdr);
5655 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5657 static const WCHAR szInstallerComponents[] = {
5658 'S','o','f','t','w','a','r','e','\\',
5659 'M','i','c','r','o','s','o','f','t','\\',
5660 'I','n','s','t','a','l','l','e','r','\\',
5661 'C','o','m','p','o','n','e','n','t','s','\\',0};
5663 MSIPACKAGE *package = param;
5664 LPCWSTR compgroupid, component, feature, qualifier;
5668 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5671 feature = MSI_RecordGetString( rec, 5 );
5672 feat = msi_get_loaded_feature( package, feature );
5674 return ERROR_SUCCESS;
5676 feat->Action = msi_get_feature_action( package, feat );
5677 if (feat->Action != INSTALLSTATE_ABSENT)
5679 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5680 return ERROR_SUCCESS;
5683 component = MSI_RecordGetString( rec, 3 );
5684 comp = msi_get_loaded_component( package, component );
5686 return ERROR_SUCCESS;
5688 compgroupid = MSI_RecordGetString( rec, 1 );
5689 qualifier = MSI_RecordGetString( rec, 2 );
5691 squash_guid( compgroupid, squashed );
5692 strcpyW( keypath, szInstallerComponents );
5693 strcatW( keypath, squashed );
5695 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5696 if (res != ERROR_SUCCESS)
5698 WARN("Unable to delete component key %d\n", res);
5701 uirow = MSI_CreateRecord( 2 );
5702 MSI_RecordSetStringW( uirow, 1, compgroupid );
5703 MSI_RecordSetStringW( uirow, 2, qualifier );
5704 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5705 msiobj_release( &uirow->hdr );
5707 return ERROR_SUCCESS;
5710 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5712 static const WCHAR query[] = {
5713 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5714 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5718 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5719 if (rc != ERROR_SUCCESS)
5720 return ERROR_SUCCESS;
5722 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5723 msiobj_release( &view->hdr );
5727 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5729 static const WCHAR query[] =
5730 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5731 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5732 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5733 MSIPACKAGE *package = param;
5734 MSICOMPONENT *component;
5737 SC_HANDLE hscm = NULL, service = NULL;
5739 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5740 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5741 DWORD serv_type, start_type, err_control;
5742 SERVICE_DESCRIPTIONW sd = {NULL};
5743 UINT ret = ERROR_SUCCESS;
5745 comp = MSI_RecordGetString( rec, 12 );
5746 component = msi_get_loaded_component( package, comp );
5749 WARN("service component not found\n");
5752 component->Action = msi_get_component_action( package, component );
5753 if (component->Action != INSTALLSTATE_LOCAL)
5755 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5758 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5761 ERR("Failed to open the SC Manager!\n");
5765 start_type = MSI_RecordGetInteger(rec, 5);
5766 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5769 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5770 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5771 serv_type = MSI_RecordGetInteger(rec, 4);
5772 err_control = MSI_RecordGetInteger(rec, 6);
5773 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5774 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5775 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5776 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5777 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5778 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5780 /* fetch the service path */
5781 row = MSI_QueryGetRecord(package->db, query, comp);
5784 ERR("Query failed\n");
5787 key = MSI_RecordGetString(row, 6);
5788 file = msi_get_loaded_file(package, key);
5789 msiobj_release(&row->hdr);
5792 ERR("Failed to load the service file\n");
5796 if (!args || !args[0]) image_path = file->TargetPath;
5799 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5800 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5802 ret = ERROR_OUTOFMEMORY;
5806 strcpyW(image_path, file->TargetPath);
5807 strcatW(image_path, szSpace);
5808 strcatW(image_path, args);
5810 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5811 start_type, err_control, image_path, load_order,
5812 NULL, depends, serv_name, pass);
5816 if (GetLastError() != ERROR_SERVICE_EXISTS)
5817 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5819 else if (sd.lpDescription)
5821 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5822 WARN("failed to set service description %u\n", GetLastError());
5825 if (image_path != file->TargetPath) msi_free(image_path);
5827 CloseServiceHandle(service);
5828 CloseServiceHandle(hscm);
5831 msi_free(sd.lpDescription);
5832 msi_free(load_order);
5833 msi_free(serv_name);
5841 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5843 static const WCHAR query[] = {
5844 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5845 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5849 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5850 if (rc != ERROR_SUCCESS)
5851 return ERROR_SUCCESS;
5853 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5854 msiobj_release(&view->hdr);
5858 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5859 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5861 LPCWSTR *vector, *temp_vector;
5865 static const WCHAR separator[] = {'[','~',']',0};
5868 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5873 vector = msi_alloc(sizeof(LPWSTR));
5881 vector[*numargs - 1] = p;
5883 if ((q = strstrW(p, separator)))
5887 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5893 vector = temp_vector;
5902 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5904 MSIPACKAGE *package = param;
5907 SC_HANDLE scm = NULL, service = NULL;
5908 LPCWSTR component, *vector = NULL;
5909 LPWSTR name, args, display_name = NULL;
5910 DWORD event, numargs, len, wait, dummy;
5911 UINT r = ERROR_FUNCTION_FAILED;
5912 SERVICE_STATUS_PROCESS status;
5913 ULONGLONG start_time;
5915 component = MSI_RecordGetString(rec, 6);
5916 comp = msi_get_loaded_component(package, component);
5918 return ERROR_SUCCESS;
5920 comp->Action = msi_get_component_action( package, comp );
5921 if (comp->Action != INSTALLSTATE_LOCAL)
5923 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5924 return ERROR_SUCCESS;
5927 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5928 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5929 event = MSI_RecordGetInteger(rec, 3);
5930 wait = MSI_RecordGetInteger(rec, 5);
5932 if (!(event & msidbServiceControlEventStart))
5938 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5941 ERR("Failed to open the service control manager\n");
5946 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5947 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5949 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5950 GetServiceDisplayNameW( scm, name, display_name, &len );
5953 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5956 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5960 vector = msi_service_args_to_vector(args, &numargs);
5962 if (!StartServiceW(service, numargs, vector) &&
5963 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5965 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5972 /* wait for at most 30 seconds for the service to be up and running */
5973 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5974 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5976 TRACE("failed to query service status (%u)\n", GetLastError());
5979 start_time = GetTickCount64();
5980 while (status.dwCurrentState == SERVICE_START_PENDING)
5982 if (GetTickCount64() - start_time > 30000) break;
5984 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5985 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5987 TRACE("failed to query service status (%u)\n", GetLastError());
5991 if (status.dwCurrentState != SERVICE_RUNNING)
5993 WARN("service failed to start %u\n", status.dwCurrentState);
5994 r = ERROR_FUNCTION_FAILED;
5999 uirow = MSI_CreateRecord( 2 );
6000 MSI_RecordSetStringW( uirow, 1, display_name );
6001 MSI_RecordSetStringW( uirow, 2, name );
6002 msi_ui_actiondata( package, szStartServices, uirow );
6003 msiobj_release( &uirow->hdr );
6005 CloseServiceHandle(service);
6006 CloseServiceHandle(scm);
6011 msi_free(display_name);
6015 static UINT ACTION_StartServices( MSIPACKAGE *package )
6017 static const WCHAR query[] = {
6018 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6019 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6023 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6024 if (rc != ERROR_SUCCESS)
6025 return ERROR_SUCCESS;
6027 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
6028 msiobj_release(&view->hdr);
6032 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6034 DWORD i, needed, count;
6035 ENUM_SERVICE_STATUSW *dependencies;
6038 BOOL stopped, ret = FALSE;
6040 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6041 0, &needed, &count))
6044 if (GetLastError() != ERROR_MORE_DATA)
6047 dependencies = msi_alloc(needed);
6051 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6052 needed, &needed, &count))
6055 for (i = 0; i < count; i++)
6057 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6058 SERVICE_STOP | SERVICE_QUERY_STATUS);
6062 stopped = ControlService(depserv, SERVICE_CONTROL_STOP, &ss);
6063 CloseServiceHandle(depserv);
6071 msi_free(dependencies);
6075 static UINT stop_service( LPCWSTR name )
6077 SC_HANDLE scm = NULL, service = NULL;
6078 SERVICE_STATUS status;
6079 SERVICE_STATUS_PROCESS ssp;
6082 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6085 WARN("Failed to open the SCM: %d\n", GetLastError());
6089 service = OpenServiceW(scm, name,
6091 SERVICE_QUERY_STATUS |
6092 SERVICE_ENUMERATE_DEPENDENTS);
6095 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
6099 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
6100 sizeof(SERVICE_STATUS_PROCESS), &needed))
6102 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
6106 if (ssp.dwCurrentState == SERVICE_STOPPED)
6109 stop_service_dependents(scm, service);
6111 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6112 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
6115 CloseServiceHandle(service);
6116 CloseServiceHandle(scm);
6118 return ERROR_SUCCESS;
6121 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6123 MSIPACKAGE *package = param;
6127 LPWSTR name = NULL, display_name = NULL;
6131 event = MSI_RecordGetInteger( rec, 3 );
6132 if (!(event & msidbServiceControlEventStop))
6133 return ERROR_SUCCESS;
6135 component = MSI_RecordGetString( rec, 6 );
6136 comp = msi_get_loaded_component( package, component );
6138 return ERROR_SUCCESS;
6140 comp->Action = msi_get_component_action( package, comp );
6141 if (comp->Action != INSTALLSTATE_ABSENT)
6143 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6144 return ERROR_SUCCESS;
6147 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6150 ERR("Failed to open the service control manager\n");
6155 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6156 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6158 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6159 GetServiceDisplayNameW( scm, name, display_name, &len );
6161 CloseServiceHandle( scm );
6163 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6164 stop_service( name );
6167 uirow = MSI_CreateRecord( 2 );
6168 MSI_RecordSetStringW( uirow, 1, display_name );
6169 MSI_RecordSetStringW( uirow, 2, name );
6170 msi_ui_actiondata( package, szStopServices, uirow );
6171 msiobj_release( &uirow->hdr );
6174 msi_free( display_name );
6175 return ERROR_SUCCESS;
6178 static UINT ACTION_StopServices( MSIPACKAGE *package )
6180 static const WCHAR query[] = {
6181 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6182 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6186 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6187 if (rc != ERROR_SUCCESS)
6188 return ERROR_SUCCESS;
6190 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6191 msiobj_release(&view->hdr);
6195 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6197 MSIPACKAGE *package = param;
6200 LPWSTR name = NULL, display_name = NULL;
6202 SC_HANDLE scm = NULL, service = NULL;
6204 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6206 return ERROR_SUCCESS;
6208 event = MSI_RecordGetInteger( rec, 3 );
6209 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6211 comp->Action = msi_get_component_action( package, comp );
6212 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6213 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6215 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6217 return ERROR_SUCCESS;
6219 stop_service( name );
6221 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6224 WARN("Failed to open the SCM: %d\n", GetLastError());
6229 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6230 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6232 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6233 GetServiceDisplayNameW( scm, name, display_name, &len );
6236 service = OpenServiceW( scm, name, DELETE );
6239 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6243 if (!DeleteService( service ))
6244 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6247 uirow = MSI_CreateRecord( 2 );
6248 MSI_RecordSetStringW( uirow, 1, display_name );
6249 MSI_RecordSetStringW( uirow, 2, name );
6250 msi_ui_actiondata( package, szDeleteServices, uirow );
6251 msiobj_release( &uirow->hdr );
6253 CloseServiceHandle( service );
6254 CloseServiceHandle( scm );
6256 msi_free( display_name );
6258 return ERROR_SUCCESS;
6261 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6263 static const WCHAR query[] = {
6264 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6265 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6269 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6270 if (rc != ERROR_SUCCESS)
6271 return ERROR_SUCCESS;
6273 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6274 msiobj_release( &view->hdr );
6278 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6280 MSIPACKAGE *package = param;
6281 LPWSTR driver, driver_path, ptr;
6282 WCHAR outpath[MAX_PATH];
6283 MSIFILE *driver_file = NULL, *setup_file = NULL;
6286 LPCWSTR desc, file_key, component;
6288 UINT r = ERROR_SUCCESS;
6290 static const WCHAR driver_fmt[] = {
6291 'D','r','i','v','e','r','=','%','s',0};
6292 static const WCHAR setup_fmt[] = {
6293 'S','e','t','u','p','=','%','s',0};
6294 static const WCHAR usage_fmt[] = {
6295 'F','i','l','e','U','s','a','g','e','=','1',0};
6297 component = MSI_RecordGetString( rec, 2 );
6298 comp = msi_get_loaded_component( package, component );
6300 return ERROR_SUCCESS;
6302 comp->Action = msi_get_component_action( package, comp );
6303 if (comp->Action != INSTALLSTATE_LOCAL)
6305 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6306 return ERROR_SUCCESS;
6308 desc = MSI_RecordGetString(rec, 3);
6310 file_key = MSI_RecordGetString( rec, 4 );
6311 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6313 file_key = MSI_RecordGetString( rec, 5 );
6314 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6318 ERR("ODBC Driver entry not found!\n");
6319 return ERROR_FUNCTION_FAILED;
6322 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6324 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6325 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6327 driver = msi_alloc(len * sizeof(WCHAR));
6329 return ERROR_OUTOFMEMORY;
6332 lstrcpyW(ptr, desc);
6333 ptr += lstrlenW(ptr) + 1;
6335 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6340 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6344 lstrcpyW(ptr, usage_fmt);
6345 ptr += lstrlenW(ptr) + 1;
6348 if (!driver_file->TargetPath)
6350 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6351 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6353 driver_path = strdupW(driver_file->TargetPath);
6354 ptr = strrchrW(driver_path, '\\');
6355 if (ptr) *ptr = '\0';
6357 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6358 NULL, ODBC_INSTALL_COMPLETE, &usage))
6360 ERR("Failed to install SQL driver!\n");
6361 r = ERROR_FUNCTION_FAILED;
6364 uirow = MSI_CreateRecord( 5 );
6365 MSI_RecordSetStringW( uirow, 1, desc );
6366 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6367 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6368 msi_ui_actiondata( package, szInstallODBC, uirow );
6369 msiobj_release( &uirow->hdr );
6372 msi_free(driver_path);
6377 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6379 MSIPACKAGE *package = param;
6380 LPWSTR translator, translator_path, ptr;
6381 WCHAR outpath[MAX_PATH];
6382 MSIFILE *translator_file = NULL, *setup_file = NULL;
6385 LPCWSTR desc, file_key, component;
6387 UINT r = ERROR_SUCCESS;
6389 static const WCHAR translator_fmt[] = {
6390 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6391 static const WCHAR setup_fmt[] = {
6392 'S','e','t','u','p','=','%','s',0};
6394 component = MSI_RecordGetString( rec, 2 );
6395 comp = msi_get_loaded_component( package, component );
6397 return ERROR_SUCCESS;
6399 comp->Action = msi_get_component_action( package, comp );
6400 if (comp->Action != INSTALLSTATE_LOCAL)
6402 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6403 return ERROR_SUCCESS;
6405 desc = MSI_RecordGetString(rec, 3);
6407 file_key = MSI_RecordGetString( rec, 4 );
6408 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6410 file_key = MSI_RecordGetString( rec, 5 );
6411 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6413 if (!translator_file)
6415 ERR("ODBC Translator entry not found!\n");
6416 return ERROR_FUNCTION_FAILED;
6419 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6421 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6423 translator = msi_alloc(len * sizeof(WCHAR));
6425 return ERROR_OUTOFMEMORY;
6428 lstrcpyW(ptr, desc);
6429 ptr += lstrlenW(ptr) + 1;
6431 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6436 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6441 translator_path = strdupW(translator_file->TargetPath);
6442 ptr = strrchrW(translator_path, '\\');
6443 if (ptr) *ptr = '\0';
6445 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6446 NULL, ODBC_INSTALL_COMPLETE, &usage))
6448 ERR("Failed to install SQL translator!\n");
6449 r = ERROR_FUNCTION_FAILED;
6452 uirow = MSI_CreateRecord( 5 );
6453 MSI_RecordSetStringW( uirow, 1, desc );
6454 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6455 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6456 msi_ui_actiondata( package, szInstallODBC, uirow );
6457 msiobj_release( &uirow->hdr );
6459 msi_free(translator);
6460 msi_free(translator_path);
6465 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6467 MSIPACKAGE *package = param;
6470 LPCWSTR desc, driver, component;
6471 WORD request = ODBC_ADD_SYS_DSN;
6474 UINT r = ERROR_SUCCESS;
6477 static const WCHAR attrs_fmt[] = {
6478 'D','S','N','=','%','s',0 };
6480 component = MSI_RecordGetString( rec, 2 );
6481 comp = msi_get_loaded_component( package, component );
6483 return ERROR_SUCCESS;
6485 comp->Action = msi_get_component_action( package, comp );
6486 if (comp->Action != INSTALLSTATE_LOCAL)
6488 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6489 return ERROR_SUCCESS;
6492 desc = MSI_RecordGetString(rec, 3);
6493 driver = MSI_RecordGetString(rec, 4);
6494 registration = MSI_RecordGetInteger(rec, 5);
6496 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6497 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6499 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6500 attrs = msi_alloc(len * sizeof(WCHAR));
6502 return ERROR_OUTOFMEMORY;
6504 len = sprintfW(attrs, attrs_fmt, desc);
6507 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6509 ERR("Failed to install SQL data source!\n");
6510 r = ERROR_FUNCTION_FAILED;
6513 uirow = MSI_CreateRecord( 5 );
6514 MSI_RecordSetStringW( uirow, 1, desc );
6515 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6516 MSI_RecordSetInteger( uirow, 3, request );
6517 msi_ui_actiondata( package, szInstallODBC, uirow );
6518 msiobj_release( &uirow->hdr );
6525 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6527 static const WCHAR driver_query[] = {
6528 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6529 'O','D','B','C','D','r','i','v','e','r',0};
6530 static const WCHAR translator_query[] = {
6531 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6532 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6533 static const WCHAR source_query[] = {
6534 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6535 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6539 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6540 if (rc == ERROR_SUCCESS)
6542 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6543 msiobj_release(&view->hdr);
6544 if (rc != ERROR_SUCCESS)
6547 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6548 if (rc == ERROR_SUCCESS)
6550 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6551 msiobj_release(&view->hdr);
6552 if (rc != ERROR_SUCCESS)
6555 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6556 if (rc == ERROR_SUCCESS)
6558 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6559 msiobj_release(&view->hdr);
6560 if (rc != ERROR_SUCCESS)
6563 return ERROR_SUCCESS;
6566 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6568 MSIPACKAGE *package = param;
6572 LPCWSTR desc, component;
6574 component = MSI_RecordGetString( rec, 2 );
6575 comp = msi_get_loaded_component( package, component );
6577 return ERROR_SUCCESS;
6579 comp->Action = msi_get_component_action( package, comp );
6580 if (comp->Action != INSTALLSTATE_ABSENT)
6582 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6583 return ERROR_SUCCESS;
6586 desc = MSI_RecordGetString( rec, 3 );
6587 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6589 WARN("Failed to remove ODBC driver\n");
6593 FIXME("Usage count reached 0\n");
6596 uirow = MSI_CreateRecord( 2 );
6597 MSI_RecordSetStringW( uirow, 1, desc );
6598 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6599 msi_ui_actiondata( package, szRemoveODBC, uirow );
6600 msiobj_release( &uirow->hdr );
6602 return ERROR_SUCCESS;
6605 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6607 MSIPACKAGE *package = param;
6611 LPCWSTR desc, component;
6613 component = MSI_RecordGetString( rec, 2 );
6614 comp = msi_get_loaded_component( package, component );
6616 return ERROR_SUCCESS;
6618 comp->Action = msi_get_component_action( package, comp );
6619 if (comp->Action != INSTALLSTATE_ABSENT)
6621 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6622 return ERROR_SUCCESS;
6625 desc = MSI_RecordGetString( rec, 3 );
6626 if (!SQLRemoveTranslatorW( desc, &usage ))
6628 WARN("Failed to remove ODBC translator\n");
6632 FIXME("Usage count reached 0\n");
6635 uirow = MSI_CreateRecord( 2 );
6636 MSI_RecordSetStringW( uirow, 1, desc );
6637 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6638 msi_ui_actiondata( package, szRemoveODBC, uirow );
6639 msiobj_release( &uirow->hdr );
6641 return ERROR_SUCCESS;
6644 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6646 MSIPACKAGE *package = param;
6650 LPCWSTR desc, driver, component;
6651 WORD request = ODBC_REMOVE_SYS_DSN;
6655 static const WCHAR attrs_fmt[] = {
6656 'D','S','N','=','%','s',0 };
6658 component = MSI_RecordGetString( rec, 2 );
6659 comp = msi_get_loaded_component( package, component );
6661 return ERROR_SUCCESS;
6663 comp->Action = msi_get_component_action( package, comp );
6664 if (comp->Action != INSTALLSTATE_ABSENT)
6666 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6667 return ERROR_SUCCESS;
6670 desc = MSI_RecordGetString( rec, 3 );
6671 driver = MSI_RecordGetString( rec, 4 );
6672 registration = MSI_RecordGetInteger( rec, 5 );
6674 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6675 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6677 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6678 attrs = msi_alloc( len * sizeof(WCHAR) );
6680 return ERROR_OUTOFMEMORY;
6682 FIXME("Use ODBCSourceAttribute table\n");
6684 len = sprintfW( attrs, attrs_fmt, desc );
6687 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6689 WARN("Failed to remove ODBC data source\n");
6693 uirow = MSI_CreateRecord( 3 );
6694 MSI_RecordSetStringW( uirow, 1, desc );
6695 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6696 MSI_RecordSetInteger( uirow, 3, request );
6697 msi_ui_actiondata( package, szRemoveODBC, uirow );
6698 msiobj_release( &uirow->hdr );
6700 return ERROR_SUCCESS;
6703 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6705 static const WCHAR driver_query[] = {
6706 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6707 'O','D','B','C','D','r','i','v','e','r',0};
6708 static const WCHAR translator_query[] = {
6709 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6710 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6711 static const WCHAR source_query[] = {
6712 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6713 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6717 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6718 if (rc == ERROR_SUCCESS)
6720 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6721 msiobj_release( &view->hdr );
6722 if (rc != ERROR_SUCCESS)
6725 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6726 if (rc == ERROR_SUCCESS)
6728 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6729 msiobj_release( &view->hdr );
6730 if (rc != ERROR_SUCCESS)
6733 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6734 if (rc == ERROR_SUCCESS)
6736 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6737 msiobj_release( &view->hdr );
6738 if (rc != ERROR_SUCCESS)
6741 return ERROR_SUCCESS;
6744 #define ENV_ACT_SETALWAYS 0x1
6745 #define ENV_ACT_SETABSENT 0x2
6746 #define ENV_ACT_REMOVE 0x4
6747 #define ENV_ACT_REMOVEMATCH 0x8
6749 #define ENV_MOD_MACHINE 0x20000000
6750 #define ENV_MOD_APPEND 0x40000000
6751 #define ENV_MOD_PREFIX 0x80000000
6752 #define ENV_MOD_MASK 0xC0000000
6754 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6756 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6758 LPCWSTR cptr = *name;
6760 static const WCHAR prefix[] = {'[','~',']',0};
6761 static const int prefix_len = 3;
6767 *flags |= ENV_ACT_SETALWAYS;
6768 else if (*cptr == '+')
6769 *flags |= ENV_ACT_SETABSENT;
6770 else if (*cptr == '-')
6771 *flags |= ENV_ACT_REMOVE;
6772 else if (*cptr == '!')
6773 *flags |= ENV_ACT_REMOVEMATCH;
6774 else if (*cptr == '*')
6775 *flags |= ENV_MOD_MACHINE;
6785 ERR("Missing environment variable\n");
6786 return ERROR_FUNCTION_FAILED;
6791 LPCWSTR ptr = *value;
6792 if (!strncmpW(ptr, prefix, prefix_len))
6794 if (ptr[prefix_len] == szSemiColon[0])
6796 *flags |= ENV_MOD_APPEND;
6797 *value += lstrlenW(prefix);
6804 else if (lstrlenW(*value) >= prefix_len)
6806 ptr += lstrlenW(ptr) - prefix_len;
6807 if (!strcmpW( ptr, prefix ))
6809 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6811 *flags |= ENV_MOD_PREFIX;
6812 /* the "[~]" will be removed by deformat_string */;
6822 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6823 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6824 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6825 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6827 ERR("Invalid flags: %08x\n", *flags);
6828 return ERROR_FUNCTION_FAILED;
6832 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6834 return ERROR_SUCCESS;
6837 static UINT open_env_key( DWORD flags, HKEY *key )
6839 static const WCHAR user_env[] =
6840 {'E','n','v','i','r','o','n','m','e','n','t',0};
6841 static const WCHAR machine_env[] =
6842 {'S','y','s','t','e','m','\\',
6843 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6844 'C','o','n','t','r','o','l','\\',
6845 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6846 'E','n','v','i','r','o','n','m','e','n','t',0};
6851 if (flags & ENV_MOD_MACHINE)
6854 root = HKEY_LOCAL_MACHINE;
6859 root = HKEY_CURRENT_USER;
6862 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6863 if (res != ERROR_SUCCESS)
6865 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6866 return ERROR_FUNCTION_FAILED;
6869 return ERROR_SUCCESS;
6872 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6874 MSIPACKAGE *package = param;
6875 LPCWSTR name, value, component;
6876 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6877 DWORD flags, type, size;
6884 component = MSI_RecordGetString(rec, 4);
6885 comp = msi_get_loaded_component(package, component);
6887 return ERROR_SUCCESS;
6889 comp->Action = msi_get_component_action( package, comp );
6890 if (comp->Action != INSTALLSTATE_LOCAL)
6892 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6893 return ERROR_SUCCESS;
6895 name = MSI_RecordGetString(rec, 2);
6896 value = MSI_RecordGetString(rec, 3);
6898 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6900 res = env_parse_flags(&name, &value, &flags);
6901 if (res != ERROR_SUCCESS || !value)
6904 if (value && !deformat_string(package, value, &deformatted))
6906 res = ERROR_OUTOFMEMORY;
6910 value = deformatted;
6912 res = open_env_key( flags, &env );
6913 if (res != ERROR_SUCCESS)
6916 if (flags & ENV_MOD_MACHINE)
6917 action |= 0x20000000;
6921 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6922 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6923 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6926 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6930 /* Nothing to do. */
6933 res = ERROR_SUCCESS;
6937 /* If we are appending but the string was empty, strip ; */
6938 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6940 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6941 newval = strdupW(value);
6944 res = ERROR_OUTOFMEMORY;
6952 /* Contrary to MSDN, +-variable to [~];path works */
6953 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6955 res = ERROR_SUCCESS;
6959 data = msi_alloc(size);
6963 return ERROR_OUTOFMEMORY;
6966 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6967 if (res != ERROR_SUCCESS)
6970 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6973 res = RegDeleteValueW(env, name);
6974 if (res != ERROR_SUCCESS)
6975 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6979 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6980 if (flags & ENV_MOD_MASK)
6984 if (flags & ENV_MOD_APPEND) multiplier++;
6985 if (flags & ENV_MOD_PREFIX) multiplier++;
6986 mod_size = lstrlenW(value) * multiplier;
6987 size += mod_size * sizeof(WCHAR);
6990 newval = msi_alloc(size);
6994 res = ERROR_OUTOFMEMORY;
6998 if (flags & ENV_MOD_PREFIX)
7000 lstrcpyW(newval, value);
7001 ptr = newval + lstrlenW(value);
7002 action |= 0x80000000;
7005 lstrcpyW(ptr, data);
7007 if (flags & ENV_MOD_APPEND)
7009 lstrcatW(newval, value);
7010 action |= 0x40000000;
7013 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
7014 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
7017 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7021 uirow = MSI_CreateRecord( 3 );
7022 MSI_RecordSetStringW( uirow, 1, name );
7023 MSI_RecordSetStringW( uirow, 2, newval );
7024 MSI_RecordSetInteger( uirow, 3, action );
7025 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
7026 msiobj_release( &uirow->hdr );
7028 if (env) RegCloseKey(env);
7029 msi_free(deformatted);
7035 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7037 static const WCHAR query[] = {
7038 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7039 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7043 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
7044 if (rc != ERROR_SUCCESS)
7045 return ERROR_SUCCESS;
7047 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7048 msiobj_release(&view->hdr);
7052 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7054 MSIPACKAGE *package = param;
7055 LPCWSTR name, value, component;
7056 LPWSTR deformatted = NULL;
7065 component = MSI_RecordGetString( rec, 4 );
7066 comp = msi_get_loaded_component( package, component );
7068 return ERROR_SUCCESS;
7070 comp->Action = msi_get_component_action( package, comp );
7071 if (comp->Action != INSTALLSTATE_ABSENT)
7073 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
7074 return ERROR_SUCCESS;
7076 name = MSI_RecordGetString( rec, 2 );
7077 value = MSI_RecordGetString( rec, 3 );
7079 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7081 r = env_parse_flags( &name, &value, &flags );
7082 if (r != ERROR_SUCCESS)
7085 if (!(flags & ENV_ACT_REMOVE))
7087 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7088 return ERROR_SUCCESS;
7091 if (value && !deformat_string( package, value, &deformatted ))
7092 return ERROR_OUTOFMEMORY;
7094 value = deformatted;
7096 r = open_env_key( flags, &env );
7097 if (r != ERROR_SUCCESS)
7103 if (flags & ENV_MOD_MACHINE)
7104 action |= 0x20000000;
7106 TRACE("Removing %s\n", debugstr_w(name));
7108 res = RegDeleteValueW( env, name );
7109 if (res != ERROR_SUCCESS)
7111 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
7116 uirow = MSI_CreateRecord( 3 );
7117 MSI_RecordSetStringW( uirow, 1, name );
7118 MSI_RecordSetStringW( uirow, 2, value );
7119 MSI_RecordSetInteger( uirow, 3, action );
7120 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
7121 msiobj_release( &uirow->hdr );
7123 if (env) RegCloseKey( env );
7124 msi_free( deformatted );
7128 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7130 static const WCHAR query[] = {
7131 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7132 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7136 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
7137 if (rc != ERROR_SUCCESS)
7138 return ERROR_SUCCESS;
7140 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7141 msiobj_release( &view->hdr );
7145 UINT msi_validate_product_id( MSIPACKAGE *package )
7147 LPWSTR key, template, id;
7148 UINT r = ERROR_SUCCESS;
7150 id = msi_dup_property( package->db, szProductID );
7154 return ERROR_SUCCESS;
7156 template = msi_dup_property( package->db, szPIDTemplate );
7157 key = msi_dup_property( package->db, szPIDKEY );
7158 if (key && template)
7160 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7161 r = msi_set_property( package->db, szProductID, key, -1 );
7163 msi_free( template );
7168 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7170 return msi_validate_product_id( package );
7173 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7176 package->need_reboot_at_end = 1;
7177 return ERROR_SUCCESS;
7180 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7182 static const WCHAR szAvailableFreeReg[] =
7183 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7185 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7187 TRACE("%p %d kilobytes\n", package, space);
7189 uirow = MSI_CreateRecord( 1 );
7190 MSI_RecordSetInteger( uirow, 1, space );
7191 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
7192 msiobj_release( &uirow->hdr );
7194 return ERROR_SUCCESS;
7197 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7199 TRACE("%p\n", package);
7201 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7202 return ERROR_SUCCESS;
7205 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7207 FIXME("%p\n", package);
7208 return ERROR_SUCCESS;
7211 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7213 static const WCHAR driver_query[] = {
7214 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7215 'O','D','B','C','D','r','i','v','e','r',0};
7216 static const WCHAR translator_query[] = {
7217 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7218 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
7222 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7223 if (r == ERROR_SUCCESS)
7226 r = MSI_IterateRecords( view, &count, NULL, package );
7227 msiobj_release( &view->hdr );
7228 if (r != ERROR_SUCCESS)
7230 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7232 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7233 if (r == ERROR_SUCCESS)
7236 r = MSI_IterateRecords( view, &count, NULL, package );
7237 msiobj_release( &view->hdr );
7238 if (r != ERROR_SUCCESS)
7240 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7242 return ERROR_SUCCESS;
7245 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7247 static const WCHAR fmtW[] =
7248 {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0};
7249 MSIPACKAGE *package = param;
7250 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7251 int attrs = MSI_RecordGetInteger( rec, 5 );
7252 UINT len = sizeof(fmtW)/sizeof(fmtW[0]);
7253 WCHAR *product, *features, *cmd;
7255 PROCESS_INFORMATION info;
7258 if (attrs & msidbUpgradeAttributesOnlyDetect) return ERROR_SUCCESS;
7259 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7261 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7263 len += strlenW( product );
7265 len += strlenW( features );
7267 len += sizeof(szAll) / sizeof(szAll[0]);
7269 if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
7271 msi_free( product );
7272 msi_free( features );
7273 return ERROR_OUTOFMEMORY;
7275 sprintfW( cmd, fmtW, product, features ? features : szAll );
7276 msi_free( product );
7277 msi_free( features );
7279 memset( &si, 0, sizeof(STARTUPINFOW) );
7280 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7282 if (!ret) return GetLastError();
7283 CloseHandle( info.hThread );
7285 WaitForSingleObject( info.hProcess, INFINITE );
7286 CloseHandle( info.hProcess );
7287 return ERROR_SUCCESS;
7290 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7292 static const WCHAR query[] = {
7293 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7297 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7298 if (r == ERROR_SUCCESS)
7300 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7301 msiobj_release( &view->hdr );
7302 if (r != ERROR_SUCCESS)
7305 return ERROR_SUCCESS;
7308 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7310 MSIPACKAGE *package = param;
7311 int attributes = MSI_RecordGetInteger( rec, 5 );
7313 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7315 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7316 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7317 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7318 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7322 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7324 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7325 if (r != ERROR_SUCCESS)
7326 return ERROR_SUCCESS;
7330 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7331 if (r != ERROR_SUCCESS)
7332 return ERROR_SUCCESS;
7334 RegCloseKey( hkey );
7336 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7337 debugstr_w(upgrade_code), debugstr_w(version_min),
7338 debugstr_w(version_max), debugstr_w(language));
7340 return ERROR_SUCCESS;
7343 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7345 static const WCHAR query[] = {
7346 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7347 'U','p','g','r','a','d','e',0};
7351 if (msi_get_property_int( package->db, szInstalled, 0 ))
7353 TRACE("product is installed, skipping action\n");
7354 return ERROR_SUCCESS;
7356 if (msi_get_property_int( package->db, szPreselected, 0 ))
7358 TRACE("Preselected property is set, not migrating feature states\n");
7359 return ERROR_SUCCESS;
7361 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7362 if (r == ERROR_SUCCESS)
7364 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7365 msiobj_release( &view->hdr );
7366 if (r != ERROR_SUCCESS)
7369 return ERROR_SUCCESS;
7372 static void bind_image( const char *filename, const char *path )
7374 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7376 WARN("failed to bind image %u\n", GetLastError());
7380 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7384 MSIPACKAGE *package = param;
7385 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7386 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7387 char *filenameA, *pathA;
7388 WCHAR *pathW, **path_list;
7390 if (!(file = msi_get_loaded_file( package, key )))
7392 WARN("file %s not found\n", debugstr_w(key));
7393 return ERROR_SUCCESS;
7395 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7396 path_list = msi_split_string( paths, ';' );
7397 if (!path_list) bind_image( filenameA, NULL );
7400 for (i = 0; path_list[i] && path_list[i][0]; i++)
7402 deformat_string( package, path_list[i], &pathW );
7403 if ((pathA = strdupWtoA( pathW )))
7405 bind_image( filenameA, pathA );
7411 msi_free( path_list );
7412 msi_free( filenameA );
7413 return ERROR_SUCCESS;
7416 static UINT ACTION_BindImage( MSIPACKAGE *package )
7418 static const WCHAR query[] = {
7419 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7420 'B','i','n','d','I','m','a','g','e',0};
7424 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7425 if (r == ERROR_SUCCESS)
7427 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7428 msiobj_release( &view->hdr );
7429 if (r != ERROR_SUCCESS)
7432 return ERROR_SUCCESS;
7435 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7437 static const WCHAR query[] = {
7438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7443 r = MSI_OpenQuery( package->db, &view, query, table );
7444 if (r == ERROR_SUCCESS)
7446 r = MSI_IterateRecords(view, &count, NULL, package);
7447 msiobj_release(&view->hdr);
7448 if (r != ERROR_SUCCESS)
7451 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7452 return ERROR_SUCCESS;
7455 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7457 static const WCHAR table[] = {
7458 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7459 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7462 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7464 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7465 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7468 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7470 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7471 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7474 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7476 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7477 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7480 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7482 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7483 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7488 const WCHAR *action;
7489 UINT (*handler)(MSIPACKAGE *);
7490 const WCHAR *action_rollback;
7494 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7495 { szAppSearch, ACTION_AppSearch, NULL },
7496 { szBindImage, ACTION_BindImage, NULL },
7497 { szCCPSearch, ACTION_CCPSearch, NULL },
7498 { szCostFinalize, ACTION_CostFinalize, NULL },
7499 { szCostInitialize, ACTION_CostInitialize, NULL },
7500 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7501 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7502 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7503 { szDisableRollback, ACTION_DisableRollback, NULL },
7504 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7505 { szExecuteAction, ACTION_ExecuteAction, NULL },
7506 { szFileCost, ACTION_FileCost, NULL },
7507 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7508 { szForceReboot, ACTION_ForceReboot, NULL },
7509 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7510 { szInstallExecute, ACTION_InstallExecute, NULL },
7511 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7512 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7513 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7514 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7515 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7516 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7517 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7518 { szInstallValidate, ACTION_InstallValidate, NULL },
7519 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7520 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7521 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7522 { szMoveFiles, ACTION_MoveFiles, NULL },
7523 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7524 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7525 { szPatchFiles, ACTION_PatchFiles, NULL },
7526 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7527 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7528 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7529 { szPublishProduct, ACTION_PublishProduct, NULL },
7530 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7531 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7532 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7533 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7534 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7535 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7536 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7537 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7538 { szRegisterUser, ACTION_RegisterUser, NULL },
7539 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7540 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7541 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7542 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7543 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7544 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7545 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7546 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7547 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7548 { szResolveSource, ACTION_ResolveSource, NULL },
7549 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7550 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7551 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7552 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7553 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7554 { szStartServices, ACTION_StartServices, szStopServices },
7555 { szStopServices, ACTION_StopServices, szStartServices },
7556 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7557 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7558 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7559 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7560 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7561 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7562 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7563 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7564 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7565 { szValidateProductID, ACTION_ValidateProductID, NULL },
7566 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7567 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7568 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7569 { NULL, NULL, NULL }
7572 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7578 while (StandardActions[i].action != NULL)
7580 if (!strcmpW( StandardActions[i].action, action ))
7582 ui_actionstart( package, action );
7583 if (StandardActions[i].handler)
7585 ui_actioninfo( package, action, TRUE, 0 );
7586 *rc = StandardActions[i].handler( package );
7587 ui_actioninfo( package, action, FALSE, *rc );
7589 if (StandardActions[i].action_rollback && !package->need_rollback)
7591 TRACE("scheduling rollback action\n");
7592 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7597 FIXME("unhandled standard action %s\n", debugstr_w(action));
7598 *rc = ERROR_SUCCESS;
7608 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7610 UINT rc = ERROR_SUCCESS;
7613 TRACE("Performing action (%s)\n", debugstr_w(action));
7615 handled = ACTION_HandleStandardAction(package, action, &rc);
7618 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7622 WARN("unhandled msi action %s\n", debugstr_w(action));
7623 rc = ERROR_FUNCTION_NOT_CALLED;
7629 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7631 UINT rc = ERROR_SUCCESS;
7632 BOOL handled = FALSE;
7634 TRACE("Performing action (%s)\n", debugstr_w(action));
7636 package->action_progress_increment = 0;
7637 handled = ACTION_HandleStandardAction(package, action, &rc);
7640 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7642 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7647 WARN("unhandled msi action %s\n", debugstr_w(action));
7648 rc = ERROR_FUNCTION_NOT_CALLED;
7654 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7656 UINT rc = ERROR_SUCCESS;
7659 static const WCHAR query[] =
7660 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7661 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7662 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7663 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7664 static const WCHAR ui_query[] =
7665 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7666 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7667 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7668 ' ', '=',' ','%','i',0};
7670 if (needs_ui_sequence(package))
7671 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7673 row = MSI_QueryGetRecord(package->db, query, seq);
7677 LPCWSTR action, cond;
7679 TRACE("Running the actions\n");
7681 /* check conditions */
7682 cond = MSI_RecordGetString(row, 2);
7684 /* this is a hack to skip errors in the condition code */
7685 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7687 msiobj_release(&row->hdr);
7688 return ERROR_SUCCESS;
7691 action = MSI_RecordGetString(row, 1);
7694 ERR("failed to fetch action\n");
7695 msiobj_release(&row->hdr);
7696 return ERROR_FUNCTION_FAILED;
7699 if (needs_ui_sequence(package))
7700 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7702 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7704 msiobj_release(&row->hdr);
7710 /****************************************************
7711 * TOP level entry points
7712 *****************************************************/
7714 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7715 LPCWSTR szCommandLine )
7717 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7718 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7719 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7720 WCHAR *reinstall, *remove, *patch;
7724 msi_set_property( package->db, szAction, szInstall, -1 );
7726 package->script->InWhatSequence = SEQUENCE_INSTALL;
7733 dir = strdupW(szPackagePath);
7734 p = strrchrW(dir, '\\');
7738 file = szPackagePath + (p - dir);
7743 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7744 GetCurrentDirectoryW(MAX_PATH, dir);
7745 lstrcatW(dir, szBackSlash);
7746 file = szPackagePath;
7749 msi_free( package->PackagePath );
7750 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7751 if (!package->PackagePath)
7754 return ERROR_OUTOFMEMORY;
7757 lstrcpyW(package->PackagePath, dir);
7758 lstrcatW(package->PackagePath, file);
7761 msi_set_sourcedir_props(package, FALSE);
7764 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7765 if (rc != ERROR_SUCCESS)
7768 msi_apply_transforms( package );
7769 msi_apply_patches( package );
7771 patch = msi_dup_property( package->db, szPatch );
7772 remove = msi_dup_property( package->db, szRemove );
7773 reinstall = msi_dup_property( package->db, szReinstall );
7774 if (msi_get_property_int( package->db, szInstalled, 0 ) && !remove && !reinstall && !patch)
7776 TRACE("setting REINSTALL property to ALL\n");
7777 msi_set_property( package->db, szReinstall, szAll, -1 );
7778 package->full_reinstall = 1;
7781 /* properties may have been added by a transform */
7782 msi_clone_properties( package );
7783 msi_set_original_database_property( package->db, szPackagePath );
7785 msi_parse_command_line( package, szCommandLine, FALSE );
7786 msi_adjust_privilege_properties( package );
7787 msi_set_context( package );
7789 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7791 TRACE("disabling rollback\n");
7792 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7795 if (needs_ui_sequence( package))
7797 package->script->InWhatSequence |= SEQUENCE_UI;
7798 rc = ACTION_ProcessUISequence(package);
7799 ui_exists = ui_sequence_exists(package);
7800 if (rc == ERROR_SUCCESS || !ui_exists)
7802 package->script->InWhatSequence |= SEQUENCE_EXEC;
7803 rc = ACTION_ProcessExecSequence(package, ui_exists);
7807 rc = ACTION_ProcessExecSequence(package, FALSE);
7809 package->script->CurrentlyScripting = FALSE;
7811 /* process the ending type action */
7812 if (rc == ERROR_SUCCESS)
7813 ACTION_PerformActionSequence(package, -1);
7814 else if (rc == ERROR_INSTALL_USEREXIT)
7815 ACTION_PerformActionSequence(package, -2);
7816 else if (rc == ERROR_INSTALL_SUSPEND)
7817 ACTION_PerformActionSequence(package, -4);
7820 ACTION_PerformActionSequence(package, -3);
7821 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7823 package->need_rollback = TRUE;
7827 /* finish up running custom actions */
7828 ACTION_FinishCustomActions(package);
7830 if (package->need_rollback && !reinstall)
7832 WARN("installation failed, running rollback script\n");
7833 execute_script( package, SCRIPT_ROLLBACK );
7835 msi_free( reinstall );
7839 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7840 return ERROR_SUCCESS_REBOOT_REQUIRED;