2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
191 sprintfW(message,template_s,timet,action);
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
221 case state_whitespace:
231 if (in_quotes && p[1] != '\"') count--;
247 if (in_quotes) count--;
251 state = state_whitespace;
252 if (!count) goto done;
257 if (!count) in_quotes = 0;
268 if (in_quotes && p[1] != '\"') count--;
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
279 if (!count) in_quotes = 0;
288 if (!ignore) *out++ = *p;
292 if (!len) *value = 0;
299 static void remove_quotes( WCHAR *str )
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
321 return ERROR_SUCCESS;
326 while (*ptr == ' ') ptr++;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
338 if (!preserve_case) struprW( prop );
341 while (*ptr2 == ' ') ptr2++;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
348 WARN("unbalanced quotes\n");
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val, -1 );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
372 LPWSTR p, *ret = NULL;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
395 for( count = 0; (ret[count] = p); count++ )
397 p = strchrW( p, sep );
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 db = msi_dup_property( package->db, szOriginalDatabase );
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
448 p = strrchrW( db, '/' );
452 return ERROR_SUCCESS;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source, -1 );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source, -1 );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
543 rc = ACTION_ForceReboot( package );
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property( package->db, szSourceDir, NULL, -1 );
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
736 if (!(slash = strrchrW( new_path, '\\' )))
741 len = slash - new_path;
743 if (!msi_create_full_path( new_path ))
748 new_path[len] = '\\';
750 msi_free( new_path );
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
814 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
815 return INSTALLSTATE_UNKNOWN;
817 return comp->ActionRequest;
820 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
822 if (package->need_rollback) return feature->Installed;
823 return feature->ActionRequest;
826 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
828 MSIPACKAGE *package = param;
829 LPCWSTR dir, component, full_path;
834 component = MSI_RecordGetString(row, 2);
836 return ERROR_SUCCESS;
838 comp = msi_get_loaded_component(package, component);
840 return ERROR_SUCCESS;
842 comp->Action = msi_get_component_action( package, comp );
843 if (comp->Action != INSTALLSTATE_LOCAL)
845 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
846 return ERROR_SUCCESS;
849 dir = MSI_RecordGetString(row,1);
852 ERR("Unable to get folder id\n");
853 return ERROR_SUCCESS;
856 uirow = MSI_CreateRecord(1);
857 MSI_RecordSetStringW(uirow, 1, dir);
858 msi_ui_actiondata(package, szCreateFolders, uirow);
859 msiobj_release(&uirow->hdr);
861 full_path = msi_get_target_folder( package, dir );
864 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
865 return ERROR_SUCCESS;
867 TRACE("folder is %s\n", debugstr_w(full_path));
869 folder = msi_get_loaded_folder( package, dir );
870 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
871 folder->State = FOLDER_STATE_CREATED;
872 return ERROR_SUCCESS;
875 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
877 static const WCHAR query[] = {
878 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
879 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
883 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
884 if (rc != ERROR_SUCCESS)
885 return ERROR_SUCCESS;
887 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
888 msiobj_release(&view->hdr);
892 static void remove_persistent_folder( MSIFOLDER *folder )
896 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
898 remove_persistent_folder( fl->folder );
900 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
902 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
906 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
908 MSIPACKAGE *package = param;
909 LPCWSTR dir, component, full_path;
914 component = MSI_RecordGetString(row, 2);
916 return ERROR_SUCCESS;
918 comp = msi_get_loaded_component(package, component);
920 return ERROR_SUCCESS;
922 comp->Action = msi_get_component_action( package, comp );
923 if (comp->Action != INSTALLSTATE_ABSENT)
925 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
926 return ERROR_SUCCESS;
929 dir = MSI_RecordGetString( row, 1 );
932 ERR("Unable to get folder id\n");
933 return ERROR_SUCCESS;
936 full_path = msi_get_target_folder( package, dir );
939 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
940 return ERROR_SUCCESS;
942 TRACE("folder is %s\n", debugstr_w(full_path));
944 uirow = MSI_CreateRecord( 1 );
945 MSI_RecordSetStringW( uirow, 1, dir );
946 msi_ui_actiondata( package, szRemoveFolders, uirow );
947 msiobj_release( &uirow->hdr );
949 folder = msi_get_loaded_folder( package, dir );
950 remove_persistent_folder( folder );
951 return ERROR_SUCCESS;
954 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
956 static const WCHAR query[] = {
957 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
958 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
962 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
963 if (rc != ERROR_SUCCESS)
964 return ERROR_SUCCESS;
966 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
967 msiobj_release( &view->hdr );
971 static UINT load_component( MSIRECORD *row, LPVOID param )
973 MSIPACKAGE *package = param;
976 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
978 return ERROR_FUNCTION_FAILED;
980 list_add_tail( &package->components, &comp->entry );
982 /* fill in the data */
983 comp->Component = msi_dup_record_field( row, 1 );
985 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
987 comp->ComponentId = msi_dup_record_field( row, 2 );
988 comp->Directory = msi_dup_record_field( row, 3 );
989 comp->Attributes = MSI_RecordGetInteger(row,4);
990 comp->Condition = msi_dup_record_field( row, 5 );
991 comp->KeyPath = msi_dup_record_field( row, 6 );
993 comp->Installed = INSTALLSTATE_UNKNOWN;
994 comp->Action = INSTALLSTATE_UNKNOWN;
995 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
997 comp->assembly = msi_load_assembly( package, comp );
998 return ERROR_SUCCESS;
1001 UINT msi_load_all_components( MSIPACKAGE *package )
1003 static const WCHAR query[] = {
1004 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1005 '`','C','o','m','p','o','n','e','n','t','`',0};
1009 if (!list_empty(&package->components))
1010 return ERROR_SUCCESS;
1012 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1013 if (r != ERROR_SUCCESS)
1016 if (!msi_init_assembly_caches( package ))
1018 ERR("can't initialize assembly caches\n");
1019 msiobj_release( &view->hdr );
1020 return ERROR_FUNCTION_FAILED;
1023 r = MSI_IterateRecords(view, NULL, load_component, package);
1024 msiobj_release(&view->hdr);
1029 MSIPACKAGE *package;
1030 MSIFEATURE *feature;
1033 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1037 cl = msi_alloc( sizeof (*cl) );
1039 return ERROR_NOT_ENOUGH_MEMORY;
1040 cl->component = comp;
1041 list_add_tail( &feature->Components, &cl->entry );
1043 return ERROR_SUCCESS;
1046 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1050 fl = msi_alloc( sizeof(*fl) );
1052 return ERROR_NOT_ENOUGH_MEMORY;
1053 fl->feature = child;
1054 list_add_tail( &parent->Children, &fl->entry );
1056 return ERROR_SUCCESS;
1059 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1061 _ilfs* ilfs = param;
1065 component = MSI_RecordGetString(row,1);
1067 /* check to see if the component is already loaded */
1068 comp = msi_get_loaded_component( ilfs->package, component );
1071 WARN("ignoring unknown component %s\n", debugstr_w(component));
1072 return ERROR_SUCCESS;
1074 add_feature_component( ilfs->feature, comp );
1075 comp->Enabled = TRUE;
1077 return ERROR_SUCCESS;
1080 static UINT load_feature(MSIRECORD * row, LPVOID param)
1082 static const WCHAR query[] = {
1083 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1084 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1085 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1086 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1087 MSIPACKAGE *package = param;
1088 MSIFEATURE *feature;
1093 /* fill in the data */
1095 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1097 return ERROR_NOT_ENOUGH_MEMORY;
1099 list_init( &feature->Children );
1100 list_init( &feature->Components );
1102 feature->Feature = msi_dup_record_field( row, 1 );
1104 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1106 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1107 feature->Title = msi_dup_record_field( row, 3 );
1108 feature->Description = msi_dup_record_field( row, 4 );
1110 if (!MSI_RecordIsNull(row,5))
1111 feature->Display = MSI_RecordGetInteger(row,5);
1113 feature->Level= MSI_RecordGetInteger(row,6);
1114 feature->Directory = msi_dup_record_field( row, 7 );
1115 feature->Attributes = MSI_RecordGetInteger(row,8);
1117 feature->Installed = INSTALLSTATE_UNKNOWN;
1118 feature->Action = INSTALLSTATE_UNKNOWN;
1119 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1121 list_add_tail( &package->features, &feature->entry );
1123 /* load feature components */
1125 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1126 if (rc != ERROR_SUCCESS)
1127 return ERROR_SUCCESS;
1129 ilfs.package = package;
1130 ilfs.feature = feature;
1132 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1133 msiobj_release(&view->hdr);
1137 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1139 MSIPACKAGE *package = param;
1140 MSIFEATURE *parent, *child;
1142 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1144 return ERROR_FUNCTION_FAILED;
1146 if (!child->Feature_Parent)
1147 return ERROR_SUCCESS;
1149 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1151 return ERROR_FUNCTION_FAILED;
1153 add_feature_child( parent, child );
1154 return ERROR_SUCCESS;
1157 UINT msi_load_all_features( MSIPACKAGE *package )
1159 static const WCHAR query[] = {
1160 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1161 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1162 '`','D','i','s','p','l','a','y','`',0};
1166 if (!list_empty(&package->features))
1167 return ERROR_SUCCESS;
1169 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1170 if (r != ERROR_SUCCESS)
1173 r = MSI_IterateRecords( view, NULL, load_feature, package );
1174 if (r != ERROR_SUCCESS)
1176 msiobj_release( &view->hdr );
1179 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1180 msiobj_release( &view->hdr );
1184 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1195 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1197 static const WCHAR query[] = {
1198 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1199 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1200 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1201 MSIQUERY *view = NULL;
1202 MSIRECORD *row = NULL;
1205 TRACE("%s\n", debugstr_w(file->File));
1207 r = MSI_OpenQuery(package->db, &view, query, file->File);
1208 if (r != ERROR_SUCCESS)
1211 r = MSI_ViewExecute(view, NULL);
1212 if (r != ERROR_SUCCESS)
1215 r = MSI_ViewFetch(view, &row);
1216 if (r != ERROR_SUCCESS)
1219 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1220 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1221 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1222 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1223 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1226 if (view) msiobj_release(&view->hdr);
1227 if (row) msiobj_release(&row->hdr);
1231 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1234 static const WCHAR query[] = {
1235 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1236 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1237 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1239 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1242 WARN("query failed\n");
1243 return ERROR_FUNCTION_FAILED;
1246 file->disk_id = MSI_RecordGetInteger( row, 1 );
1247 msiobj_release( &row->hdr );
1248 return ERROR_SUCCESS;
1251 static UINT load_file(MSIRECORD *row, LPVOID param)
1253 MSIPACKAGE* package = param;
1257 /* fill in the data */
1259 file = msi_alloc_zero( sizeof (MSIFILE) );
1261 return ERROR_NOT_ENOUGH_MEMORY;
1263 file->File = msi_dup_record_field( row, 1 );
1265 component = MSI_RecordGetString( row, 2 );
1266 file->Component = msi_get_loaded_component( package, component );
1268 if (!file->Component)
1270 WARN("Component not found: %s\n", debugstr_w(component));
1271 msi_free(file->File);
1273 return ERROR_SUCCESS;
1276 file->FileName = msi_dup_record_field( row, 3 );
1277 msi_reduce_to_long_filename( file->FileName );
1279 file->ShortName = msi_dup_record_field( row, 3 );
1280 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1282 file->FileSize = MSI_RecordGetInteger( row, 4 );
1283 file->Version = msi_dup_record_field( row, 5 );
1284 file->Language = msi_dup_record_field( row, 6 );
1285 file->Attributes = MSI_RecordGetInteger( row, 7 );
1286 file->Sequence = MSI_RecordGetInteger( row, 8 );
1288 file->state = msifs_invalid;
1290 /* if the compressed bits are not set in the file attributes,
1291 * then read the information from the package word count property
1293 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1295 file->IsCompressed = FALSE;
1297 else if (file->Attributes &
1298 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1300 file->IsCompressed = TRUE;
1302 else if (file->Attributes & msidbFileAttributesNoncompressed)
1304 file->IsCompressed = FALSE;
1308 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1311 load_file_hash(package, file);
1312 load_file_disk_id(package, file);
1314 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1316 list_add_tail( &package->files, &file->entry );
1318 return ERROR_SUCCESS;
1321 static UINT load_all_files(MSIPACKAGE *package)
1323 static const WCHAR query[] = {
1324 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1325 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1326 '`','S','e','q','u','e','n','c','e','`', 0};
1330 if (!list_empty(&package->files))
1331 return ERROR_SUCCESS;
1333 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1334 if (rc != ERROR_SUCCESS)
1335 return ERROR_SUCCESS;
1337 rc = MSI_IterateRecords(view, NULL, load_file, package);
1338 msiobj_release(&view->hdr);
1342 static UINT load_media( MSIRECORD *row, LPVOID param )
1344 MSIPACKAGE *package = param;
1345 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1346 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1348 /* FIXME: load external cabinets and directory sources too */
1349 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1350 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1351 return ERROR_SUCCESS;
1354 static UINT load_all_media( MSIPACKAGE *package )
1356 static const WCHAR query[] = {
1357 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1358 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1359 '`','D','i','s','k','I','d','`',0};
1363 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1364 if (r != ERROR_SUCCESS)
1365 return ERROR_SUCCESS;
1367 r = MSI_IterateRecords( view, NULL, load_media, package );
1368 msiobj_release( &view->hdr );
1372 static UINT load_patch(MSIRECORD *row, LPVOID param)
1374 MSIPACKAGE *package = param;
1375 MSIFILEPATCH *patch;
1378 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1380 return ERROR_NOT_ENOUGH_MEMORY;
1382 file_key = msi_dup_record_field( row, 1 );
1383 patch->File = msi_get_loaded_file( package, file_key );
1388 ERR("Failed to find target for patch in File table\n");
1390 return ERROR_FUNCTION_FAILED;
1393 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1395 /* FIXME: The database should be properly transformed */
1396 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1398 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1399 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1400 patch->IsApplied = FALSE;
1403 * Header field - for patch validation.
1404 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1407 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1409 list_add_tail( &package->filepatches, &patch->entry );
1411 return ERROR_SUCCESS;
1414 static UINT load_all_patches(MSIPACKAGE *package)
1416 static const WCHAR query[] = {
1417 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1418 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1419 '`','S','e','q','u','e','n','c','e','`',0};
1423 if (!list_empty(&package->filepatches))
1424 return ERROR_SUCCESS;
1426 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1427 if (rc != ERROR_SUCCESS)
1428 return ERROR_SUCCESS;
1430 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1431 msiobj_release(&view->hdr);
1435 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1437 static const WCHAR query[] = {
1438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1439 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1440 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1443 folder->persistent = FALSE;
1444 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1446 if (!MSI_ViewExecute( view, NULL ))
1449 if (!MSI_ViewFetch( view, &rec ))
1451 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1452 folder->persistent = TRUE;
1453 msiobj_release( &rec->hdr );
1456 msiobj_release( &view->hdr );
1458 return ERROR_SUCCESS;
1461 static UINT load_folder( MSIRECORD *row, LPVOID param )
1463 MSIPACKAGE *package = param;
1464 static WCHAR szEmpty[] = { 0 };
1465 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1468 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1469 list_init( &folder->children );
1470 folder->Directory = msi_dup_record_field( row, 1 );
1471 folder->Parent = msi_dup_record_field( row, 2 );
1472 p = msi_dup_record_field(row, 3);
1474 TRACE("%s\n", debugstr_w(folder->Directory));
1476 /* split src and target dir */
1478 src_short = folder_split_path( p, ':' );
1480 /* split the long and short paths */
1481 tgt_long = folder_split_path( tgt_short, '|' );
1482 src_long = folder_split_path( src_short, '|' );
1484 /* check for no-op dirs */
1485 if (tgt_short && !strcmpW( szDot, tgt_short ))
1486 tgt_short = szEmpty;
1487 if (src_short && !strcmpW( szDot, src_short ))
1488 src_short = szEmpty;
1491 tgt_long = tgt_short;
1494 src_short = tgt_short;
1495 src_long = tgt_long;
1499 src_long = src_short;
1501 /* FIXME: use the target short path too */
1502 folder->TargetDefault = strdupW(tgt_long);
1503 folder->SourceShortPath = strdupW(src_short);
1504 folder->SourceLongPath = strdupW(src_long);
1507 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1508 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1509 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1511 load_folder_persistence( package, folder );
1513 list_add_tail( &package->folders, &folder->entry );
1514 return ERROR_SUCCESS;
1517 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1521 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1523 list_add_tail( &parent->children, &fl->entry );
1524 return ERROR_SUCCESS;
1527 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1529 MSIPACKAGE *package = param;
1530 MSIFOLDER *parent, *child;
1532 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1533 return ERROR_FUNCTION_FAILED;
1535 if (!child->Parent) return ERROR_SUCCESS;
1537 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1538 return ERROR_FUNCTION_FAILED;
1540 return add_folder_child( parent, child );
1543 static UINT load_all_folders( MSIPACKAGE *package )
1545 static const WCHAR query[] = {
1546 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1547 '`','D','i','r','e','c','t','o','r','y','`',0};
1551 if (!list_empty(&package->folders))
1552 return ERROR_SUCCESS;
1554 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1555 if (r != ERROR_SUCCESS)
1558 r = MSI_IterateRecords( view, NULL, load_folder, package );
1559 if (r != ERROR_SUCCESS)
1561 msiobj_release( &view->hdr );
1564 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1565 msiobj_release( &view->hdr );
1569 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1571 msi_set_property( package->db, szCostingComplete, szZero, -1 );
1572 msi_set_property( package->db, szRootDrive, szCRoot, -1 );
1574 load_all_folders( package );
1575 msi_load_all_components( package );
1576 msi_load_all_features( package );
1577 load_all_files( package );
1578 load_all_patches( package );
1579 load_all_media( package );
1581 return ERROR_SUCCESS;
1584 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1586 const WCHAR *action = package->script->Actions[script][index];
1587 ui_actionstart( package, action );
1588 TRACE("executing %s\n", debugstr_w(action));
1589 return ACTION_PerformAction( package, action, script );
1592 static UINT execute_script( MSIPACKAGE *package, UINT script )
1594 UINT i, rc = ERROR_SUCCESS;
1596 TRACE("executing script %u\n", script);
1598 if (!package->script)
1600 ERR("no script!\n");
1601 return ERROR_FUNCTION_FAILED;
1603 if (script == SCRIPT_ROLLBACK)
1605 for (i = package->script->ActionCount[script]; i > 0; i--)
1607 rc = execute_script_action( package, script, i - 1 );
1608 if (rc != ERROR_SUCCESS) break;
1613 for (i = 0; i < package->script->ActionCount[script]; i++)
1615 rc = execute_script_action( package, script, i );
1616 if (rc != ERROR_SUCCESS) break;
1619 msi_free_action_script(package, script);
1623 static UINT ACTION_FileCost(MSIPACKAGE *package)
1625 return ERROR_SUCCESS;
1628 static void get_client_counts( MSIPACKAGE *package )
1633 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1635 if (!comp->ComponentId) continue;
1637 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE ) &&
1638 MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ))
1640 comp->num_clients = 0;
1643 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
1644 NULL, NULL, NULL, NULL );
1645 RegCloseKey( hkey );
1649 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1654 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1656 if (!comp->ComponentId) continue;
1658 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1659 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1661 if (r == ERROR_SUCCESS) continue;
1663 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1664 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1666 if (r == ERROR_SUCCESS) continue;
1668 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1669 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1671 if (r == ERROR_SUCCESS) continue;
1673 comp->Installed = INSTALLSTATE_ABSENT;
1677 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1679 MSIFEATURE *feature;
1681 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1685 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1686 feature->Installed = INSTALLSTATE_ABSENT;
1688 feature->Installed = state;
1692 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1694 return (feature->Level > 0 && feature->Level <= level);
1697 static BOOL process_state_property(MSIPACKAGE* package, int level,
1698 LPCWSTR property, INSTALLSTATE state)
1701 MSIFEATURE *feature;
1703 override = msi_dup_property( package->db, property );
1707 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1709 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1712 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1714 if (!strcmpiW( override, szAll ))
1716 if (feature->Installed != state)
1718 feature->Action = state;
1719 feature->ActionRequest = state;
1724 LPWSTR ptr = override;
1725 LPWSTR ptr2 = strchrW(override,',');
1729 int len = ptr2 - ptr;
1731 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1732 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1734 if (feature->Installed != state)
1736 feature->Action = state;
1737 feature->ActionRequest = state;
1744 ptr2 = strchrW(ptr,',');
1755 static BOOL process_overrides( MSIPACKAGE *package, int level )
1757 static const WCHAR szAddLocal[] =
1758 {'A','D','D','L','O','C','A','L',0};
1759 static const WCHAR szAddSource[] =
1760 {'A','D','D','S','O','U','R','C','E',0};
1761 static const WCHAR szAdvertise[] =
1762 {'A','D','V','E','R','T','I','S','E',0};
1765 /* all these activation/deactivation things happen in order and things
1766 * later on the list override things earlier on the list.
1768 * 0 INSTALLLEVEL processing
1781 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1782 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1783 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1784 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1785 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1788 msi_set_property( package->db, szPreselected, szOne, -1 );
1793 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1796 MSICOMPONENT* component;
1797 MSIFEATURE *feature;
1799 TRACE("Checking Install Level\n");
1801 level = msi_get_property_int(package->db, szInstallLevel, 1);
1803 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1805 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1807 if (!is_feature_selected( feature, level )) continue;
1809 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1811 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1813 feature->Action = INSTALLSTATE_SOURCE;
1814 feature->ActionRequest = INSTALLSTATE_SOURCE;
1816 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1818 feature->Action = INSTALLSTATE_ADVERTISED;
1819 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1823 feature->Action = INSTALLSTATE_LOCAL;
1824 feature->ActionRequest = INSTALLSTATE_LOCAL;
1828 /* disable child features of unselected parent or follow parent */
1829 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1833 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1835 if (!is_feature_selected( feature, level ))
1837 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1838 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1840 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1842 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1843 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1844 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1845 fl->feature->Action = feature->Action;
1846 fl->feature->ActionRequest = feature->ActionRequest;
1851 else /* preselected */
1853 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1855 if (!is_feature_selected( feature, level )) continue;
1857 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1859 if (feature->Installed == INSTALLSTATE_ABSENT)
1861 feature->Action = INSTALLSTATE_UNKNOWN;
1862 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1866 feature->Action = feature->Installed;
1867 feature->ActionRequest = feature->Installed;
1871 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1875 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1877 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1878 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1880 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1881 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1882 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1883 fl->feature->Action = feature->Action;
1884 fl->feature->ActionRequest = feature->ActionRequest;
1890 /* now we want to set component state based based on feature state */
1891 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1895 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1896 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1897 feature->ActionRequest, feature->Action);
1899 if (!is_feature_selected( feature, level )) continue;
1901 /* features with components that have compressed files are made local */
1902 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1904 if (cl->component->ForceLocalState &&
1905 feature->ActionRequest == INSTALLSTATE_SOURCE)
1907 feature->Action = INSTALLSTATE_LOCAL;
1908 feature->ActionRequest = INSTALLSTATE_LOCAL;
1913 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1915 component = cl->component;
1917 switch (feature->ActionRequest)
1919 case INSTALLSTATE_ABSENT:
1920 component->anyAbsent = 1;
1922 case INSTALLSTATE_ADVERTISED:
1923 component->hasAdvertiseFeature = 1;
1925 case INSTALLSTATE_SOURCE:
1926 component->hasSourceFeature = 1;
1928 case INSTALLSTATE_LOCAL:
1929 component->hasLocalFeature = 1;
1931 case INSTALLSTATE_DEFAULT:
1932 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1933 component->hasAdvertiseFeature = 1;
1934 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1935 component->hasSourceFeature = 1;
1937 component->hasLocalFeature = 1;
1945 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1947 /* check if it's local or source */
1948 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1949 (component->hasLocalFeature || component->hasSourceFeature))
1951 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1952 !component->ForceLocalState)
1954 component->Action = INSTALLSTATE_SOURCE;
1955 component->ActionRequest = INSTALLSTATE_SOURCE;
1959 component->Action = INSTALLSTATE_LOCAL;
1960 component->ActionRequest = INSTALLSTATE_LOCAL;
1965 /* if any feature is local, the component must be local too */
1966 if (component->hasLocalFeature)
1968 component->Action = INSTALLSTATE_LOCAL;
1969 component->ActionRequest = INSTALLSTATE_LOCAL;
1972 if (component->hasSourceFeature)
1974 component->Action = INSTALLSTATE_SOURCE;
1975 component->ActionRequest = INSTALLSTATE_SOURCE;
1978 if (component->hasAdvertiseFeature)
1980 component->Action = INSTALLSTATE_ADVERTISED;
1981 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1984 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1985 if (component->anyAbsent && component->ComponentId)
1987 component->Action = INSTALLSTATE_ABSENT;
1988 component->ActionRequest = INSTALLSTATE_ABSENT;
1992 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1994 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1996 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1997 component->Action = INSTALLSTATE_LOCAL;
1998 component->ActionRequest = INSTALLSTATE_LOCAL;
2001 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2002 component->Installed == INSTALLSTATE_SOURCE &&
2003 component->hasSourceFeature)
2005 component->Action = INSTALLSTATE_UNKNOWN;
2006 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2009 TRACE("component %s (installed %d request %d action %d)\n",
2010 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2012 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
2013 component->num_clients++;
2014 else if (component->Action == INSTALLSTATE_ABSENT)
2015 component->num_clients--;
2018 return ERROR_SUCCESS;
2021 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2023 MSIPACKAGE *package = param;
2025 MSIFEATURE *feature;
2027 name = MSI_RecordGetString( row, 1 );
2029 feature = msi_get_loaded_feature( package, name );
2031 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2035 Condition = MSI_RecordGetString(row,3);
2037 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2039 int level = MSI_RecordGetInteger(row,2);
2040 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2041 feature->Level = level;
2044 return ERROR_SUCCESS;
2047 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2049 static const WCHAR name[] = {'\\',0};
2050 VS_FIXEDFILEINFO *ptr, *ret;
2052 DWORD versize, handle;
2055 versize = GetFileVersionInfoSizeW( filename, &handle );
2059 version = msi_alloc( versize );
2063 GetFileVersionInfoW( filename, 0, versize, version );
2065 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2067 msi_free( version );
2071 ret = msi_alloc( sz );
2072 memcpy( ret, ptr, sz );
2074 msi_free( version );
2078 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2082 msi_parse_version_string( version, &ms, &ls );
2084 if (fi->dwFileVersionMS > ms) return 1;
2085 else if (fi->dwFileVersionMS < ms) return -1;
2086 else if (fi->dwFileVersionLS > ls) return 1;
2087 else if (fi->dwFileVersionLS < ls) return -1;
2091 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2095 msi_parse_version_string( ver1, &ms1, NULL );
2096 msi_parse_version_string( ver2, &ms2, NULL );
2098 if (ms1 > ms2) return 1;
2099 else if (ms1 < ms2) return -1;
2103 DWORD msi_get_disk_file_size( LPCWSTR filename )
2108 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2109 if (file == INVALID_HANDLE_VALUE)
2110 return INVALID_FILE_SIZE;
2112 size = GetFileSize( file, NULL );
2113 TRACE("size is %u\n", size);
2114 CloseHandle( file );
2118 BOOL msi_file_hash_matches( MSIFILE *file )
2121 MSIFILEHASHINFO hash;
2123 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2124 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2125 if (r != ERROR_SUCCESS)
2128 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2131 static WCHAR *get_temp_dir( void )
2134 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2136 GetTempPathW( MAX_PATH, tmp );
2139 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2140 if (CreateDirectoryW( dir, NULL )) break;
2142 return strdupW( dir );
2146 * msi_build_directory_name()
2148 * This function is to save messing round with directory names
2149 * It handles adding backslashes between path segments,
2150 * and can add \ at the end of the directory name if told to.
2152 * It takes a variable number of arguments.
2153 * It always allocates a new string for the result, so make sure
2154 * to free the return value when finished with it.
2156 * The first arg is the number of path segments that follow.
2157 * The arguments following count are a list of path segments.
2158 * A path segment may be NULL.
2160 * Path segments will be added with a \ separating them.
2161 * A \ will not be added after the last segment, however if the
2162 * last segment is NULL, then the last character will be a \
2164 WCHAR *msi_build_directory_name( DWORD count, ... )
2170 va_start( va, count );
2171 for (i = 0; i < count; i++)
2173 const WCHAR *str = va_arg( va, const WCHAR * );
2174 if (str) sz += strlenW( str ) + 1;
2178 dir = msi_alloc( sz * sizeof(WCHAR) );
2181 va_start( va, count );
2182 for (i = 0; i < count; i++)
2184 const WCHAR *str = va_arg( va, const WCHAR * );
2186 strcatW( dir, str );
2187 if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2193 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2195 MSIASSEMBLY *assembly = file->Component->assembly;
2197 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2199 msi_free( file->TargetPath );
2200 if (assembly && !assembly->application)
2202 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2203 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2204 msi_track_tempfile( package, file->TargetPath );
2208 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2209 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2212 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2215 static UINT calculate_file_cost( MSIPACKAGE *package )
2217 VS_FIXEDFILEINFO *file_version;
2218 WCHAR *font_version;
2221 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2223 MSICOMPONENT *comp = file->Component;
2226 if (!comp->Enabled) continue;
2228 if (file->IsCompressed)
2229 comp->ForceLocalState = TRUE;
2231 set_target_path( package, file );
2233 if ((comp->assembly && !comp->assembly->installed) ||
2234 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2236 comp->Cost += file->FileSize;
2239 file_size = msi_get_disk_file_size( file->TargetPath );
2243 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2245 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2247 comp->Cost += file->FileSize - file_size;
2249 msi_free( file_version );
2252 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2254 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2256 comp->Cost += file->FileSize - file_size;
2258 msi_free( font_version );
2262 if (file_size != file->FileSize)
2264 comp->Cost += file->FileSize - file_size;
2267 return ERROR_SUCCESS;
2270 WCHAR *msi_normalize_path( const WCHAR *in )
2272 const WCHAR *p = in;
2274 int n, len = strlenW( in ) + 2;
2276 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2281 /* copy until the end of the string or a space */
2282 while (*p != ' ' && (*q = *p))
2285 /* reduce many backslashes to one */
2286 if (*p != '\\' || *q != '\\')
2290 /* quit at the end of the string */
2294 /* count the number of spaces */
2299 /* if it's leading or trailing space, skip it */
2300 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2302 else /* copy n spaces */
2303 while (n && (*q++ = *p++)) n--;
2305 while (q - ret > 0 && q[-1] == ' ') q--;
2306 if (q - ret > 0 && q[-1] != '\\')
2314 static WCHAR *get_install_location( MSIPACKAGE *package )
2319 if (!package->ProductCode) return NULL;
2320 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ))
2322 path = msi_reg_get_val_str( hkey, szInstallLocation );
2323 RegCloseKey( hkey );
2327 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2330 MSIFOLDER *folder, *parent, *child;
2331 WCHAR *path, *normalized_path;
2333 TRACE("resolving %s\n", debugstr_w(name));
2335 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2337 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2339 if (!(path = get_install_location( package )) &&
2340 (!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))))
2342 path = msi_dup_property( package->db, szRootDrive );
2345 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2347 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2349 parent = msi_get_loaded_folder( package, folder->Parent );
2350 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2353 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2355 normalized_path = msi_normalize_path( path );
2357 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2359 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2360 msi_free( normalized_path );
2363 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2364 msi_free( folder->ResolvedTarget );
2365 folder->ResolvedTarget = normalized_path;
2367 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2370 msi_resolve_target_folder( package, child->Directory, load_prop );
2372 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2375 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2377 static const WCHAR query[] = {
2378 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2379 '`','C','o','n','d','i','t','i','o','n','`',0};
2380 static const WCHAR szOutOfDiskSpace[] = {
2381 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2387 TRACE("Building directory properties\n");
2388 msi_resolve_target_folder( package, szTargetDir, TRUE );
2390 TRACE("Evaluating component conditions\n");
2391 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2393 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2395 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2396 comp->Enabled = FALSE;
2399 comp->Enabled = TRUE;
2401 get_client_counts( package );
2403 /* read components states from the registry */
2404 ACTION_GetComponentInstallStates(package);
2405 ACTION_GetFeatureInstallStates(package);
2407 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2409 TRACE("Evaluating feature conditions\n");
2411 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2412 if (rc == ERROR_SUCCESS)
2414 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2415 msiobj_release( &view->hdr );
2416 if (rc != ERROR_SUCCESS)
2421 TRACE("Calculating file cost\n");
2422 calculate_file_cost( package );
2424 msi_set_property( package->db, szCostingComplete, szOne, -1 );
2425 /* set default run level if not set */
2426 level = msi_dup_property( package->db, szInstallLevel );
2428 msi_set_property( package->db, szInstallLevel, szOne, -1 );
2431 /* FIXME: check volume disk space */
2432 msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
2434 return MSI_SetFeatureStates(package);
2437 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type, DWORD *size )
2443 *size = sizeof(WCHAR);
2445 if ((data = msi_alloc( *size ))) *(WCHAR *)data = 0;
2448 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2454 LPWSTR deformated = NULL;
2457 deformat_string(package, &value[2], &deformated);
2459 /* binary value type */
2463 *size = (strlenW(ptr)/2)+1;
2465 *size = strlenW(ptr)/2;
2467 data = msi_alloc(*size);
2473 /* if uneven pad with a zero in front */
2479 data[count] = (BYTE)strtol(byte,NULL,0);
2481 TRACE("Uneven byte count\n");
2489 data[count] = (BYTE)strtol(byte,NULL,0);
2492 msi_free(deformated);
2494 TRACE("Data %i bytes(%i)\n",*size,count);
2501 deformat_string(package, &value[1], &deformated);
2504 *size = sizeof(DWORD);
2505 data = msi_alloc(*size);
2511 if ( (*p < '0') || (*p > '9') )
2517 if (deformated[0] == '-')
2520 TRACE("DWORD %i\n",*(LPDWORD)data);
2522 msi_free(deformated);
2527 const WCHAR *ptr = value;
2531 if (value[0] == '#')
2534 if (value[1] == '%')
2537 *type = REG_EXPAND_SZ;
2540 len = deformat_string( package, ptr, (WCHAR **)&data );
2541 if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
2542 *size = (len + 1) * sizeof(WCHAR);
2547 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2554 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2556 *root_key = HKEY_LOCAL_MACHINE;
2561 *root_key = HKEY_CURRENT_USER;
2566 *root_key = HKEY_CLASSES_ROOT;
2570 *root_key = HKEY_CURRENT_USER;
2574 *root_key = HKEY_LOCAL_MACHINE;
2578 *root_key = HKEY_USERS;
2582 ERR("Unknown root %i\n", root);
2589 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2591 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2592 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2594 if ((is_64bit || is_wow64) &&
2595 !(comp->Attributes & msidbComponentAttributes64bit) &&
2596 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2601 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2602 if (!(path_32node = msi_alloc( size ))) return NULL;
2604 memcpy( path_32node, path, len * sizeof(WCHAR) );
2605 strcpyW( path_32node + len, szWow6432Node );
2606 strcatW( path_32node, szBackSlash );
2607 strcatW( path_32node, path + len );
2610 return strdupW( path );
2613 static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
2615 REGSAM access = KEY_ALL_ACCESS;
2616 WCHAR *subkey, *p, *q;
2617 HKEY hkey, ret = NULL;
2620 if (is_wow64) access |= KEY_WOW64_64KEY;
2622 if (!(subkey = strdupW( path ))) return NULL;
2624 if ((q = strchrW( p, '\\' ))) *q = 0;
2626 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2628 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2631 TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
2637 ret = open_key( hkey, q + 1, create );
2638 RegCloseKey( hkey );
2645 static BOOL is_special_entry( const WCHAR *name )
2647 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2650 static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count )
2652 const WCHAR *p = str;
2657 if (!str) return NULL;
2658 while ((p - str) < len)
2660 p += strlenW( p ) + 1;
2663 if (!(ret = msi_alloc( *count * sizeof(WCHAR *) ))) return NULL;
2665 while ((p - str) < len)
2667 if (!(ret[i] = strdupW( p )))
2669 for (; i >= 0; i--) msi_free( ret[i] );
2673 p += strlenW( p ) + 1;
2679 static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count,
2680 WCHAR **right, DWORD right_count, DWORD *size )
2685 *size = sizeof(WCHAR);
2686 for (i = 0; i < left_count; i++) *size += (strlenW( left[i] ) + 1) * sizeof(WCHAR);
2687 for (i = 0; i < right_count; i++) *size += (strlenW( right[i] ) + 1) * sizeof(WCHAR);
2689 if (!(ret = p = msi_alloc( *size ))) return NULL;
2691 for (i = 0; i < left_count; i++)
2693 strcpyW( p, left[i] );
2694 p += strlenW( p ) + 1;
2696 for (i = 0; i < right_count; i++)
2698 strcpyW( p, right[i] );
2699 p += strlenW( p ) + 1;
2705 static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
2706 WCHAR **new, DWORD new_count )
2708 DWORD ret = old_count;
2709 unsigned int i, j, k;
2711 for (i = 0; i < new_count; i++)
2713 for (j = 0; j < old_count; j++)
2715 if (old[j] && !strcmpW( new[i], old[j] ))
2718 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
2734 static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
2735 WCHAR **new, DWORD new_count, DWORD *size )
2739 case JOIN_OP_APPEND:
2740 old_count = remove_duplicate_values( old, old_count, new, new_count );
2741 return flatten_multi_string_values( old, old_count, new, new_count, size );
2743 case JOIN_OP_PREPEND:
2744 old_count = remove_duplicate_values( old, old_count, new, new_count );
2745 return flatten_multi_string_values( new, new_count, old, old_count, size );
2747 case JOIN_OP_REPLACE:
2748 return flatten_multi_string_values( new, new_count, NULL, 0, size );
2751 ERR("unhandled join op %u\n", op);
2756 static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size,
2757 BYTE *new_value, DWORD new_size, DWORD *size )
2759 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
2760 const WCHAR *new_ptr = NULL, *old_ptr = NULL;
2761 enum join_op op = JOIN_OP_REPLACE;
2762 WCHAR **old = NULL, **new = NULL;
2765 if (new_size / sizeof(WCHAR) - 1 > 1)
2767 new_ptr = (const WCHAR *)new_value;
2768 new_len = new_size / sizeof(WCHAR) - 1;
2770 if (!new_ptr[0] && new_ptr[new_len - 1])
2772 op = JOIN_OP_APPEND;
2776 else if (new_ptr[0] && !new_ptr[new_len - 1])
2778 op = JOIN_OP_PREPEND;
2781 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2783 op = JOIN_OP_REPLACE;
2787 new = split_multi_string_values( new_ptr, new_len, &new_count );
2789 if (old_size / sizeof(WCHAR) - 1 > 1)
2791 old_ptr = (const WCHAR *)old_value;
2792 old_len = old_size / sizeof(WCHAR) - 1;
2793 old = split_multi_string_values( old_ptr, old_len, &old_count );
2795 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
2796 for (i = 0; i < old_count; i++) msi_free( old[i] );
2797 for (i = 0; i < new_count; i++) msi_free( new[i] );
2803 static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
2806 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
2807 if (!(ret = msi_alloc( *size ))) return NULL;
2808 RegQueryValueExW( hkey, name, NULL, type, ret, size );
2812 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2814 MSIPACKAGE *package = param;
2815 BYTE *new_value, *old_value = NULL;
2816 HKEY root_key, hkey;
2817 DWORD type, old_type, new_size, old_size = 0;
2818 LPWSTR deformated, uikey, keypath;
2819 const WCHAR *szRoot, *component, *name, *key, *str;
2823 BOOL check_first = FALSE;
2826 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2828 component = MSI_RecordGetString(row, 6);
2829 comp = msi_get_loaded_component(package,component);
2831 return ERROR_SUCCESS;
2833 comp->Action = msi_get_component_action( package, comp );
2834 if (comp->Action != INSTALLSTATE_LOCAL)
2836 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2837 return ERROR_SUCCESS;
2840 name = MSI_RecordGetString(row, 4);
2841 if( MSI_RecordIsNull(row,5) && name )
2843 /* null values can have special meanings */
2844 if (name[0]=='-' && name[1] == 0)
2845 return ERROR_SUCCESS;
2846 if ((name[0] == '+' || name[0] == '*') && !name[1])
2850 root = MSI_RecordGetInteger(row,2);
2851 key = MSI_RecordGetString(row, 3);
2853 szRoot = get_root_key( package, root, &root_key );
2855 return ERROR_SUCCESS;
2857 deformat_string(package, key , &deformated);
2858 uikey = msi_alloc( (strlenW(deformated) + strlenW(szRoot) + 1) * sizeof(WCHAR) );
2859 strcpyW(uikey,szRoot);
2860 strcatW(uikey,deformated);
2862 keypath = get_keypath( comp, root_key, deformated );
2863 msi_free( deformated );
2864 if (!(hkey = open_key( root_key, keypath, TRUE )))
2866 ERR("Could not create key %s\n", debugstr_w(keypath));
2869 return ERROR_FUNCTION_FAILED;
2871 str = msi_record_get_string( row, 5, &len );
2872 if (str && len > strlenW( str ))
2874 type = REG_MULTI_SZ;
2875 new_size = (len + 1) * sizeof(WCHAR);
2876 new_value = (BYTE *)msi_strdupW( str, len );
2878 else new_value = parse_value( package, str, &type, &new_size );
2879 deformat_string(package, name, &deformated);
2881 if (!is_special_entry( name ))
2883 old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
2884 if (type == REG_MULTI_SZ)
2887 if (old_value && old_type != REG_MULTI_SZ)
2889 msi_free( old_value );
2893 new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size );
2894 msi_free( new_value );
2899 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2900 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2902 else if (!old_value)
2904 if (deformated || new_size)
2906 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2907 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2910 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
2914 uirow = MSI_CreateRecord(3);
2915 MSI_RecordSetStringW(uirow,2,deformated);
2916 MSI_RecordSetStringW(uirow,1,uikey);
2917 if (type == REG_SZ || type == REG_EXPAND_SZ)
2918 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
2919 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2920 msiobj_release( &uirow->hdr );
2922 msi_free(new_value);
2923 msi_free(old_value);
2924 msi_free(deformated);
2928 return ERROR_SUCCESS;
2931 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2933 static const WCHAR query[] = {
2934 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2935 '`','R','e','g','i','s','t','r','y','`',0};
2939 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2940 if (rc != ERROR_SUCCESS)
2941 return ERROR_SUCCESS;
2943 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2944 msiobj_release(&view->hdr);
2948 static void delete_key( HKEY root, const WCHAR *path )
2955 if (is_wow64) access |= KEY_WOW64_64KEY;
2957 if (!(subkey = strdupW( path ))) return;
2960 if ((p = strrchrW( subkey, '\\' ))) *p = 0;
2961 hkey = open_key( root, subkey, FALSE );
2964 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2966 res = RegDeleteKeyExW( root, subkey, access, 0 );
2969 TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
2972 if (p && p[1]) RegCloseKey( hkey );
2978 static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
2982 DWORD num_subkeys, num_values;
2984 if ((hkey = open_key( root, path, FALSE )))
2986 if ((res = RegDeleteValueW( hkey, value )))
2987 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2989 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2990 NULL, NULL, NULL, NULL );
2991 RegCloseKey( hkey );
2992 if (!res && !num_subkeys && !num_values)
2994 TRACE("removing empty key %s\n", debugstr_w(path));
2995 delete_key( root, path );
3000 static void delete_tree( HKEY root, const WCHAR *path )
3005 if (!(hkey = open_key( root, path, FALSE ))) return;
3006 res = RegDeleteTreeW( hkey, NULL );
3007 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
3008 delete_key( root, path );
3009 RegCloseKey( hkey );
3012 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
3014 MSIPACKAGE *package = param;
3015 LPCWSTR component, name, key_str, root_key_str;
3016 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3019 BOOL delete_key = FALSE;
3024 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
3026 component = MSI_RecordGetString( row, 6 );
3027 comp = msi_get_loaded_component( package, component );
3029 return ERROR_SUCCESS;
3031 comp->Action = msi_get_component_action( package, comp );
3032 if (comp->Action != INSTALLSTATE_ABSENT)
3034 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3035 return ERROR_SUCCESS;
3038 name = MSI_RecordGetString( row, 4 );
3039 if (MSI_RecordIsNull( row, 5 ) && name )
3041 if (name[0] == '+' && !name[1])
3042 return ERROR_SUCCESS;
3043 if ((name[0] == '-' || name[0] == '*') && !name[1])
3050 root = MSI_RecordGetInteger( row, 2 );
3051 key_str = MSI_RecordGetString( row, 3 );
3053 root_key_str = get_root_key( package, root, &hkey_root );
3055 return ERROR_SUCCESS;
3057 deformat_string( package, key_str, &deformated_key );
3058 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3059 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3060 strcpyW( ui_key_str, root_key_str );
3061 strcatW( ui_key_str, deformated_key );
3063 deformat_string( package, name, &deformated_name );
3065 keypath = get_keypath( comp, hkey_root, deformated_key );
3066 msi_free( deformated_key );
3067 if (delete_key) delete_tree( hkey_root, keypath );
3068 else delete_value( hkey_root, keypath, deformated_name );
3069 msi_free( keypath );
3071 uirow = MSI_CreateRecord( 2 );
3072 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3073 MSI_RecordSetStringW( uirow, 2, deformated_name );
3074 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3075 msiobj_release( &uirow->hdr );
3077 msi_free( ui_key_str );
3078 msi_free( deformated_name );
3079 return ERROR_SUCCESS;
3082 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
3084 MSIPACKAGE *package = param;
3085 LPCWSTR component, name, key_str, root_key_str;
3086 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3089 BOOL delete_key = FALSE;
3094 component = MSI_RecordGetString( row, 5 );
3095 comp = msi_get_loaded_component( package, component );
3097 return ERROR_SUCCESS;
3099 comp->Action = msi_get_component_action( package, comp );
3100 if (comp->Action != INSTALLSTATE_LOCAL)
3102 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3103 return ERROR_SUCCESS;
3106 if ((name = MSI_RecordGetString( row, 4 )))
3108 if (name[0] == '-' && !name[1])
3115 root = MSI_RecordGetInteger( row, 2 );
3116 key_str = MSI_RecordGetString( row, 3 );
3118 root_key_str = get_root_key( package, root, &hkey_root );
3120 return ERROR_SUCCESS;
3122 deformat_string( package, key_str, &deformated_key );
3123 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3124 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3125 strcpyW( ui_key_str, root_key_str );
3126 strcatW( ui_key_str, deformated_key );
3128 deformat_string( package, name, &deformated_name );
3130 keypath = get_keypath( comp, hkey_root, deformated_key );
3131 msi_free( deformated_key );
3132 if (delete_key) delete_tree( hkey_root, keypath );
3133 else delete_value( hkey_root, keypath, deformated_name );
3134 msi_free( keypath );
3136 uirow = MSI_CreateRecord( 2 );
3137 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3138 MSI_RecordSetStringW( uirow, 2, deformated_name );
3139 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3140 msiobj_release( &uirow->hdr );
3142 msi_free( ui_key_str );
3143 msi_free( deformated_name );
3144 return ERROR_SUCCESS;
3147 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3149 static const WCHAR registry_query[] = {
3150 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3151 '`','R','e','g','i','s','t','r','y','`',0};
3152 static const WCHAR remove_registry_query[] = {
3153 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3154 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
3158 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3159 if (rc == ERROR_SUCCESS)
3161 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3162 msiobj_release( &view->hdr );
3163 if (rc != ERROR_SUCCESS)
3166 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3167 if (rc == ERROR_SUCCESS)
3169 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3170 msiobj_release( &view->hdr );
3171 if (rc != ERROR_SUCCESS)
3174 return ERROR_SUCCESS;
3177 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3179 package->script->CurrentlyScripting = TRUE;
3181 return ERROR_SUCCESS;
3185 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3187 static const WCHAR query[]= {
3188 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3189 '`','R','e','g','i','s','t','r','y','`',0};
3191 DWORD total = 0, count = 0;
3193 MSIFEATURE *feature;
3197 TRACE("InstallValidate\n");
3199 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3200 if (rc == ERROR_SUCCESS)
3202 rc = MSI_IterateRecords( view, &count, NULL, package );
3203 msiobj_release( &view->hdr );
3204 if (rc != ERROR_SUCCESS)
3206 total += count * REG_PROGRESS_VALUE;
3208 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3209 total += COMPONENT_PROGRESS_VALUE;
3211 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3212 total += file->FileSize;
3214 msi_ui_progress( package, 0, total, 0, 0 );
3216 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3218 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3219 debugstr_w(feature->Feature), feature->Installed,
3220 feature->ActionRequest, feature->Action);
3222 return ERROR_SUCCESS;
3225 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3227 MSIPACKAGE* package = param;
3228 LPCWSTR cond = NULL;
3229 LPCWSTR message = NULL;
3232 static const WCHAR title[]=
3233 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3235 cond = MSI_RecordGetString(row,1);
3237 r = MSI_EvaluateConditionW(package,cond);
3238 if (r == MSICONDITION_FALSE)
3240 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3243 message = MSI_RecordGetString(row,2);
3244 deformat_string(package,message,&deformated);
3245 MessageBoxW(NULL,deformated,title,MB_OK);
3246 msi_free(deformated);
3249 return ERROR_INSTALL_FAILURE;
3252 return ERROR_SUCCESS;
3255 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3257 static const WCHAR query[] = {
3258 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3259 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3263 TRACE("Checking launch conditions\n");
3265 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3266 if (rc != ERROR_SUCCESS)
3267 return ERROR_SUCCESS;
3269 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3270 msiobj_release(&view->hdr);
3274 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3278 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3280 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3282 static const WCHAR query[] = {
3283 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3284 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3285 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3286 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3287 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3290 LPWSTR deformated, buffer, deformated_name;
3293 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3297 root = MSI_RecordGetInteger(row,2);
3298 key = MSI_RecordGetString(row, 3);
3299 name = MSI_RecordGetString(row, 4);
3300 deformat_string(package, key , &deformated);
3301 deformat_string(package, name, &deformated_name);
3303 len = strlenW(deformated) + 6;
3304 if (deformated_name)
3305 len+=strlenW(deformated_name);
3307 buffer = msi_alloc( len *sizeof(WCHAR));
3309 if (deformated_name)
3310 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3312 sprintfW(buffer,fmt,root,deformated);
3314 msi_free(deformated);
3315 msi_free(deformated_name);
3316 msiobj_release(&row->hdr);
3320 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3322 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3327 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3330 return strdupW( file->TargetPath );
3335 static HKEY openSharedDLLsKey(void)
3338 static const WCHAR path[] =
3339 {'S','o','f','t','w','a','r','e','\\',
3340 'M','i','c','r','o','s','o','f','t','\\',
3341 'W','i','n','d','o','w','s','\\',
3342 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3343 'S','h','a','r','e','d','D','L','L','s',0};
3345 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3349 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3354 DWORD sz = sizeof(count);
3357 hkey = openSharedDLLsKey();
3358 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3359 if (rc != ERROR_SUCCESS)
3365 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3369 hkey = openSharedDLLsKey();
3371 msi_reg_set_val_dword( hkey, path, count );
3373 RegDeleteValueW(hkey,path);
3378 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3380 MSIFEATURE *feature;
3384 /* only refcount DLLs */
3385 if (comp->KeyPath == NULL ||
3387 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3388 comp->Attributes & msidbComponentAttributesODBCDataSource)
3392 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3393 write = (count > 0);
3395 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3399 /* increment counts */
3400 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3404 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3407 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3409 if ( cl->component == comp )
3414 /* decrement counts */
3415 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3419 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3422 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3424 if ( cl->component == comp )
3429 /* ref count all the files in the component */
3434 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3436 if (file->Component == comp)
3437 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3441 /* add a count for permanent */
3442 if (comp->Attributes & msidbComponentAttributesPermanent)
3445 comp->RefCount = count;
3448 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3451 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3455 const WCHAR prefixW[] = {'<','\\',0};
3456 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3457 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3461 strcpyW( keypath, prefixW );
3462 strcatW( keypath, comp->assembly->display_name );
3466 return resolve_keypath( package, comp );
3469 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3471 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3478 squash_guid(package->ProductCode,squished_pc);
3479 msi_set_sourcedir_props(package, FALSE);
3481 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3484 INSTALLSTATE action;
3486 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3487 if (!comp->ComponentId)
3490 squash_guid( comp->ComponentId, squished_cc );
3491 msi_free( comp->FullKeypath );
3492 comp->FullKeypath = build_full_keypath( package, comp );
3494 ACTION_RefCountComponent( package, comp );
3496 if (package->need_rollback) action = comp->Installed;
3497 else action = comp->ActionRequest;
3499 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3500 debugstr_w(comp->Component), debugstr_w(squished_cc),
3501 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3503 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3505 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3506 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3508 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3510 if (rc != ERROR_SUCCESS)
3513 if (comp->Attributes & msidbComponentAttributesPermanent)
3515 static const WCHAR szPermKey[] =
3516 { '0','0','0','0','0','0','0','0','0','0','0','0',
3517 '0','0','0','0','0','0','0','0','0','0','0','0',
3518 '0','0','0','0','0','0','0','0',0 };
3520 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3522 if (action == INSTALLSTATE_LOCAL)
3523 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3529 WCHAR source[MAX_PATH];
3530 WCHAR base[MAX_PATH];
3533 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3534 static const WCHAR query[] = {
3535 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3536 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3537 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3538 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3539 '`','D','i','s','k','I','d','`',0};
3541 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3544 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3545 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3546 ptr2 = strrchrW(source, '\\') + 1;
3547 msiobj_release(&row->hdr);
3549 lstrcpyW(base, package->PackagePath);
3550 ptr = strrchrW(base, '\\');
3553 sourcepath = msi_resolve_file_source(package, file);
3554 ptr = sourcepath + lstrlenW(base);
3555 lstrcpyW(ptr2, ptr);
3556 msi_free(sourcepath);
3558 msi_reg_set_val_str(hkey, squished_pc, source);
3562 else if (action == INSTALLSTATE_ABSENT)
3564 if (comp->num_clients <= 0)
3566 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3567 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid );
3569 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
3574 uirow = MSI_CreateRecord(3);
3575 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3576 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3577 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3578 msi_ui_actiondata( package, szProcessComponents, uirow );
3579 msiobj_release( &uirow->hdr );
3581 return ERROR_SUCCESS;
3592 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3593 LPWSTR lpszName, LONG_PTR lParam)
3596 typelib_struct *tl_struct = (typelib_struct*) lParam;
3597 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3601 if (!IS_INTRESOURCE(lpszName))
3603 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3607 sz = strlenW(tl_struct->source)+4;
3608 sz *= sizeof(WCHAR);
3610 if ((INT_PTR)lpszName == 1)
3611 tl_struct->path = strdupW(tl_struct->source);
3614 tl_struct->path = msi_alloc(sz);
3615 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3618 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3619 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3622 msi_free(tl_struct->path);
3623 tl_struct->path = NULL;
3628 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3629 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3631 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3635 msi_free(tl_struct->path);
3636 tl_struct->path = NULL;
3638 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3639 ITypeLib_Release(tl_struct->ptLib);
3644 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3646 MSIPACKAGE* package = param;
3650 typelib_struct tl_struct;
3655 component = MSI_RecordGetString(row,3);
3656 comp = msi_get_loaded_component(package,component);
3658 return ERROR_SUCCESS;
3660 comp->Action = msi_get_component_action( package, comp );
3661 if (comp->Action != INSTALLSTATE_LOCAL)
3663 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3664 return ERROR_SUCCESS;
3667 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3669 TRACE("component has no key path\n");
3670 return ERROR_SUCCESS;
3672 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3674 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3678 guid = MSI_RecordGetString(row,1);
3679 CLSIDFromString( guid, &tl_struct.clsid);
3680 tl_struct.source = strdupW( file->TargetPath );
3681 tl_struct.path = NULL;
3683 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3684 (LONG_PTR)&tl_struct);
3688 LPCWSTR helpid, help_path = NULL;
3691 helpid = MSI_RecordGetString(row,6);
3693 if (helpid) help_path = msi_get_target_folder( package, helpid );
3694 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3697 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3699 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3701 ITypeLib_Release(tl_struct.ptLib);
3702 msi_free(tl_struct.path);
3704 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3706 FreeLibrary(module);
3707 msi_free(tl_struct.source);
3711 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3714 ERR("Failed to load type library: %08x\n", hr);
3715 return ERROR_INSTALL_FAILURE;
3718 ITypeLib_Release(tlib);
3721 return ERROR_SUCCESS;
3724 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3726 static const WCHAR query[] = {
3727 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3728 '`','T','y','p','e','L','i','b','`',0};
3732 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3733 if (rc != ERROR_SUCCESS)
3734 return ERROR_SUCCESS;
3736 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3737 msiobj_release(&view->hdr);
3741 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3743 MSIPACKAGE *package = param;
3744 LPCWSTR component, guid;
3752 component = MSI_RecordGetString( row, 3 );
3753 comp = msi_get_loaded_component( package, component );
3755 return ERROR_SUCCESS;
3757 comp->Action = msi_get_component_action( package, comp );
3758 if (comp->Action != INSTALLSTATE_ABSENT)
3760 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3761 return ERROR_SUCCESS;
3763 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3765 guid = MSI_RecordGetString( row, 1 );
3766 CLSIDFromString( guid, &libid );
3767 version = MSI_RecordGetInteger( row, 4 );
3768 language = MSI_RecordGetInteger( row, 2 );
3771 syskind = SYS_WIN64;
3773 syskind = SYS_WIN32;
3776 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3779 WARN("Failed to unregister typelib: %08x\n", hr);
3782 return ERROR_SUCCESS;
3785 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3787 static const WCHAR query[] = {
3788 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3789 '`','T','y','p','e','L','i','b','`',0};
3793 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3794 if (rc != ERROR_SUCCESS)
3795 return ERROR_SUCCESS;
3797 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3798 msiobj_release( &view->hdr );
3802 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3804 static const WCHAR szlnk[] = {'.','l','n','k',0};
3805 LPCWSTR directory, extension, link_folder;
3806 LPWSTR link_file, filename;
3808 directory = MSI_RecordGetString( row, 2 );
3809 link_folder = msi_get_target_folder( package, directory );
3812 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3815 /* may be needed because of a bug somewhere else */
3816 msi_create_full_path( link_folder );
3818 filename = msi_dup_record_field( row, 3 );
3819 msi_reduce_to_long_filename( filename );
3821 extension = strchrW( filename, '.' );
3822 if (!extension || strcmpiW( extension, szlnk ))
3824 int len = strlenW( filename );
3825 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3826 memcpy( filename + len, szlnk, sizeof(szlnk) );
3828 link_file = msi_build_directory_name( 2, link_folder, filename );
3829 msi_free( filename );
3834 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3836 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3837 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3838 WCHAR *folder, *dest, *path;
3840 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3841 folder = msi_dup_property( package->db, szWindowsFolder );
3844 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3845 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3846 msi_free( appdata );
3848 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3849 msi_create_full_path( dest );
3850 path = msi_build_directory_name( 2, dest, icon_name );
3856 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3858 MSIPACKAGE *package = param;
3859 LPWSTR link_file, deformated, path;
3860 LPCWSTR component, target;
3862 IShellLinkW *sl = NULL;
3863 IPersistFile *pf = NULL;
3866 component = MSI_RecordGetString(row, 4);
3867 comp = msi_get_loaded_component(package, component);
3869 return ERROR_SUCCESS;
3871 comp->Action = msi_get_component_action( package, comp );
3872 if (comp->Action != INSTALLSTATE_LOCAL)
3874 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3875 return ERROR_SUCCESS;
3877 msi_ui_actiondata( package, szCreateShortcuts, row );
3879 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3880 &IID_IShellLinkW, (LPVOID *) &sl );
3884 ERR("CLSID_ShellLink not available\n");
3888 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3891 ERR("QueryInterface(IID_IPersistFile) failed\n");
3895 target = MSI_RecordGetString(row, 5);
3896 if (strchrW(target, '['))
3898 deformat_string( package, target, &path );
3899 TRACE("target path is %s\n", debugstr_w(path));
3900 IShellLinkW_SetPath( sl, path );
3905 FIXME("poorly handled shortcut format, advertised shortcut\n");
3906 IShellLinkW_SetPath(sl,comp->FullKeypath);
3909 if (!MSI_RecordIsNull(row,6))
3911 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3912 deformat_string(package, arguments, &deformated);
3913 IShellLinkW_SetArguments(sl,deformated);
3914 msi_free(deformated);
3917 if (!MSI_RecordIsNull(row,7))
3919 LPCWSTR description = MSI_RecordGetString(row, 7);
3920 IShellLinkW_SetDescription(sl, description);
3923 if (!MSI_RecordIsNull(row,8))
3924 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3926 if (!MSI_RecordIsNull(row,9))
3929 LPCWSTR icon = MSI_RecordGetString(row, 9);
3931 path = msi_build_icon_path(package, icon);
3932 index = MSI_RecordGetInteger(row,10);
3934 /* no value means 0 */
3935 if (index == MSI_NULL_INTEGER)
3938 IShellLinkW_SetIconLocation(sl, path, index);
3942 if (!MSI_RecordIsNull(row,11))
3943 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3945 if (!MSI_RecordIsNull(row,12))
3947 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3948 full_path = msi_get_target_folder( package, wkdir );
3949 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3951 link_file = get_link_file(package, row);
3953 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3954 IPersistFile_Save(pf, link_file, FALSE);
3955 msi_free(link_file);
3959 IPersistFile_Release( pf );
3961 IShellLinkW_Release( sl );
3963 return ERROR_SUCCESS;
3966 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3968 static const WCHAR query[] = {
3969 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3970 '`','S','h','o','r','t','c','u','t','`',0};
3975 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3976 if (rc != ERROR_SUCCESS)
3977 return ERROR_SUCCESS;
3979 res = CoInitialize( NULL );
3981 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3982 msiobj_release(&view->hdr);
3984 if (SUCCEEDED(res)) CoUninitialize();
3988 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3990 MSIPACKAGE *package = param;
3995 component = MSI_RecordGetString( row, 4 );
3996 comp = msi_get_loaded_component( package, component );
3998 return ERROR_SUCCESS;
4000 comp->Action = msi_get_component_action( package, comp );
4001 if (comp->Action != INSTALLSTATE_ABSENT)
4003 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4004 return ERROR_SUCCESS;
4006 msi_ui_actiondata( package, szRemoveShortcuts, row );
4008 link_file = get_link_file( package, row );
4010 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
4011 if (!DeleteFileW( link_file ))
4013 WARN("Failed to remove shortcut file %u\n", GetLastError());
4015 msi_free( link_file );
4017 return ERROR_SUCCESS;
4020 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4022 static const WCHAR query[] = {
4023 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4024 '`','S','h','o','r','t','c','u','t','`',0};
4028 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4029 if (rc != ERROR_SUCCESS)
4030 return ERROR_SUCCESS;
4032 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
4033 msiobj_release( &view->hdr );
4037 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
4039 MSIPACKAGE* package = param;
4047 FileName = MSI_RecordGetString(row,1);
4050 ERR("Unable to get FileName\n");
4051 return ERROR_SUCCESS;
4054 FilePath = msi_build_icon_path(package, FileName);
4056 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4058 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4059 FILE_ATTRIBUTE_NORMAL, NULL);
4061 if (the_file == INVALID_HANDLE_VALUE)
4063 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4065 return ERROR_SUCCESS;
4072 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4073 if (rc != ERROR_SUCCESS)
4075 ERR("Failed to get stream\n");
4076 CloseHandle(the_file);
4077 DeleteFileW(FilePath);
4080 WriteFile(the_file,buffer,sz,&write,NULL);
4081 } while (sz == 1024);
4084 CloseHandle(the_file);
4086 return ERROR_SUCCESS;
4089 static UINT msi_publish_icons(MSIPACKAGE *package)
4091 static const WCHAR query[]= {
4092 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4093 '`','I','c','o','n','`',0};
4097 r = MSI_DatabaseOpenViewW(package->db, query, &view);
4098 if (r == ERROR_SUCCESS)
4100 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
4101 msiobj_release(&view->hdr);
4102 if (r != ERROR_SUCCESS)
4105 return ERROR_SUCCESS;
4108 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
4114 MSISOURCELISTINFO *info;
4116 r = RegCreateKeyW(hkey, szSourceList, &source);
4117 if (r != ERROR_SUCCESS)
4120 RegCloseKey(source);
4122 buffer = strrchrW(package->PackagePath, '\\') + 1;
4123 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4124 package->Context, MSICODE_PRODUCT,
4125 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4126 if (r != ERROR_SUCCESS)
4129 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4130 package->Context, MSICODE_PRODUCT,
4131 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4132 if (r != ERROR_SUCCESS)
4135 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4136 package->Context, MSICODE_PRODUCT,
4137 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4138 if (r != ERROR_SUCCESS)
4141 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4143 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4144 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4145 info->options, info->value);
4147 MsiSourceListSetInfoW(package->ProductCode, NULL,
4148 info->context, info->options,
4149 info->property, info->value);
4152 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4154 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4155 disk->context, disk->options,
4156 disk->disk_id, disk->volume_label, disk->disk_prompt);
4159 return ERROR_SUCCESS;
4162 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4164 MSIHANDLE hdb, suminfo;
4165 WCHAR guids[MAX_PATH];
4166 WCHAR packcode[SQUISH_GUID_SIZE];
4173 static const WCHAR szARPProductIcon[] =
4174 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4175 static const WCHAR szAssignment[] =
4176 {'A','s','s','i','g','n','m','e','n','t',0};
4177 static const WCHAR szAdvertiseFlags[] =
4178 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4179 static const WCHAR szClients[] =
4180 {'C','l','i','e','n','t','s',0};
4181 static const WCHAR szColon[] = {':',0};
4183 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4184 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4187 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4188 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4191 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4193 buffer = msi_dup_property(package->db, szARPProductIcon);
4196 LPWSTR path = msi_build_icon_path(package, buffer);
4197 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4202 buffer = msi_dup_property(package->db, szProductVersion);
4205 DWORD verdword = msi_version_str_to_dword(buffer);
4206 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4210 msi_reg_set_val_dword(hkey, szAssignment, 0);
4211 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4212 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4213 msi_reg_set_val_str(hkey, szClients, szColon);
4215 hdb = alloc_msihandle(&package->db->hdr);
4217 return ERROR_NOT_ENOUGH_MEMORY;
4219 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4220 MsiCloseHandle(hdb);
4221 if (r != ERROR_SUCCESS)
4225 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4226 NULL, guids, &size);
4227 if (r != ERROR_SUCCESS)
4230 ptr = strchrW(guids, ';');
4232 squash_guid(guids, packcode);
4233 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4236 MsiCloseHandle(suminfo);
4237 return ERROR_SUCCESS;
4240 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4245 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4247 upgrade = msi_dup_property(package->db, szUpgradeCode);
4249 return ERROR_SUCCESS;
4251 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4252 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4254 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4256 if (r != ERROR_SUCCESS)
4258 WARN("failed to open upgrade code key\n");
4260 return ERROR_SUCCESS;
4262 squash_guid(package->ProductCode, squashed_pc);
4263 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4266 return ERROR_SUCCESS;
4269 static BOOL msi_check_publish(MSIPACKAGE *package)
4271 MSIFEATURE *feature;
4273 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4275 feature->Action = msi_get_feature_action( package, feature );
4276 if (feature->Action == INSTALLSTATE_LOCAL)
4283 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4285 MSIFEATURE *feature;
4287 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4289 feature->Action = msi_get_feature_action( package, feature );
4290 if (feature->Action != INSTALLSTATE_ABSENT)
4297 static UINT msi_publish_patches( MSIPACKAGE *package )
4299 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4300 WCHAR patch_squashed[GUID_SIZE];
4301 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4303 MSIPATCHINFO *patch;
4305 WCHAR *p, *all_patches = NULL;
4308 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4309 if (r != ERROR_SUCCESS)
4310 return ERROR_FUNCTION_FAILED;
4312 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4313 if (res != ERROR_SUCCESS)
4315 r = ERROR_FUNCTION_FAILED;
4319 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4320 if (r != ERROR_SUCCESS)
4323 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4325 squash_guid( patch->patchcode, patch_squashed );
4326 len += strlenW( patch_squashed ) + 1;
4329 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4333 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4337 squash_guid( patch->patchcode, p );
4338 p += strlenW( p ) + 1;
4340 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4341 (const BYTE *)patch->transforms,
4342 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4343 if (res != ERROR_SUCCESS)
4346 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4347 if (r != ERROR_SUCCESS)
4350 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4351 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4352 RegCloseKey( patch_key );
4353 if (res != ERROR_SUCCESS)
4356 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4358 res = GetLastError();
4359 ERR("Unable to copy patch package %d\n", res);
4362 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4363 if (res != ERROR_SUCCESS)
4366 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4367 RegCloseKey( patch_key );
4368 if (res != ERROR_SUCCESS)
4372 all_patches[len] = 0;
4373 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4374 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4375 if (res != ERROR_SUCCESS)
4378 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4379 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4380 if (res != ERROR_SUCCESS)
4381 r = ERROR_FUNCTION_FAILED;
4384 RegCloseKey( product_patches_key );
4385 RegCloseKey( patches_key );
4386 RegCloseKey( product_key );
4387 msi_free( all_patches );
4391 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4394 HKEY hukey = NULL, hudkey = NULL;
4397 if (!list_empty(&package->patches))
4399 rc = msi_publish_patches(package);
4400 if (rc != ERROR_SUCCESS)
4404 /* FIXME: also need to publish if the product is in advertise mode */
4405 if (!msi_check_publish(package))
4406 return ERROR_SUCCESS;
4408 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4410 if (rc != ERROR_SUCCESS)
4413 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4414 NULL, &hudkey, TRUE);
4415 if (rc != ERROR_SUCCESS)
4418 rc = msi_publish_upgrade_code(package);
4419 if (rc != ERROR_SUCCESS)
4422 rc = msi_publish_product_properties(package, hukey);
4423 if (rc != ERROR_SUCCESS)
4426 rc = msi_publish_sourcelist(package, hukey);
4427 if (rc != ERROR_SUCCESS)
4430 rc = msi_publish_icons(package);
4433 uirow = MSI_CreateRecord( 1 );
4434 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4435 msi_ui_actiondata( package, szPublishProduct, uirow );
4436 msiobj_release( &uirow->hdr );
4439 RegCloseKey(hudkey);
4443 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4445 WCHAR *filename, *ptr, *folder, *ret;
4446 const WCHAR *dirprop;
4448 filename = msi_dup_record_field( row, 2 );
4449 if (filename && (ptr = strchrW( filename, '|' )))
4454 dirprop = MSI_RecordGetString( row, 3 );
4457 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4458 if (!folder) folder = msi_dup_property( package->db, dirprop );
4461 folder = msi_dup_property( package->db, szWindowsFolder );
4465 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4466 msi_free( filename );
4470 ret = msi_build_directory_name( 2, folder, ptr );
4472 msi_free( filename );
4477 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4479 MSIPACKAGE *package = param;
4480 LPCWSTR component, section, key, value, identifier;
4481 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4486 component = MSI_RecordGetString(row, 8);
4487 comp = msi_get_loaded_component(package,component);
4489 return ERROR_SUCCESS;
4491 comp->Action = msi_get_component_action( package, comp );
4492 if (comp->Action != INSTALLSTATE_LOCAL)
4494 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4495 return ERROR_SUCCESS;
4498 identifier = MSI_RecordGetString(row,1);
4499 section = MSI_RecordGetString(row,4);
4500 key = MSI_RecordGetString(row,5);
4501 value = MSI_RecordGetString(row,6);
4502 action = MSI_RecordGetInteger(row,7);
4504 deformat_string(package,section,&deformated_section);
4505 deformat_string(package,key,&deformated_key);
4506 deformat_string(package,value,&deformated_value);
4508 fullname = get_ini_file_name(package, row);
4512 TRACE("Adding value %s to section %s in %s\n",
4513 debugstr_w(deformated_key), debugstr_w(deformated_section),
4514 debugstr_w(fullname));
4515 WritePrivateProfileStringW(deformated_section, deformated_key,
4516 deformated_value, fullname);
4518 else if (action == 1)
4521 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4522 returned, 10, fullname);
4523 if (returned[0] == 0)
4525 TRACE("Adding value %s to section %s in %s\n",
4526 debugstr_w(deformated_key), debugstr_w(deformated_section),
4527 debugstr_w(fullname));
4529 WritePrivateProfileStringW(deformated_section, deformated_key,
4530 deformated_value, fullname);
4533 else if (action == 3)
4534 FIXME("Append to existing section not yet implemented\n");
4536 uirow = MSI_CreateRecord(4);
4537 MSI_RecordSetStringW(uirow,1,identifier);
4538 MSI_RecordSetStringW(uirow,2,deformated_section);
4539 MSI_RecordSetStringW(uirow,3,deformated_key);
4540 MSI_RecordSetStringW(uirow,4,deformated_value);
4541 msi_ui_actiondata( package, szWriteIniValues, uirow );
4542 msiobj_release( &uirow->hdr );
4545 msi_free(deformated_key);
4546 msi_free(deformated_value);
4547 msi_free(deformated_section);
4548 return ERROR_SUCCESS;
4551 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4553 static const WCHAR query[] = {
4554 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4555 '`','I','n','i','F','i','l','e','`',0};
4559 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4560 if (rc != ERROR_SUCCESS)
4561 return ERROR_SUCCESS;
4563 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4564 msiobj_release(&view->hdr);
4568 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4570 MSIPACKAGE *package = param;
4571 LPCWSTR component, section, key, value, identifier;
4572 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4577 component = MSI_RecordGetString( row, 8 );
4578 comp = msi_get_loaded_component( package, component );
4580 return ERROR_SUCCESS;
4582 comp->Action = msi_get_component_action( package, comp );
4583 if (comp->Action != INSTALLSTATE_ABSENT)
4585 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4586 return ERROR_SUCCESS;
4589 identifier = MSI_RecordGetString( row, 1 );
4590 section = MSI_RecordGetString( row, 4 );
4591 key = MSI_RecordGetString( row, 5 );
4592 value = MSI_RecordGetString( row, 6 );
4593 action = MSI_RecordGetInteger( row, 7 );
4595 deformat_string( package, section, &deformated_section );
4596 deformat_string( package, key, &deformated_key );
4597 deformat_string( package, value, &deformated_value );
4599 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4601 filename = get_ini_file_name( package, row );
4603 TRACE("Removing key %s from section %s in %s\n",
4604 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4606 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4608 WARN("Unable to remove key %u\n", GetLastError());
4610 msi_free( filename );
4613 FIXME("Unsupported action %d\n", action);
4616 uirow = MSI_CreateRecord( 4 );
4617 MSI_RecordSetStringW( uirow, 1, identifier );
4618 MSI_RecordSetStringW( uirow, 2, deformated_section );
4619 MSI_RecordSetStringW( uirow, 3, deformated_key );
4620 MSI_RecordSetStringW( uirow, 4, deformated_value );
4621 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4622 msiobj_release( &uirow->hdr );
4624 msi_free( deformated_key );
4625 msi_free( deformated_value );
4626 msi_free( deformated_section );
4627 return ERROR_SUCCESS;
4630 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4632 MSIPACKAGE *package = param;
4633 LPCWSTR component, section, key, value, identifier;
4634 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4639 component = MSI_RecordGetString( row, 8 );
4640 comp = msi_get_loaded_component( package, component );
4642 return ERROR_SUCCESS;
4644 comp->Action = msi_get_component_action( package, comp );
4645 if (comp->Action != INSTALLSTATE_LOCAL)
4647 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4648 return ERROR_SUCCESS;
4651 identifier = MSI_RecordGetString( row, 1 );
4652 section = MSI_RecordGetString( row, 4 );
4653 key = MSI_RecordGetString( row, 5 );
4654 value = MSI_RecordGetString( row, 6 );
4655 action = MSI_RecordGetInteger( row, 7 );
4657 deformat_string( package, section, &deformated_section );
4658 deformat_string( package, key, &deformated_key );
4659 deformat_string( package, value, &deformated_value );
4661 if (action == msidbIniFileActionRemoveLine)
4663 filename = get_ini_file_name( package, row );
4665 TRACE("Removing key %s from section %s in %s\n",
4666 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4668 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4670 WARN("Unable to remove key %u\n", GetLastError());
4672 msi_free( filename );
4675 FIXME("Unsupported action %d\n", action);
4677 uirow = MSI_CreateRecord( 4 );
4678 MSI_RecordSetStringW( uirow, 1, identifier );
4679 MSI_RecordSetStringW( uirow, 2, deformated_section );
4680 MSI_RecordSetStringW( uirow, 3, deformated_key );
4681 MSI_RecordSetStringW( uirow, 4, deformated_value );
4682 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4683 msiobj_release( &uirow->hdr );
4685 msi_free( deformated_key );
4686 msi_free( deformated_value );
4687 msi_free( deformated_section );
4688 return ERROR_SUCCESS;
4691 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4693 static const WCHAR query[] = {
4694 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4695 '`','I','n','i','F','i','l','e','`',0};
4696 static const WCHAR remove_query[] = {
4697 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4698 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4702 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4703 if (rc == ERROR_SUCCESS)
4705 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4706 msiobj_release( &view->hdr );
4707 if (rc != ERROR_SUCCESS)
4710 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4711 if (rc == ERROR_SUCCESS)
4713 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4714 msiobj_release( &view->hdr );
4715 if (rc != ERROR_SUCCESS)
4718 return ERROR_SUCCESS;
4721 static void register_dll( const WCHAR *dll, BOOL unregister )
4723 static const WCHAR regW[] =
4724 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"','%','s','\"',0};
4725 static const WCHAR unregW[] =
4726 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"','%','s','\"',0};
4727 PROCESS_INFORMATION pi;
4731 if (!(cmd = msi_alloc( strlenW(dll) * sizeof(WCHAR) + sizeof(unregW) ))) return;
4733 if (unregister) sprintfW( cmd, unregW, dll );
4734 else sprintfW( cmd, regW, dll );
4736 memset( &si, 0, sizeof(STARTUPINFOW) );
4737 if (CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
4739 CloseHandle( pi.hThread );
4740 msi_dialog_check_messages( pi.hProcess );
4741 CloseHandle( pi.hProcess );
4746 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4748 MSIPACKAGE *package = param;
4753 filename = MSI_RecordGetString( row, 1 );
4754 file = msi_get_loaded_file( package, filename );
4757 WARN("unable to find file %s\n", debugstr_w(filename));
4758 return ERROR_SUCCESS;
4760 file->Component->Action = msi_get_component_action( package, file->Component );
4761 if (file->Component->Action != INSTALLSTATE_LOCAL)
4763 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4764 return ERROR_SUCCESS;
4767 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4768 register_dll( file->TargetPath, FALSE );
4770 uirow = MSI_CreateRecord( 2 );
4771 MSI_RecordSetStringW( uirow, 1, file->File );
4772 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4773 msi_ui_actiondata( package, szSelfRegModules, uirow );
4774 msiobj_release( &uirow->hdr );
4776 return ERROR_SUCCESS;
4779 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4781 static const WCHAR query[] = {
4782 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4783 '`','S','e','l','f','R','e','g','`',0};
4787 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4788 if (rc != ERROR_SUCCESS)
4789 return ERROR_SUCCESS;
4791 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4792 msiobj_release(&view->hdr);
4796 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4798 MSIPACKAGE *package = param;
4803 filename = MSI_RecordGetString( row, 1 );
4804 file = msi_get_loaded_file( package, filename );
4807 WARN("unable to find file %s\n", debugstr_w(filename));
4808 return ERROR_SUCCESS;
4810 file->Component->Action = msi_get_component_action( package, file->Component );
4811 if (file->Component->Action != INSTALLSTATE_ABSENT)
4813 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4814 return ERROR_SUCCESS;
4817 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4818 register_dll( file->TargetPath, TRUE );
4820 uirow = MSI_CreateRecord( 2 );
4821 MSI_RecordSetStringW( uirow, 1, file->File );
4822 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4823 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4824 msiobj_release( &uirow->hdr );
4826 return ERROR_SUCCESS;
4829 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4831 static const WCHAR query[] = {
4832 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4833 '`','S','e','l','f','R','e','g','`',0};
4837 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4838 if (rc != ERROR_SUCCESS)
4839 return ERROR_SUCCESS;
4841 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4842 msiobj_release( &view->hdr );
4846 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4848 MSIFEATURE *feature;
4850 HKEY hkey = NULL, userdata = NULL;
4852 if (!msi_check_publish(package))
4853 return ERROR_SUCCESS;
4855 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4857 if (rc != ERROR_SUCCESS)
4860 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4862 if (rc != ERROR_SUCCESS)
4865 /* here the guids are base 85 encoded */
4866 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4872 BOOL absent = FALSE;
4875 if (feature->Action != INSTALLSTATE_LOCAL &&
4876 feature->Action != INSTALLSTATE_SOURCE &&
4877 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4880 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4884 if (feature->Feature_Parent)
4885 size += strlenW( feature->Feature_Parent )+2;
4887 data = msi_alloc(size * sizeof(WCHAR));
4890 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4892 MSICOMPONENT* component = cl->component;
4896 if (component->ComponentId)
4898 TRACE("From %s\n",debugstr_w(component->ComponentId));
4899 CLSIDFromString(component->ComponentId, &clsid);
4900 encode_base85_guid(&clsid,buf);
4901 TRACE("to %s\n",debugstr_w(buf));
4906 if (feature->Feature_Parent)
4908 static const WCHAR sep[] = {'\2',0};
4910 strcatW(data,feature->Feature_Parent);
4913 msi_reg_set_val_str( userdata, feature->Feature, data );
4917 if (feature->Feature_Parent)
4918 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4921 size += sizeof(WCHAR);
4922 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4923 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4927 size += 2*sizeof(WCHAR);
4928 data = msi_alloc(size);
4931 if (feature->Feature_Parent)
4932 strcpyW( &data[1], feature->Feature_Parent );
4933 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4939 uirow = MSI_CreateRecord( 1 );
4940 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4941 msi_ui_actiondata( package, szPublishFeatures, uirow );
4942 msiobj_release( &uirow->hdr );
4943 /* FIXME: call msi_ui_progress? */
4948 RegCloseKey(userdata);
4952 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4958 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4960 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4962 if (r == ERROR_SUCCESS)
4964 RegDeleteValueW(hkey, feature->Feature);
4968 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4970 if (r == ERROR_SUCCESS)
4972 RegDeleteValueW(hkey, feature->Feature);
4976 uirow = MSI_CreateRecord( 1 );
4977 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4978 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4979 msiobj_release( &uirow->hdr );
4981 return ERROR_SUCCESS;
4984 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4986 MSIFEATURE *feature;
4988 if (!msi_check_unpublish(package))
4989 return ERROR_SUCCESS;
4991 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4993 msi_unpublish_feature(package, feature);
4996 return ERROR_SUCCESS;
4999 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
5003 WCHAR date[9], *val, *buffer;
5004 const WCHAR *prop, *key;
5006 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
5007 static const WCHAR modpath_fmt[] =
5008 {'M','s','i','E','x','e','c','.','e','x','e',' ',
5009 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
5010 static const WCHAR szModifyPath[] =
5011 {'M','o','d','i','f','y','P','a','t','h',0};
5012 static const WCHAR szUninstallString[] =
5013 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5014 static const WCHAR szEstimatedSize[] =
5015 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5016 static const WCHAR szDisplayVersion[] =
5017 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5018 static const WCHAR szInstallSource[] =
5019 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5020 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
5021 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5022 static const WCHAR szAuthorizedCDFPrefix[] =
5023 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5024 static const WCHAR szARPCONTACT[] =
5025 {'A','R','P','C','O','N','T','A','C','T',0};
5026 static const WCHAR szContact[] =
5027 {'C','o','n','t','a','c','t',0};
5028 static const WCHAR szARPCOMMENTS[] =
5029 {'A','R','P','C','O','M','M','E','N','T','S',0};
5030 static const WCHAR szComments[] =
5031 {'C','o','m','m','e','n','t','s',0};
5032 static const WCHAR szProductName[] =
5033 {'P','r','o','d','u','c','t','N','a','m','e',0};
5034 static const WCHAR szDisplayName[] =
5035 {'D','i','s','p','l','a','y','N','a','m','e',0};
5036 static const WCHAR szARPHELPLINK[] =
5037 {'A','R','P','H','E','L','P','L','I','N','K',0};
5038 static const WCHAR szHelpLink[] =
5039 {'H','e','l','p','L','i','n','k',0};
5040 static const WCHAR szARPHELPTELEPHONE[] =
5041 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5042 static const WCHAR szHelpTelephone[] =
5043 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5044 static const WCHAR szARPINSTALLLOCATION[] =
5045 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5046 static const WCHAR szManufacturer[] =
5047 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5048 static const WCHAR szPublisher[] =
5049 {'P','u','b','l','i','s','h','e','r',0};
5050 static const WCHAR szARPREADME[] =
5051 {'A','R','P','R','E','A','D','M','E',0};
5052 static const WCHAR szReadme[] =
5053 {'R','e','a','d','M','e',0};
5054 static const WCHAR szARPSIZE[] =
5055 {'A','R','P','S','I','Z','E',0};
5056 static const WCHAR szSize[] =
5057 {'S','i','z','e',0};
5058 static const WCHAR szARPURLINFOABOUT[] =
5059 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5060 static const WCHAR szURLInfoAbout[] =
5061 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5062 static const WCHAR szARPURLUPDATEINFO[] =
5063 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5064 static const WCHAR szURLUpdateInfo[] =
5065 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5066 static const WCHAR szARPSYSTEMCOMPONENT[] =
5067 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
5068 static const WCHAR szSystemComponent[] =
5069 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
5071 static const WCHAR *propval[] = {
5072 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
5073 szARPCONTACT, szContact,
5074 szARPCOMMENTS, szComments,
5075 szProductName, szDisplayName,
5076 szARPHELPLINK, szHelpLink,
5077 szARPHELPTELEPHONE, szHelpTelephone,
5078 szARPINSTALLLOCATION, szInstallLocation,
5079 szSourceDir, szInstallSource,
5080 szManufacturer, szPublisher,
5081 szARPREADME, szReadme,
5083 szARPURLINFOABOUT, szURLInfoAbout,
5084 szARPURLUPDATEINFO, szURLUpdateInfo,
5087 const WCHAR **p = propval;
5093 val = msi_dup_property(package->db, prop);
5094 msi_reg_set_val_str(hkey, key, val);
5098 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5099 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
5101 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
5103 size = deformat_string(package, modpath_fmt, &buffer) * sizeof(WCHAR);
5104 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5105 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5108 /* FIXME: Write real Estimated Size when we have it */
5109 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5111 GetLocalTime(&systime);
5112 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5113 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5115 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5116 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5118 buffer = msi_dup_property(package->db, szProductVersion);
5119 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5122 DWORD verdword = msi_version_str_to_dword(buffer);
5124 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5125 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5126 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5130 return ERROR_SUCCESS;
5133 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5135 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5137 LPWSTR upgrade_code;
5138 HKEY hkey, props, upgrade_key;
5141 /* FIXME: also need to publish if the product is in advertise mode */
5142 if (!msi_check_publish(package))
5143 return ERROR_SUCCESS;
5145 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
5146 if (rc != ERROR_SUCCESS)
5149 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
5150 if (rc != ERROR_SUCCESS)
5153 rc = msi_publish_install_properties(package, hkey);
5154 if (rc != ERROR_SUCCESS)
5157 rc = msi_publish_install_properties(package, props);
5158 if (rc != ERROR_SUCCESS)
5161 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5164 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
5165 if (rc == ERROR_SUCCESS)
5167 squash_guid( package->ProductCode, squashed_pc );
5168 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
5169 RegCloseKey( upgrade_key );
5171 msi_free( upgrade_code );
5173 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
5174 package->delete_on_close = FALSE;
5177 uirow = MSI_CreateRecord( 1 );
5178 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5179 msi_ui_actiondata( package, szRegisterProduct, uirow );
5180 msiobj_release( &uirow->hdr );
5183 return ERROR_SUCCESS;
5186 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5188 return execute_script(package, SCRIPT_INSTALL);
5191 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5193 MSIPACKAGE *package = param;
5194 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5195 WCHAR *p, *icon_path;
5197 if (!icon) return ERROR_SUCCESS;
5198 if ((icon_path = msi_build_icon_path( package, icon )))
5200 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5201 DeleteFileW( icon_path );
5202 if ((p = strrchrW( icon_path, '\\' )))
5205 RemoveDirectoryW( icon_path );
5207 msi_free( icon_path );
5209 return ERROR_SUCCESS;
5212 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5214 static const WCHAR query[]= {
5215 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
5219 r = MSI_DatabaseOpenViewW( package->db, query, &view );
5220 if (r == ERROR_SUCCESS)
5222 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5223 msiobj_release( &view->hdr );
5224 if (r != ERROR_SUCCESS)
5227 return ERROR_SUCCESS;
5230 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
5232 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
5233 WCHAR *upgrade, **features;
5234 BOOL full_uninstall = TRUE;
5235 MSIFEATURE *feature;
5236 MSIPATCHINFO *patch;
5239 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5241 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
5243 features = msi_split_string( remove, ',' );
5244 for (i = 0; features && features[i]; i++)
5246 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
5250 if (!full_uninstall)
5251 return ERROR_SUCCESS;
5253 MSIREG_DeleteProductKey(package->ProductCode);
5254 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5255 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5257 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5258 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5259 MSIREG_DeleteUserProductKey(package->ProductCode);
5260 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5262 upgrade = msi_dup_property(package->db, szUpgradeCode);
5265 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5266 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5270 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5272 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5273 if (!strcmpW( package->ProductCode, patch->products ))
5275 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5276 patch->delete_on_close = TRUE;
5278 /* FIXME: remove local patch package if this is the last product */
5280 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5281 package->delete_on_close = TRUE;
5283 msi_unpublish_icons( package );
5284 return ERROR_SUCCESS;
5287 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5292 /* turn off scheduling */
5293 package->script->CurrentlyScripting= FALSE;
5295 /* first do the same as an InstallExecute */
5296 rc = ACTION_InstallExecute(package);
5297 if (rc != ERROR_SUCCESS)
5300 /* then handle commit actions */
5301 rc = execute_script(package, SCRIPT_COMMIT);
5302 if (rc != ERROR_SUCCESS)
5305 remove = msi_dup_property(package->db, szRemove);
5306 rc = msi_unpublish_product(package, remove);
5311 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5313 static const WCHAR RunOnce[] = {
5314 'S','o','f','t','w','a','r','e','\\',
5315 'M','i','c','r','o','s','o','f','t','\\',
5316 'W','i','n','d','o','w','s','\\',
5317 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5318 'R','u','n','O','n','c','e',0};
5319 static const WCHAR InstallRunOnce[] = {
5320 'S','o','f','t','w','a','r','e','\\',
5321 'M','i','c','r','o','s','o','f','t','\\',
5322 'W','i','n','d','o','w','s','\\',
5323 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5324 'I','n','s','t','a','l','l','e','r','\\',
5325 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5327 static const WCHAR msiexec_fmt[] = {
5329 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5330 '\"','%','s','\"',0};
5331 static const WCHAR install_fmt[] = {
5332 '/','I',' ','\"','%','s','\"',' ',
5333 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5334 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5335 WCHAR buffer[256], sysdir[MAX_PATH];
5337 WCHAR squished_pc[100];
5339 squash_guid(package->ProductCode,squished_pc);
5341 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5342 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5343 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5346 msi_reg_set_val_str( hkey, squished_pc, buffer );
5349 TRACE("Reboot command %s\n",debugstr_w(buffer));
5351 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5352 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5354 msi_reg_set_val_str( hkey, squished_pc, buffer );
5357 return ERROR_INSTALL_SUSPEND;
5360 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5362 static const WCHAR query[] =
5363 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5364 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5365 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5366 MSIRECORD *rec, *row;
5372 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5374 rec = MSI_CreateRecord( count + 2 );
5375 str = MSI_RecordGetString( row, 1 );
5376 MSI_RecordSetStringW( rec, 0, str );
5377 msiobj_release( &row->hdr );
5378 MSI_RecordSetInteger( rec, 1, error );
5380 va_start( va, count );
5381 for (i = 0; i < count; i++)
5383 str = va_arg( va, const WCHAR *);
5384 MSI_RecordSetStringW( rec, i + 2, str );
5388 MSI_FormatRecordW( package, rec, NULL, &size );
5390 data = msi_alloc( size * sizeof(WCHAR) );
5391 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5393 msiobj_release( &rec->hdr );
5397 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5403 * We are currently doing what should be done here in the top level Install
5404 * however for Administrative and uninstalls this step will be needed
5406 if (!package->PackagePath)
5407 return ERROR_SUCCESS;
5409 msi_set_sourcedir_props(package, TRUE);
5411 attrib = GetFileAttributesW(package->db->path);
5412 if (attrib == INVALID_FILE_ATTRIBUTES)
5417 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5418 package->Context, MSICODE_PRODUCT,
5419 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5420 if (rc == ERROR_MORE_DATA)
5422 prompt = msi_alloc(size * sizeof(WCHAR));
5423 MsiSourceListGetInfoW(package->ProductCode, NULL,
5424 package->Context, MSICODE_PRODUCT,
5425 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5428 prompt = strdupW(package->db->path);
5430 msg = msi_build_error_string(package, 1302, 1, prompt);
5432 while(attrib == INVALID_FILE_ATTRIBUTES)
5434 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5438 return ERROR_INSTALL_USEREXIT;
5440 attrib = GetFileAttributesW(package->db->path);
5446 return ERROR_SUCCESS;
5451 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5454 LPWSTR buffer, productid = NULL;
5455 UINT i, rc = ERROR_SUCCESS;
5458 static const WCHAR szPropKeys[][80] =
5460 {'P','r','o','d','u','c','t','I','D',0},
5461 {'U','S','E','R','N','A','M','E',0},
5462 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5466 static const WCHAR szRegKeys[][80] =
5468 {'P','r','o','d','u','c','t','I','D',0},
5469 {'R','e','g','O','w','n','e','r',0},
5470 {'R','e','g','C','o','m','p','a','n','y',0},
5474 if (msi_check_unpublish(package))
5476 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5480 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5484 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5486 if (rc != ERROR_SUCCESS)
5489 for( i = 0; szPropKeys[i][0]; i++ )
5491 buffer = msi_dup_property( package->db, szPropKeys[i] );
5492 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5497 uirow = MSI_CreateRecord( 1 );
5498 MSI_RecordSetStringW( uirow, 1, productid );
5499 msi_ui_actiondata( package, szRegisterUser, uirow );
5500 msiobj_release( &uirow->hdr );
5502 msi_free(productid);
5508 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5512 package->script->InWhatSequence |= SEQUENCE_EXEC;
5513 rc = ACTION_ProcessExecSequence(package,FALSE);
5517 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5519 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5520 WCHAR productid_85[21], component_85[21], *ret;
5524 /* > is used if there is a component GUID and < if not. */
5526 productid_85[0] = 0;
5527 component_85[0] = 0;
5528 CLSIDFromString( package->ProductCode, &clsid );
5530 encode_base85_guid( &clsid, productid_85 );
5533 CLSIDFromString( component->ComponentId, &clsid );
5534 encode_base85_guid( &clsid, component_85 );
5537 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5538 debugstr_w(component_85));
5540 sz = 20 + strlenW( feature ) + 20 + 3;
5541 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5542 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5546 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5548 MSIPACKAGE *package = param;
5549 LPCWSTR compgroupid, component, feature, qualifier, text;
5550 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5559 feature = MSI_RecordGetString(rec, 5);
5560 feat = msi_get_loaded_feature(package, feature);
5562 return ERROR_SUCCESS;
5564 feat->Action = msi_get_feature_action( package, feat );
5565 if (feat->Action != INSTALLSTATE_LOCAL &&
5566 feat->Action != INSTALLSTATE_SOURCE &&
5567 feat->Action != INSTALLSTATE_ADVERTISED)
5569 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5570 return ERROR_SUCCESS;
5573 component = MSI_RecordGetString(rec, 3);
5574 comp = msi_get_loaded_component(package, component);
5576 return ERROR_SUCCESS;
5578 compgroupid = MSI_RecordGetString(rec,1);
5579 qualifier = MSI_RecordGetString(rec,2);
5581 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5582 if (rc != ERROR_SUCCESS)
5585 advertise = msi_create_component_advertise_string( package, comp, feature );
5586 text = MSI_RecordGetString( rec, 4 );
5589 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5590 strcpyW( p, advertise );
5592 msi_free( advertise );
5595 existing = msi_reg_get_val_str( hkey, qualifier );
5597 sz = strlenW( advertise ) + 1;
5600 for (p = existing; *p; p += len)
5602 len = strlenW( p ) + 1;
5603 if (strcmpW( advertise, p )) sz += len;
5606 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5608 rc = ERROR_OUTOFMEMORY;
5614 for (p = existing; *p; p += len)
5616 len = strlenW( p ) + 1;
5617 if (strcmpW( advertise, p ))
5619 memcpy( q, p, len * sizeof(WCHAR) );
5624 strcpyW( q, advertise );
5625 q[strlenW( q ) + 1] = 0;
5627 msi_reg_set_val_multi_str( hkey, qualifier, output );
5632 msi_free( advertise );
5633 msi_free( existing );
5636 uirow = MSI_CreateRecord( 2 );
5637 MSI_RecordSetStringW( uirow, 1, compgroupid );
5638 MSI_RecordSetStringW( uirow, 2, qualifier);
5639 msi_ui_actiondata( package, szPublishComponents, uirow );
5640 msiobj_release( &uirow->hdr );
5641 /* FIXME: call ui_progress? */
5647 * At present I am ignorning the advertised components part of this and only
5648 * focusing on the qualified component sets
5650 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5652 static const WCHAR query[] = {
5653 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5654 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5658 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5659 if (rc != ERROR_SUCCESS)
5660 return ERROR_SUCCESS;
5662 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5663 msiobj_release(&view->hdr);
5667 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5669 static const WCHAR szInstallerComponents[] = {
5670 'S','o','f','t','w','a','r','e','\\',
5671 'M','i','c','r','o','s','o','f','t','\\',
5672 'I','n','s','t','a','l','l','e','r','\\',
5673 'C','o','m','p','o','n','e','n','t','s','\\',0};
5675 MSIPACKAGE *package = param;
5676 LPCWSTR compgroupid, component, feature, qualifier;
5680 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5683 feature = MSI_RecordGetString( rec, 5 );
5684 feat = msi_get_loaded_feature( package, feature );
5686 return ERROR_SUCCESS;
5688 feat->Action = msi_get_feature_action( package, feat );
5689 if (feat->Action != INSTALLSTATE_ABSENT)
5691 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5692 return ERROR_SUCCESS;
5695 component = MSI_RecordGetString( rec, 3 );
5696 comp = msi_get_loaded_component( package, component );
5698 return ERROR_SUCCESS;
5700 compgroupid = MSI_RecordGetString( rec, 1 );
5701 qualifier = MSI_RecordGetString( rec, 2 );
5703 squash_guid( compgroupid, squashed );
5704 strcpyW( keypath, szInstallerComponents );
5705 strcatW( keypath, squashed );
5707 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5708 if (res != ERROR_SUCCESS)
5710 WARN("Unable to delete component key %d\n", res);
5713 uirow = MSI_CreateRecord( 2 );
5714 MSI_RecordSetStringW( uirow, 1, compgroupid );
5715 MSI_RecordSetStringW( uirow, 2, qualifier );
5716 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5717 msiobj_release( &uirow->hdr );
5719 return ERROR_SUCCESS;
5722 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5724 static const WCHAR query[] = {
5725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5726 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5730 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5731 if (rc != ERROR_SUCCESS)
5732 return ERROR_SUCCESS;
5734 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5735 msiobj_release( &view->hdr );
5739 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5741 static const WCHAR query[] =
5742 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5743 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5744 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5745 MSIPACKAGE *package = param;
5746 MSICOMPONENT *component;
5749 SC_HANDLE hscm = NULL, service = NULL;
5751 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5752 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5753 DWORD serv_type, start_type, err_control;
5754 SERVICE_DESCRIPTIONW sd = {NULL};
5756 comp = MSI_RecordGetString( rec, 12 );
5757 component = msi_get_loaded_component( package, comp );
5760 WARN("service component not found\n");
5763 component->Action = msi_get_component_action( package, component );
5764 if (component->Action != INSTALLSTATE_LOCAL)
5766 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5769 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5772 ERR("Failed to open the SC Manager!\n");
5776 start_type = MSI_RecordGetInteger(rec, 5);
5777 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5780 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5781 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5782 serv_type = MSI_RecordGetInteger(rec, 4);
5783 err_control = MSI_RecordGetInteger(rec, 6);
5784 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5785 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5786 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5787 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5788 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5789 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5791 /* fetch the service path */
5792 row = MSI_QueryGetRecord(package->db, query, comp);
5795 ERR("Query failed\n");
5798 key = MSI_RecordGetString(row, 6);
5799 file = msi_get_loaded_file(package, key);
5800 msiobj_release(&row->hdr);
5803 ERR("Failed to load the service file\n");
5807 if (!args || !args[0]) image_path = file->TargetPath;
5810 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5811 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5812 return ERROR_OUTOFMEMORY;
5814 strcpyW(image_path, file->TargetPath);
5815 strcatW(image_path, szSpace);
5816 strcatW(image_path, args);
5818 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5819 start_type, err_control, image_path, load_order,
5820 NULL, depends, serv_name, pass);
5824 if (GetLastError() != ERROR_SERVICE_EXISTS)
5825 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5827 else if (sd.lpDescription)
5829 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5830 WARN("failed to set service description %u\n", GetLastError());
5833 if (image_path != file->TargetPath) msi_free(image_path);
5835 CloseServiceHandle(service);
5836 CloseServiceHandle(hscm);
5839 msi_free(sd.lpDescription);
5840 msi_free(load_order);
5841 msi_free(serv_name);
5846 return ERROR_SUCCESS;
5849 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5851 static const WCHAR query[] = {
5852 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5853 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5857 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5858 if (rc != ERROR_SUCCESS)
5859 return ERROR_SUCCESS;
5861 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5862 msiobj_release(&view->hdr);
5866 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5867 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5869 LPCWSTR *vector, *temp_vector;
5873 static const WCHAR separator[] = {'[','~',']',0};
5876 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5881 vector = msi_alloc(sizeof(LPWSTR));
5889 vector[*numargs - 1] = p;
5891 if ((q = strstrW(p, separator)))
5895 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5901 vector = temp_vector;
5910 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5912 MSIPACKAGE *package = param;
5915 SC_HANDLE scm = NULL, service = NULL;
5916 LPCWSTR component, *vector = NULL;
5917 LPWSTR name, args, display_name = NULL;
5918 DWORD event, numargs, len, wait, dummy;
5919 UINT r = ERROR_FUNCTION_FAILED;
5920 SERVICE_STATUS_PROCESS status;
5921 ULONGLONG start_time;
5923 component = MSI_RecordGetString(rec, 6);
5924 comp = msi_get_loaded_component(package, component);
5926 return ERROR_SUCCESS;
5928 comp->Action = msi_get_component_action( package, comp );
5929 if (comp->Action != INSTALLSTATE_LOCAL)
5931 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5932 return ERROR_SUCCESS;
5935 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5936 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5937 event = MSI_RecordGetInteger(rec, 3);
5938 wait = MSI_RecordGetInteger(rec, 5);
5940 if (!(event & msidbServiceControlEventStart))
5946 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5949 ERR("Failed to open the service control manager\n");
5954 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5955 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5957 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5958 GetServiceDisplayNameW( scm, name, display_name, &len );
5961 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5964 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5968 vector = msi_service_args_to_vector(args, &numargs);
5970 if (!StartServiceW(service, numargs, vector) &&
5971 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5973 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5980 /* wait for at most 30 seconds for the service to be up and running */
5981 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5982 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5984 TRACE("failed to query service status (%u)\n", GetLastError());
5987 start_time = GetTickCount64();
5988 while (status.dwCurrentState == SERVICE_START_PENDING)
5990 if (GetTickCount64() - start_time > 30000) break;
5992 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5993 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5995 TRACE("failed to query service status (%u)\n", GetLastError());
5999 if (status.dwCurrentState != SERVICE_RUNNING)
6001 WARN("service failed to start %u\n", status.dwCurrentState);
6002 r = ERROR_FUNCTION_FAILED;
6007 uirow = MSI_CreateRecord( 2 );
6008 MSI_RecordSetStringW( uirow, 1, display_name );
6009 MSI_RecordSetStringW( uirow, 2, name );
6010 msi_ui_actiondata( package, szStartServices, uirow );
6011 msiobj_release( &uirow->hdr );
6013 CloseServiceHandle(service);
6014 CloseServiceHandle(scm);
6019 msi_free(display_name);
6023 static UINT ACTION_StartServices( MSIPACKAGE *package )
6025 static const WCHAR query[] = {
6026 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6027 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6031 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6032 if (rc != ERROR_SUCCESS)
6033 return ERROR_SUCCESS;
6035 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
6036 msiobj_release(&view->hdr);
6040 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6042 DWORD i, needed, count;
6043 ENUM_SERVICE_STATUSW *dependencies;
6047 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6048 0, &needed, &count))
6051 if (GetLastError() != ERROR_MORE_DATA)
6054 dependencies = msi_alloc(needed);
6058 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6059 needed, &needed, &count))
6062 for (i = 0; i < count; i++)
6064 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6065 SERVICE_STOP | SERVICE_QUERY_STATUS);
6069 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
6076 msi_free(dependencies);
6080 static UINT stop_service( LPCWSTR name )
6082 SC_HANDLE scm = NULL, service = NULL;
6083 SERVICE_STATUS status;
6084 SERVICE_STATUS_PROCESS ssp;
6087 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6090 WARN("Failed to open the SCM: %d\n", GetLastError());
6094 service = OpenServiceW(scm, name,
6096 SERVICE_QUERY_STATUS |
6097 SERVICE_ENUMERATE_DEPENDENTS);
6100 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
6104 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
6105 sizeof(SERVICE_STATUS_PROCESS), &needed))
6107 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
6111 if (ssp.dwCurrentState == SERVICE_STOPPED)
6114 stop_service_dependents(scm, service);
6116 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6117 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
6120 CloseServiceHandle(service);
6121 CloseServiceHandle(scm);
6123 return ERROR_SUCCESS;
6126 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6128 MSIPACKAGE *package = param;
6132 LPWSTR name = NULL, display_name = NULL;
6136 event = MSI_RecordGetInteger( rec, 3 );
6137 if (!(event & msidbServiceControlEventStop))
6138 return ERROR_SUCCESS;
6140 component = MSI_RecordGetString( rec, 6 );
6141 comp = msi_get_loaded_component( package, component );
6143 return ERROR_SUCCESS;
6145 comp->Action = msi_get_component_action( package, comp );
6146 if (comp->Action != INSTALLSTATE_ABSENT)
6148 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6149 return ERROR_SUCCESS;
6152 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6155 ERR("Failed to open the service control manager\n");
6160 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6161 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6163 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6164 GetServiceDisplayNameW( scm, name, display_name, &len );
6166 CloseServiceHandle( scm );
6168 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6169 stop_service( name );
6172 uirow = MSI_CreateRecord( 2 );
6173 MSI_RecordSetStringW( uirow, 1, display_name );
6174 MSI_RecordSetStringW( uirow, 2, name );
6175 msi_ui_actiondata( package, szStopServices, uirow );
6176 msiobj_release( &uirow->hdr );
6179 msi_free( display_name );
6180 return ERROR_SUCCESS;
6183 static UINT ACTION_StopServices( MSIPACKAGE *package )
6185 static const WCHAR query[] = {
6186 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6187 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6191 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6192 if (rc != ERROR_SUCCESS)
6193 return ERROR_SUCCESS;
6195 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6196 msiobj_release(&view->hdr);
6200 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6202 MSIPACKAGE *package = param;
6205 LPWSTR name = NULL, display_name = NULL;
6207 SC_HANDLE scm = NULL, service = NULL;
6209 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6211 return ERROR_SUCCESS;
6213 event = MSI_RecordGetInteger( rec, 3 );
6214 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6216 comp->Action = msi_get_component_action( package, comp );
6217 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6218 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6220 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6222 return ERROR_SUCCESS;
6224 stop_service( name );
6226 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6229 WARN("Failed to open the SCM: %d\n", GetLastError());
6234 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6235 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6237 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6238 GetServiceDisplayNameW( scm, name, display_name, &len );
6241 service = OpenServiceW( scm, name, DELETE );
6244 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6248 if (!DeleteService( service ))
6249 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6252 uirow = MSI_CreateRecord( 2 );
6253 MSI_RecordSetStringW( uirow, 1, display_name );
6254 MSI_RecordSetStringW( uirow, 2, name );
6255 msi_ui_actiondata( package, szDeleteServices, uirow );
6256 msiobj_release( &uirow->hdr );
6258 CloseServiceHandle( service );
6259 CloseServiceHandle( scm );
6261 msi_free( display_name );
6263 return ERROR_SUCCESS;
6266 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6268 static const WCHAR query[] = {
6269 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6270 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6274 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6275 if (rc != ERROR_SUCCESS)
6276 return ERROR_SUCCESS;
6278 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6279 msiobj_release( &view->hdr );
6283 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6285 MSIPACKAGE *package = param;
6286 LPWSTR driver, driver_path, ptr;
6287 WCHAR outpath[MAX_PATH];
6288 MSIFILE *driver_file = NULL, *setup_file = NULL;
6291 LPCWSTR desc, file_key, component;
6293 UINT r = ERROR_SUCCESS;
6295 static const WCHAR driver_fmt[] = {
6296 'D','r','i','v','e','r','=','%','s',0};
6297 static const WCHAR setup_fmt[] = {
6298 'S','e','t','u','p','=','%','s',0};
6299 static const WCHAR usage_fmt[] = {
6300 'F','i','l','e','U','s','a','g','e','=','1',0};
6302 component = MSI_RecordGetString( rec, 2 );
6303 comp = msi_get_loaded_component( package, component );
6305 return ERROR_SUCCESS;
6307 comp->Action = msi_get_component_action( package, comp );
6308 if (comp->Action != INSTALLSTATE_LOCAL)
6310 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6311 return ERROR_SUCCESS;
6313 desc = MSI_RecordGetString(rec, 3);
6315 file_key = MSI_RecordGetString( rec, 4 );
6316 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6318 file_key = MSI_RecordGetString( rec, 5 );
6319 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6323 ERR("ODBC Driver entry not found!\n");
6324 return ERROR_FUNCTION_FAILED;
6327 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6329 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6330 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6332 driver = msi_alloc(len * sizeof(WCHAR));
6334 return ERROR_OUTOFMEMORY;
6337 lstrcpyW(ptr, desc);
6338 ptr += lstrlenW(ptr) + 1;
6340 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6345 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6349 lstrcpyW(ptr, usage_fmt);
6350 ptr += lstrlenW(ptr) + 1;
6353 if (!driver_file->TargetPath)
6355 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6356 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6358 driver_path = strdupW(driver_file->TargetPath);
6359 ptr = strrchrW(driver_path, '\\');
6360 if (ptr) *ptr = '\0';
6362 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6363 NULL, ODBC_INSTALL_COMPLETE, &usage))
6365 ERR("Failed to install SQL driver!\n");
6366 r = ERROR_FUNCTION_FAILED;
6369 uirow = MSI_CreateRecord( 5 );
6370 MSI_RecordSetStringW( uirow, 1, desc );
6371 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6372 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6373 msi_ui_actiondata( package, szInstallODBC, uirow );
6374 msiobj_release( &uirow->hdr );
6377 msi_free(driver_path);
6382 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6384 MSIPACKAGE *package = param;
6385 LPWSTR translator, translator_path, ptr;
6386 WCHAR outpath[MAX_PATH];
6387 MSIFILE *translator_file = NULL, *setup_file = NULL;
6390 LPCWSTR desc, file_key, component;
6392 UINT r = ERROR_SUCCESS;
6394 static const WCHAR translator_fmt[] = {
6395 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6396 static const WCHAR setup_fmt[] = {
6397 'S','e','t','u','p','=','%','s',0};
6399 component = MSI_RecordGetString( rec, 2 );
6400 comp = msi_get_loaded_component( package, component );
6402 return ERROR_SUCCESS;
6404 comp->Action = msi_get_component_action( package, comp );
6405 if (comp->Action != INSTALLSTATE_LOCAL)
6407 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6408 return ERROR_SUCCESS;
6410 desc = MSI_RecordGetString(rec, 3);
6412 file_key = MSI_RecordGetString( rec, 4 );
6413 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6415 file_key = MSI_RecordGetString( rec, 5 );
6416 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6418 if (!translator_file)
6420 ERR("ODBC Translator entry not found!\n");
6421 return ERROR_FUNCTION_FAILED;
6424 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6426 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6428 translator = msi_alloc(len * sizeof(WCHAR));
6430 return ERROR_OUTOFMEMORY;
6433 lstrcpyW(ptr, desc);
6434 ptr += lstrlenW(ptr) + 1;
6436 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6441 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6446 translator_path = strdupW(translator_file->TargetPath);
6447 ptr = strrchrW(translator_path, '\\');
6448 if (ptr) *ptr = '\0';
6450 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6451 NULL, ODBC_INSTALL_COMPLETE, &usage))
6453 ERR("Failed to install SQL translator!\n");
6454 r = ERROR_FUNCTION_FAILED;
6457 uirow = MSI_CreateRecord( 5 );
6458 MSI_RecordSetStringW( uirow, 1, desc );
6459 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6460 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6461 msi_ui_actiondata( package, szInstallODBC, uirow );
6462 msiobj_release( &uirow->hdr );
6464 msi_free(translator);
6465 msi_free(translator_path);
6470 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6472 MSIPACKAGE *package = param;
6475 LPCWSTR desc, driver, component;
6476 WORD request = ODBC_ADD_SYS_DSN;
6479 UINT r = ERROR_SUCCESS;
6482 static const WCHAR attrs_fmt[] = {
6483 'D','S','N','=','%','s',0 };
6485 component = MSI_RecordGetString( rec, 2 );
6486 comp = msi_get_loaded_component( package, component );
6488 return ERROR_SUCCESS;
6490 comp->Action = msi_get_component_action( package, comp );
6491 if (comp->Action != INSTALLSTATE_LOCAL)
6493 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6494 return ERROR_SUCCESS;
6497 desc = MSI_RecordGetString(rec, 3);
6498 driver = MSI_RecordGetString(rec, 4);
6499 registration = MSI_RecordGetInteger(rec, 5);
6501 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6502 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6504 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6505 attrs = msi_alloc(len * sizeof(WCHAR));
6507 return ERROR_OUTOFMEMORY;
6509 len = sprintfW(attrs, attrs_fmt, desc);
6512 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6514 ERR("Failed to install SQL data source!\n");
6515 r = ERROR_FUNCTION_FAILED;
6518 uirow = MSI_CreateRecord( 5 );
6519 MSI_RecordSetStringW( uirow, 1, desc );
6520 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6521 MSI_RecordSetInteger( uirow, 3, request );
6522 msi_ui_actiondata( package, szInstallODBC, uirow );
6523 msiobj_release( &uirow->hdr );
6530 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6532 static const WCHAR driver_query[] = {
6533 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6534 'O','D','B','C','D','r','i','v','e','r',0};
6535 static const WCHAR translator_query[] = {
6536 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6537 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6538 static const WCHAR source_query[] = {
6539 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6540 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6544 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6545 if (rc == ERROR_SUCCESS)
6547 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6548 msiobj_release(&view->hdr);
6549 if (rc != ERROR_SUCCESS)
6552 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6553 if (rc == ERROR_SUCCESS)
6555 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6556 msiobj_release(&view->hdr);
6557 if (rc != ERROR_SUCCESS)
6560 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6561 if (rc == ERROR_SUCCESS)
6563 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6564 msiobj_release(&view->hdr);
6565 if (rc != ERROR_SUCCESS)
6568 return ERROR_SUCCESS;
6571 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6573 MSIPACKAGE *package = param;
6577 LPCWSTR desc, component;
6579 component = MSI_RecordGetString( rec, 2 );
6580 comp = msi_get_loaded_component( package, component );
6582 return ERROR_SUCCESS;
6584 comp->Action = msi_get_component_action( package, comp );
6585 if (comp->Action != INSTALLSTATE_ABSENT)
6587 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6588 return ERROR_SUCCESS;
6591 desc = MSI_RecordGetString( rec, 3 );
6592 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6594 WARN("Failed to remove ODBC driver\n");
6598 FIXME("Usage count reached 0\n");
6601 uirow = MSI_CreateRecord( 2 );
6602 MSI_RecordSetStringW( uirow, 1, desc );
6603 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6604 msi_ui_actiondata( package, szRemoveODBC, uirow );
6605 msiobj_release( &uirow->hdr );
6607 return ERROR_SUCCESS;
6610 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6612 MSIPACKAGE *package = param;
6616 LPCWSTR desc, component;
6618 component = MSI_RecordGetString( rec, 2 );
6619 comp = msi_get_loaded_component( package, component );
6621 return ERROR_SUCCESS;
6623 comp->Action = msi_get_component_action( package, comp );
6624 if (comp->Action != INSTALLSTATE_ABSENT)
6626 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6627 return ERROR_SUCCESS;
6630 desc = MSI_RecordGetString( rec, 3 );
6631 if (!SQLRemoveTranslatorW( desc, &usage ))
6633 WARN("Failed to remove ODBC translator\n");
6637 FIXME("Usage count reached 0\n");
6640 uirow = MSI_CreateRecord( 2 );
6641 MSI_RecordSetStringW( uirow, 1, desc );
6642 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6643 msi_ui_actiondata( package, szRemoveODBC, uirow );
6644 msiobj_release( &uirow->hdr );
6646 return ERROR_SUCCESS;
6649 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6651 MSIPACKAGE *package = param;
6655 LPCWSTR desc, driver, component;
6656 WORD request = ODBC_REMOVE_SYS_DSN;
6660 static const WCHAR attrs_fmt[] = {
6661 'D','S','N','=','%','s',0 };
6663 component = MSI_RecordGetString( rec, 2 );
6664 comp = msi_get_loaded_component( package, component );
6666 return ERROR_SUCCESS;
6668 comp->Action = msi_get_component_action( package, comp );
6669 if (comp->Action != INSTALLSTATE_ABSENT)
6671 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6672 return ERROR_SUCCESS;
6675 desc = MSI_RecordGetString( rec, 3 );
6676 driver = MSI_RecordGetString( rec, 4 );
6677 registration = MSI_RecordGetInteger( rec, 5 );
6679 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6680 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6682 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6683 attrs = msi_alloc( len * sizeof(WCHAR) );
6685 return ERROR_OUTOFMEMORY;
6687 FIXME("Use ODBCSourceAttribute table\n");
6689 len = sprintfW( attrs, attrs_fmt, desc );
6692 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6694 WARN("Failed to remove ODBC data source\n");
6698 uirow = MSI_CreateRecord( 3 );
6699 MSI_RecordSetStringW( uirow, 1, desc );
6700 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6701 MSI_RecordSetInteger( uirow, 3, request );
6702 msi_ui_actiondata( package, szRemoveODBC, uirow );
6703 msiobj_release( &uirow->hdr );
6705 return ERROR_SUCCESS;
6708 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6710 static const WCHAR driver_query[] = {
6711 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6712 'O','D','B','C','D','r','i','v','e','r',0};
6713 static const WCHAR translator_query[] = {
6714 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6715 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6716 static const WCHAR source_query[] = {
6717 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6718 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6722 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6723 if (rc == ERROR_SUCCESS)
6725 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6726 msiobj_release( &view->hdr );
6727 if (rc != ERROR_SUCCESS)
6730 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6731 if (rc == ERROR_SUCCESS)
6733 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6734 msiobj_release( &view->hdr );
6735 if (rc != ERROR_SUCCESS)
6738 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6739 if (rc == ERROR_SUCCESS)
6741 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6742 msiobj_release( &view->hdr );
6743 if (rc != ERROR_SUCCESS)
6746 return ERROR_SUCCESS;
6749 #define ENV_ACT_SETALWAYS 0x1
6750 #define ENV_ACT_SETABSENT 0x2
6751 #define ENV_ACT_REMOVE 0x4
6752 #define ENV_ACT_REMOVEMATCH 0x8
6754 #define ENV_MOD_MACHINE 0x20000000
6755 #define ENV_MOD_APPEND 0x40000000
6756 #define ENV_MOD_PREFIX 0x80000000
6757 #define ENV_MOD_MASK 0xC0000000
6759 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6761 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6763 LPCWSTR cptr = *name;
6765 static const WCHAR prefix[] = {'[','~',']',0};
6766 static const int prefix_len = 3;
6772 *flags |= ENV_ACT_SETALWAYS;
6773 else if (*cptr == '+')
6774 *flags |= ENV_ACT_SETABSENT;
6775 else if (*cptr == '-')
6776 *flags |= ENV_ACT_REMOVE;
6777 else if (*cptr == '!')
6778 *flags |= ENV_ACT_REMOVEMATCH;
6779 else if (*cptr == '*')
6780 *flags |= ENV_MOD_MACHINE;
6790 ERR("Missing environment variable\n");
6791 return ERROR_FUNCTION_FAILED;
6796 LPCWSTR ptr = *value;
6797 if (!strncmpW(ptr, prefix, prefix_len))
6799 if (ptr[prefix_len] == szSemiColon[0])
6801 *flags |= ENV_MOD_APPEND;
6802 *value += lstrlenW(prefix);
6809 else if (lstrlenW(*value) >= prefix_len)
6811 ptr += lstrlenW(ptr) - prefix_len;
6812 if (!strcmpW( ptr, prefix ))
6814 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6816 *flags |= ENV_MOD_PREFIX;
6817 /* the "[~]" will be removed by deformat_string */;
6827 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6828 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6829 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6830 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6832 ERR("Invalid flags: %08x\n", *flags);
6833 return ERROR_FUNCTION_FAILED;
6837 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6839 return ERROR_SUCCESS;
6842 static UINT open_env_key( DWORD flags, HKEY *key )
6844 static const WCHAR user_env[] =
6845 {'E','n','v','i','r','o','n','m','e','n','t',0};
6846 static const WCHAR machine_env[] =
6847 {'S','y','s','t','e','m','\\',
6848 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6849 'C','o','n','t','r','o','l','\\',
6850 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6851 'E','n','v','i','r','o','n','m','e','n','t',0};
6856 if (flags & ENV_MOD_MACHINE)
6859 root = HKEY_LOCAL_MACHINE;
6864 root = HKEY_CURRENT_USER;
6867 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6868 if (res != ERROR_SUCCESS)
6870 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6871 return ERROR_FUNCTION_FAILED;
6874 return ERROR_SUCCESS;
6877 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6879 MSIPACKAGE *package = param;
6880 LPCWSTR name, value, component;
6881 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6882 DWORD flags, type, size;
6889 component = MSI_RecordGetString(rec, 4);
6890 comp = msi_get_loaded_component(package, component);
6892 return ERROR_SUCCESS;
6894 comp->Action = msi_get_component_action( package, comp );
6895 if (comp->Action != INSTALLSTATE_LOCAL)
6897 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6898 return ERROR_SUCCESS;
6900 name = MSI_RecordGetString(rec, 2);
6901 value = MSI_RecordGetString(rec, 3);
6903 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6905 res = env_parse_flags(&name, &value, &flags);
6906 if (res != ERROR_SUCCESS || !value)
6909 if (value && !deformat_string(package, value, &deformatted))
6911 res = ERROR_OUTOFMEMORY;
6915 value = deformatted;
6917 res = open_env_key( flags, &env );
6918 if (res != ERROR_SUCCESS)
6921 if (flags & ENV_MOD_MACHINE)
6922 action |= 0x20000000;
6926 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6927 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6928 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6931 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6935 /* Nothing to do. */
6938 res = ERROR_SUCCESS;
6942 /* If we are appending but the string was empty, strip ; */
6943 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6945 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6946 newval = strdupW(value);
6949 res = ERROR_OUTOFMEMORY;
6957 /* Contrary to MSDN, +-variable to [~];path works */
6958 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6960 res = ERROR_SUCCESS;
6964 data = msi_alloc(size);
6968 return ERROR_OUTOFMEMORY;
6971 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6972 if (res != ERROR_SUCCESS)
6975 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6978 res = RegDeleteValueW(env, name);
6979 if (res != ERROR_SUCCESS)
6980 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6984 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6985 if (flags & ENV_MOD_MASK)
6989 if (flags & ENV_MOD_APPEND) multiplier++;
6990 if (flags & ENV_MOD_PREFIX) multiplier++;
6991 mod_size = lstrlenW(value) * multiplier;
6992 size += mod_size * sizeof(WCHAR);
6995 newval = msi_alloc(size);
6999 res = ERROR_OUTOFMEMORY;
7003 if (flags & ENV_MOD_PREFIX)
7005 lstrcpyW(newval, value);
7006 ptr = newval + lstrlenW(value);
7007 action |= 0x80000000;
7010 lstrcpyW(ptr, data);
7012 if (flags & ENV_MOD_APPEND)
7014 lstrcatW(newval, value);
7015 action |= 0x40000000;
7018 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
7019 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
7022 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7026 uirow = MSI_CreateRecord( 3 );
7027 MSI_RecordSetStringW( uirow, 1, name );
7028 MSI_RecordSetStringW( uirow, 2, newval );
7029 MSI_RecordSetInteger( uirow, 3, action );
7030 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
7031 msiobj_release( &uirow->hdr );
7033 if (env) RegCloseKey(env);
7034 msi_free(deformatted);
7040 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7042 static const WCHAR query[] = {
7043 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7044 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7048 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
7049 if (rc != ERROR_SUCCESS)
7050 return ERROR_SUCCESS;
7052 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7053 msiobj_release(&view->hdr);
7057 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7059 MSIPACKAGE *package = param;
7060 LPCWSTR name, value, component;
7061 LPWSTR deformatted = NULL;
7070 component = MSI_RecordGetString( rec, 4 );
7071 comp = msi_get_loaded_component( package, component );
7073 return ERROR_SUCCESS;
7075 comp->Action = msi_get_component_action( package, comp );
7076 if (comp->Action != INSTALLSTATE_ABSENT)
7078 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
7079 return ERROR_SUCCESS;
7081 name = MSI_RecordGetString( rec, 2 );
7082 value = MSI_RecordGetString( rec, 3 );
7084 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7086 r = env_parse_flags( &name, &value, &flags );
7087 if (r != ERROR_SUCCESS)
7090 if (!(flags & ENV_ACT_REMOVE))
7092 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7093 return ERROR_SUCCESS;
7096 if (value && !deformat_string( package, value, &deformatted ))
7097 return ERROR_OUTOFMEMORY;
7099 value = deformatted;
7101 r = open_env_key( flags, &env );
7102 if (r != ERROR_SUCCESS)
7108 if (flags & ENV_MOD_MACHINE)
7109 action |= 0x20000000;
7111 TRACE("Removing %s\n", debugstr_w(name));
7113 res = RegDeleteValueW( env, name );
7114 if (res != ERROR_SUCCESS)
7116 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
7121 uirow = MSI_CreateRecord( 3 );
7122 MSI_RecordSetStringW( uirow, 1, name );
7123 MSI_RecordSetStringW( uirow, 2, value );
7124 MSI_RecordSetInteger( uirow, 3, action );
7125 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
7126 msiobj_release( &uirow->hdr );
7128 if (env) RegCloseKey( env );
7129 msi_free( deformatted );
7133 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7135 static const WCHAR query[] = {
7136 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7137 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7141 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
7142 if (rc != ERROR_SUCCESS)
7143 return ERROR_SUCCESS;
7145 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7146 msiobj_release( &view->hdr );
7150 UINT msi_validate_product_id( MSIPACKAGE *package )
7152 LPWSTR key, template, id;
7153 UINT r = ERROR_SUCCESS;
7155 id = msi_dup_property( package->db, szProductID );
7159 return ERROR_SUCCESS;
7161 template = msi_dup_property( package->db, szPIDTemplate );
7162 key = msi_dup_property( package->db, szPIDKEY );
7163 if (key && template)
7165 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7166 r = msi_set_property( package->db, szProductID, key, -1 );
7168 msi_free( template );
7173 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7175 return msi_validate_product_id( package );
7178 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7181 package->need_reboot_at_end = 1;
7182 return ERROR_SUCCESS;
7185 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7187 static const WCHAR szAvailableFreeReg[] =
7188 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7190 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7192 TRACE("%p %d kilobytes\n", package, space);
7194 uirow = MSI_CreateRecord( 1 );
7195 MSI_RecordSetInteger( uirow, 1, space );
7196 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
7197 msiobj_release( &uirow->hdr );
7199 return ERROR_SUCCESS;
7202 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7204 TRACE("%p\n", package);
7206 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7207 return ERROR_SUCCESS;
7210 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7212 FIXME("%p\n", package);
7213 return ERROR_SUCCESS;
7216 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7218 static const WCHAR driver_query[] = {
7219 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7220 'O','D','B','C','D','r','i','v','e','r',0};
7221 static const WCHAR translator_query[] = {
7222 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7223 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
7227 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7228 if (r == ERROR_SUCCESS)
7231 r = MSI_IterateRecords( view, &count, NULL, package );
7232 msiobj_release( &view->hdr );
7233 if (r != ERROR_SUCCESS)
7235 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7237 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7238 if (r == ERROR_SUCCESS)
7241 r = MSI_IterateRecords( view, &count, NULL, package );
7242 msiobj_release( &view->hdr );
7243 if (r != ERROR_SUCCESS)
7245 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7247 return ERROR_SUCCESS;
7250 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7252 static const WCHAR fmtW[] =
7253 {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0};
7254 MSIPACKAGE *package = param;
7255 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7256 UINT len = sizeof(fmtW)/sizeof(fmtW[0]);
7257 WCHAR *product, *features, *cmd;
7259 PROCESS_INFORMATION info;
7262 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7264 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7266 len += strlenW( product );
7268 len += strlenW( features );
7270 len += sizeof(szAll) / sizeof(szAll[0]);
7272 if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
7274 msi_free( product );
7275 msi_free( features );
7276 return ERROR_OUTOFMEMORY;
7278 sprintfW( cmd, fmtW, product, features ? features : szAll );
7279 msi_free( product );
7280 msi_free( features );
7282 memset( &si, 0, sizeof(STARTUPINFOW) );
7283 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7285 if (!ret) return GetLastError();
7286 CloseHandle( info.hThread );
7288 WaitForSingleObject( info.hProcess, INFINITE );
7289 CloseHandle( info.hProcess );
7290 return ERROR_SUCCESS;
7293 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7295 static const WCHAR query[] = {
7296 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7300 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7301 if (r == ERROR_SUCCESS)
7303 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7304 msiobj_release( &view->hdr );
7305 if (r != ERROR_SUCCESS)
7308 return ERROR_SUCCESS;
7311 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7313 MSIPACKAGE *package = param;
7314 int attributes = MSI_RecordGetInteger( rec, 5 );
7316 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7318 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7319 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7320 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7321 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7325 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7327 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7328 if (r != ERROR_SUCCESS)
7329 return ERROR_SUCCESS;
7333 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7334 if (r != ERROR_SUCCESS)
7335 return ERROR_SUCCESS;
7337 RegCloseKey( hkey );
7339 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7340 debugstr_w(upgrade_code), debugstr_w(version_min),
7341 debugstr_w(version_max), debugstr_w(language));
7343 return ERROR_SUCCESS;
7346 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7348 static const WCHAR query[] = {
7349 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7350 'U','p','g','r','a','d','e',0};
7354 if (msi_get_property_int( package->db, szInstalled, 0 ))
7356 TRACE("product is installed, skipping action\n");
7357 return ERROR_SUCCESS;
7359 if (msi_get_property_int( package->db, szPreselected, 0 ))
7361 TRACE("Preselected property is set, not migrating feature states\n");
7362 return ERROR_SUCCESS;
7364 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7365 if (r == ERROR_SUCCESS)
7367 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7368 msiobj_release( &view->hdr );
7369 if (r != ERROR_SUCCESS)
7372 return ERROR_SUCCESS;
7375 static void bind_image( const char *filename, const char *path )
7377 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7379 WARN("failed to bind image %u\n", GetLastError());
7383 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7387 MSIPACKAGE *package = param;
7388 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7389 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7390 char *filenameA, *pathA;
7391 WCHAR *pathW, **path_list;
7393 if (!(file = msi_get_loaded_file( package, key )))
7395 WARN("file %s not found\n", debugstr_w(key));
7396 return ERROR_SUCCESS;
7398 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7399 path_list = msi_split_string( paths, ';' );
7400 if (!path_list) bind_image( filenameA, NULL );
7403 for (i = 0; path_list[i] && path_list[i][0]; i++)
7405 deformat_string( package, path_list[i], &pathW );
7406 if ((pathA = strdupWtoA( pathW )))
7408 bind_image( filenameA, pathA );
7414 msi_free( path_list );
7415 msi_free( filenameA );
7416 return ERROR_SUCCESS;
7419 static UINT ACTION_BindImage( MSIPACKAGE *package )
7421 static const WCHAR query[] = {
7422 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7423 'B','i','n','d','I','m','a','g','e',0};
7427 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7428 if (r == ERROR_SUCCESS)
7430 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7431 msiobj_release( &view->hdr );
7432 if (r != ERROR_SUCCESS)
7435 return ERROR_SUCCESS;
7438 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7440 static const WCHAR query[] = {
7441 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7446 r = MSI_OpenQuery( package->db, &view, query, table );
7447 if (r == ERROR_SUCCESS)
7449 r = MSI_IterateRecords(view, &count, NULL, package);
7450 msiobj_release(&view->hdr);
7451 if (r != ERROR_SUCCESS)
7454 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7455 return ERROR_SUCCESS;
7458 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7460 static const WCHAR table[] = {
7461 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7462 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7465 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7467 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7468 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7471 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7473 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7474 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7477 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7479 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7480 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7483 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7485 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7486 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7491 const WCHAR *action;
7492 UINT (*handler)(MSIPACKAGE *);
7493 const WCHAR *action_rollback;
7497 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7498 { szAppSearch, ACTION_AppSearch, NULL },
7499 { szBindImage, ACTION_BindImage, NULL },
7500 { szCCPSearch, ACTION_CCPSearch, NULL },
7501 { szCostFinalize, ACTION_CostFinalize, NULL },
7502 { szCostInitialize, ACTION_CostInitialize, NULL },
7503 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7504 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7505 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7506 { szDisableRollback, ACTION_DisableRollback, NULL },
7507 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7508 { szExecuteAction, ACTION_ExecuteAction, NULL },
7509 { szFileCost, ACTION_FileCost, NULL },
7510 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7511 { szForceReboot, ACTION_ForceReboot, NULL },
7512 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7513 { szInstallExecute, ACTION_InstallExecute, NULL },
7514 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7515 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7516 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7517 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7518 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7519 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7520 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7521 { szInstallValidate, ACTION_InstallValidate, NULL },
7522 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7523 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7524 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7525 { szMoveFiles, ACTION_MoveFiles, NULL },
7526 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7527 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7528 { szPatchFiles, ACTION_PatchFiles, NULL },
7529 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7530 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7531 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7532 { szPublishProduct, ACTION_PublishProduct, NULL },
7533 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7534 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7535 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7536 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7537 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7538 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7539 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7540 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7541 { szRegisterUser, ACTION_RegisterUser, NULL },
7542 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7543 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7544 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7545 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7546 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7547 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7548 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7549 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7550 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7551 { szResolveSource, ACTION_ResolveSource, NULL },
7552 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7553 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7554 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7555 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7556 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7557 { szStartServices, ACTION_StartServices, szStopServices },
7558 { szStopServices, ACTION_StopServices, szStartServices },
7559 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7560 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7561 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7562 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7563 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7564 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7565 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7566 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7567 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7568 { szValidateProductID, ACTION_ValidateProductID, NULL },
7569 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7570 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7571 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7572 { NULL, NULL, NULL }
7575 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7581 while (StandardActions[i].action != NULL)
7583 if (!strcmpW( StandardActions[i].action, action ))
7585 ui_actionstart( package, action );
7586 if (StandardActions[i].handler)
7588 ui_actioninfo( package, action, TRUE, 0 );
7589 *rc = StandardActions[i].handler( package );
7590 ui_actioninfo( package, action, FALSE, *rc );
7592 if (StandardActions[i].action_rollback && !package->need_rollback)
7594 TRACE("scheduling rollback action\n");
7595 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7600 FIXME("unhandled standard action %s\n", debugstr_w(action));
7601 *rc = ERROR_SUCCESS;
7611 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7613 UINT rc = ERROR_SUCCESS;
7616 TRACE("Performing action (%s)\n", debugstr_w(action));
7618 handled = ACTION_HandleStandardAction(package, action, &rc);
7621 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7625 WARN("unhandled msi action %s\n", debugstr_w(action));
7626 rc = ERROR_FUNCTION_NOT_CALLED;
7632 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7634 UINT rc = ERROR_SUCCESS;
7635 BOOL handled = FALSE;
7637 TRACE("Performing action (%s)\n", debugstr_w(action));
7639 package->action_progress_increment = 0;
7640 handled = ACTION_HandleStandardAction(package, action, &rc);
7643 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7645 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7650 WARN("unhandled msi action %s\n", debugstr_w(action));
7651 rc = ERROR_FUNCTION_NOT_CALLED;
7657 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7659 UINT rc = ERROR_SUCCESS;
7662 static const WCHAR query[] =
7663 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7664 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7665 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7666 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7667 static const WCHAR ui_query[] =
7668 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7669 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7670 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7671 ' ', '=',' ','%','i',0};
7673 if (needs_ui_sequence(package))
7674 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7676 row = MSI_QueryGetRecord(package->db, query, seq);
7680 LPCWSTR action, cond;
7682 TRACE("Running the actions\n");
7684 /* check conditions */
7685 cond = MSI_RecordGetString(row, 2);
7687 /* this is a hack to skip errors in the condition code */
7688 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7690 msiobj_release(&row->hdr);
7691 return ERROR_SUCCESS;
7694 action = MSI_RecordGetString(row, 1);
7697 ERR("failed to fetch action\n");
7698 msiobj_release(&row->hdr);
7699 return ERROR_FUNCTION_FAILED;
7702 if (needs_ui_sequence(package))
7703 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7705 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7707 msiobj_release(&row->hdr);
7713 /****************************************************
7714 * TOP level entry points
7715 *****************************************************/
7717 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7718 LPCWSTR szCommandLine )
7720 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7721 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7722 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7723 WCHAR *reinstall, *remove;
7727 msi_set_property( package->db, szAction, szInstall, -1 );
7729 package->script->InWhatSequence = SEQUENCE_INSTALL;
7736 dir = strdupW(szPackagePath);
7737 p = strrchrW(dir, '\\');
7741 file = szPackagePath + (p - dir);
7746 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7747 GetCurrentDirectoryW(MAX_PATH, dir);
7748 lstrcatW(dir, szBackSlash);
7749 file = szPackagePath;
7752 msi_free( package->PackagePath );
7753 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7754 if (!package->PackagePath)
7757 return ERROR_OUTOFMEMORY;
7760 lstrcpyW(package->PackagePath, dir);
7761 lstrcatW(package->PackagePath, file);
7764 msi_set_sourcedir_props(package, FALSE);
7767 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7768 if (rc != ERROR_SUCCESS)
7771 msi_apply_transforms( package );
7772 msi_apply_patches( package );
7774 remove = msi_dup_property( package->db, szRemove );
7775 reinstall = msi_dup_property( package->db, szReinstall );
7776 if (msi_get_property_int( package->db, szInstalled, 0 ) && !remove && !reinstall)
7778 TRACE("setting REINSTALL property to ALL\n");
7779 msi_set_property( package->db, szReinstall, szAll, -1 );
7782 /* properties may have been added by a transform */
7783 msi_clone_properties( package );
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 );
7838 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7839 return ERROR_SUCCESS_REBOOT_REQUIRED;