2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
191 sprintfW(message,template_s,timet,action);
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
221 case state_whitespace:
231 if (in_quotes && p[1] != '\"') count--;
247 if (in_quotes) count--;
251 state = state_whitespace;
252 if (!count) goto done;
257 if (!count) in_quotes = 0;
268 if (in_quotes && p[1] != '\"') count--;
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
279 if (!count) in_quotes = 0;
288 if (!ignore) *out++ = *p;
292 if (!len) *value = 0;
299 static void remove_quotes( WCHAR *str )
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
321 return ERROR_SUCCESS;
326 while (*ptr == ' ') ptr++;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
338 if (!preserve_case) struprW( prop );
341 while (*ptr2 == ' ') ptr2++;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
348 WARN("unbalanced quotes\n");
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val, -1 );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
372 LPWSTR p, *ret = NULL;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
395 for( count = 0; (ret[count] = p); count++ )
397 p = strchrW( p, sep );
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 db = msi_dup_property( package->db, szOriginalDatabase );
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
448 p = strrchrW( db, '/' );
452 return ERROR_SUCCESS;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source, -1 );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source, -1 );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
543 rc = ACTION_ForceReboot( package );
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property( package->db, szSourceDir, NULL, -1 );
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
736 if (!(slash = strrchrW( new_path, '\\' )))
741 len = slash - new_path;
743 if (!msi_create_full_path( new_path ))
748 new_path[len] = '\\';
750 msi_free( new_path );
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
814 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
815 return INSTALLSTATE_UNKNOWN;
817 return comp->ActionRequest;
820 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
822 if (package->need_rollback) return feature->Installed;
823 return feature->ActionRequest;
826 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
828 MSIPACKAGE *package = param;
829 LPCWSTR dir, component, full_path;
834 component = MSI_RecordGetString(row, 2);
836 return ERROR_SUCCESS;
838 comp = msi_get_loaded_component(package, component);
840 return ERROR_SUCCESS;
842 comp->Action = msi_get_component_action( package, comp );
843 if (comp->Action != INSTALLSTATE_LOCAL)
845 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
846 return ERROR_SUCCESS;
849 dir = MSI_RecordGetString(row,1);
852 ERR("Unable to get folder id\n");
853 return ERROR_SUCCESS;
856 uirow = MSI_CreateRecord(1);
857 MSI_RecordSetStringW(uirow, 1, dir);
858 msi_ui_actiondata(package, szCreateFolders, uirow);
859 msiobj_release(&uirow->hdr);
861 full_path = msi_get_target_folder( package, dir );
864 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
865 return ERROR_SUCCESS;
867 TRACE("folder is %s\n", debugstr_w(full_path));
869 folder = msi_get_loaded_folder( package, dir );
870 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
871 folder->State = FOLDER_STATE_CREATED;
872 return ERROR_SUCCESS;
875 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
877 static const WCHAR query[] = {
878 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
879 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
883 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
884 if (rc != ERROR_SUCCESS)
885 return ERROR_SUCCESS;
887 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
888 msiobj_release(&view->hdr);
892 static void remove_persistent_folder( MSIFOLDER *folder )
896 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
898 remove_persistent_folder( fl->folder );
900 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
902 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
906 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
908 MSIPACKAGE *package = param;
909 LPCWSTR dir, component, full_path;
914 component = MSI_RecordGetString(row, 2);
916 return ERROR_SUCCESS;
918 comp = msi_get_loaded_component(package, component);
920 return ERROR_SUCCESS;
922 comp->Action = msi_get_component_action( package, comp );
923 if (comp->Action != INSTALLSTATE_ABSENT)
925 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
926 return ERROR_SUCCESS;
929 dir = MSI_RecordGetString( row, 1 );
932 ERR("Unable to get folder id\n");
933 return ERROR_SUCCESS;
936 full_path = msi_get_target_folder( package, dir );
939 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
940 return ERROR_SUCCESS;
942 TRACE("folder is %s\n", debugstr_w(full_path));
944 uirow = MSI_CreateRecord( 1 );
945 MSI_RecordSetStringW( uirow, 1, dir );
946 msi_ui_actiondata( package, szRemoveFolders, uirow );
947 msiobj_release( &uirow->hdr );
949 folder = msi_get_loaded_folder( package, dir );
950 remove_persistent_folder( folder );
951 return ERROR_SUCCESS;
954 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
956 static const WCHAR query[] = {
957 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
958 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
962 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
963 if (rc != ERROR_SUCCESS)
964 return ERROR_SUCCESS;
966 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
967 msiobj_release( &view->hdr );
971 static UINT load_component( MSIRECORD *row, LPVOID param )
973 MSIPACKAGE *package = param;
976 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
978 return ERROR_FUNCTION_FAILED;
980 list_add_tail( &package->components, &comp->entry );
982 /* fill in the data */
983 comp->Component = msi_dup_record_field( row, 1 );
985 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
987 comp->ComponentId = msi_dup_record_field( row, 2 );
988 comp->Directory = msi_dup_record_field( row, 3 );
989 comp->Attributes = MSI_RecordGetInteger(row,4);
990 comp->Condition = msi_dup_record_field( row, 5 );
991 comp->KeyPath = msi_dup_record_field( row, 6 );
993 comp->Installed = INSTALLSTATE_UNKNOWN;
994 comp->Action = INSTALLSTATE_UNKNOWN;
995 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
997 comp->assembly = msi_load_assembly( package, comp );
998 return ERROR_SUCCESS;
1001 UINT msi_load_all_components( MSIPACKAGE *package )
1003 static const WCHAR query[] = {
1004 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1005 '`','C','o','m','p','o','n','e','n','t','`',0};
1009 if (!list_empty(&package->components))
1010 return ERROR_SUCCESS;
1012 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1013 if (r != ERROR_SUCCESS)
1016 if (!msi_init_assembly_caches( package ))
1018 ERR("can't initialize assembly caches\n");
1019 msiobj_release( &view->hdr );
1020 return ERROR_FUNCTION_FAILED;
1023 r = MSI_IterateRecords(view, NULL, load_component, package);
1024 msiobj_release(&view->hdr);
1029 MSIPACKAGE *package;
1030 MSIFEATURE *feature;
1033 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1037 cl = msi_alloc( sizeof (*cl) );
1039 return ERROR_NOT_ENOUGH_MEMORY;
1040 cl->component = comp;
1041 list_add_tail( &feature->Components, &cl->entry );
1043 return ERROR_SUCCESS;
1046 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1050 fl = msi_alloc( sizeof(*fl) );
1052 return ERROR_NOT_ENOUGH_MEMORY;
1053 fl->feature = child;
1054 list_add_tail( &parent->Children, &fl->entry );
1056 return ERROR_SUCCESS;
1059 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1061 _ilfs* ilfs = param;
1065 component = MSI_RecordGetString(row,1);
1067 /* check to see if the component is already loaded */
1068 comp = msi_get_loaded_component( ilfs->package, component );
1071 WARN("ignoring unknown component %s\n", debugstr_w(component));
1072 return ERROR_SUCCESS;
1074 add_feature_component( ilfs->feature, comp );
1075 comp->Enabled = TRUE;
1077 return ERROR_SUCCESS;
1080 static UINT load_feature(MSIRECORD * row, LPVOID param)
1082 static const WCHAR query[] = {
1083 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1084 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1085 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1086 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1087 MSIPACKAGE *package = param;
1088 MSIFEATURE *feature;
1093 /* fill in the data */
1095 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1097 return ERROR_NOT_ENOUGH_MEMORY;
1099 list_init( &feature->Children );
1100 list_init( &feature->Components );
1102 feature->Feature = msi_dup_record_field( row, 1 );
1104 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1106 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1107 feature->Title = msi_dup_record_field( row, 3 );
1108 feature->Description = msi_dup_record_field( row, 4 );
1110 if (!MSI_RecordIsNull(row,5))
1111 feature->Display = MSI_RecordGetInteger(row,5);
1113 feature->Level= MSI_RecordGetInteger(row,6);
1114 feature->Directory = msi_dup_record_field( row, 7 );
1115 feature->Attributes = MSI_RecordGetInteger(row,8);
1117 feature->Installed = INSTALLSTATE_UNKNOWN;
1118 feature->Action = INSTALLSTATE_UNKNOWN;
1119 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1121 list_add_tail( &package->features, &feature->entry );
1123 /* load feature components */
1125 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1126 if (rc != ERROR_SUCCESS)
1127 return ERROR_SUCCESS;
1129 ilfs.package = package;
1130 ilfs.feature = feature;
1132 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1133 msiobj_release(&view->hdr);
1137 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1139 MSIPACKAGE *package = param;
1140 MSIFEATURE *parent, *child;
1142 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1144 return ERROR_FUNCTION_FAILED;
1146 if (!child->Feature_Parent)
1147 return ERROR_SUCCESS;
1149 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1151 return ERROR_FUNCTION_FAILED;
1153 add_feature_child( parent, child );
1154 return ERROR_SUCCESS;
1157 UINT msi_load_all_features( MSIPACKAGE *package )
1159 static const WCHAR query[] = {
1160 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1161 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1162 '`','D','i','s','p','l','a','y','`',0};
1166 if (!list_empty(&package->features))
1167 return ERROR_SUCCESS;
1169 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1170 if (r != ERROR_SUCCESS)
1173 r = MSI_IterateRecords( view, NULL, load_feature, package );
1174 if (r != ERROR_SUCCESS)
1176 msiobj_release( &view->hdr );
1179 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1180 msiobj_release( &view->hdr );
1184 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1195 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1197 static const WCHAR query[] = {
1198 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1199 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1200 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1201 MSIQUERY *view = NULL;
1202 MSIRECORD *row = NULL;
1205 TRACE("%s\n", debugstr_w(file->File));
1207 r = MSI_OpenQuery(package->db, &view, query, file->File);
1208 if (r != ERROR_SUCCESS)
1211 r = MSI_ViewExecute(view, NULL);
1212 if (r != ERROR_SUCCESS)
1215 r = MSI_ViewFetch(view, &row);
1216 if (r != ERROR_SUCCESS)
1219 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1220 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1221 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1222 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1223 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1226 if (view) msiobj_release(&view->hdr);
1227 if (row) msiobj_release(&row->hdr);
1231 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1234 static const WCHAR query[] = {
1235 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1236 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1237 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1239 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1242 WARN("query failed\n");
1243 return ERROR_FUNCTION_FAILED;
1246 file->disk_id = MSI_RecordGetInteger( row, 1 );
1247 msiobj_release( &row->hdr );
1248 return ERROR_SUCCESS;
1251 static UINT load_file(MSIRECORD *row, LPVOID param)
1253 MSIPACKAGE* package = param;
1257 /* fill in the data */
1259 file = msi_alloc_zero( sizeof (MSIFILE) );
1261 return ERROR_NOT_ENOUGH_MEMORY;
1263 file->File = msi_dup_record_field( row, 1 );
1265 component = MSI_RecordGetString( row, 2 );
1266 file->Component = msi_get_loaded_component( package, component );
1268 if (!file->Component)
1270 WARN("Component not found: %s\n", debugstr_w(component));
1271 msi_free(file->File);
1273 return ERROR_SUCCESS;
1276 file->FileName = msi_dup_record_field( row, 3 );
1277 msi_reduce_to_long_filename( file->FileName );
1279 file->ShortName = msi_dup_record_field( row, 3 );
1280 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1282 file->FileSize = MSI_RecordGetInteger( row, 4 );
1283 file->Version = msi_dup_record_field( row, 5 );
1284 file->Language = msi_dup_record_field( row, 6 );
1285 file->Attributes = MSI_RecordGetInteger( row, 7 );
1286 file->Sequence = MSI_RecordGetInteger( row, 8 );
1288 file->state = msifs_invalid;
1290 /* if the compressed bits are not set in the file attributes,
1291 * then read the information from the package word count property
1293 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1295 file->IsCompressed = FALSE;
1297 else if (file->Attributes &
1298 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1300 file->IsCompressed = TRUE;
1302 else if (file->Attributes & msidbFileAttributesNoncompressed)
1304 file->IsCompressed = FALSE;
1308 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1311 load_file_hash(package, file);
1312 load_file_disk_id(package, file);
1314 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1316 list_add_tail( &package->files, &file->entry );
1318 return ERROR_SUCCESS;
1321 static UINT load_all_files(MSIPACKAGE *package)
1323 static const WCHAR query[] = {
1324 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1325 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1326 '`','S','e','q','u','e','n','c','e','`', 0};
1330 if (!list_empty(&package->files))
1331 return ERROR_SUCCESS;
1333 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1334 if (rc != ERROR_SUCCESS)
1335 return ERROR_SUCCESS;
1337 rc = MSI_IterateRecords(view, NULL, load_file, package);
1338 msiobj_release(&view->hdr);
1342 static UINT load_media( MSIRECORD *row, LPVOID param )
1344 MSIPACKAGE *package = param;
1345 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1346 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1348 /* FIXME: load external cabinets and directory sources too */
1349 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1350 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1351 return ERROR_SUCCESS;
1354 static UINT load_all_media( MSIPACKAGE *package )
1356 static const WCHAR query[] = {
1357 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1358 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1359 '`','D','i','s','k','I','d','`',0};
1363 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1364 if (r != ERROR_SUCCESS)
1365 return ERROR_SUCCESS;
1367 r = MSI_IterateRecords( view, NULL, load_media, package );
1368 msiobj_release( &view->hdr );
1372 static UINT load_patch(MSIRECORD *row, LPVOID param)
1374 MSIPACKAGE *package = param;
1375 MSIFILEPATCH *patch;
1378 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1380 return ERROR_NOT_ENOUGH_MEMORY;
1382 file_key = msi_dup_record_field( row, 1 );
1383 patch->File = msi_get_loaded_file( package, file_key );
1388 ERR("Failed to find target for patch in File table\n");
1390 return ERROR_FUNCTION_FAILED;
1393 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1395 /* FIXME: The database should be properly transformed */
1396 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1398 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1399 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1400 patch->IsApplied = FALSE;
1403 * Header field - for patch validation.
1404 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1407 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1409 list_add_tail( &package->filepatches, &patch->entry );
1411 return ERROR_SUCCESS;
1414 static UINT load_all_patches(MSIPACKAGE *package)
1416 static const WCHAR query[] = {
1417 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1418 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1419 '`','S','e','q','u','e','n','c','e','`',0};
1423 if (!list_empty(&package->filepatches))
1424 return ERROR_SUCCESS;
1426 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1427 if (rc != ERROR_SUCCESS)
1428 return ERROR_SUCCESS;
1430 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1431 msiobj_release(&view->hdr);
1435 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1437 static const WCHAR query[] = {
1438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1439 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1440 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1443 folder->persistent = FALSE;
1444 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1446 if (!MSI_ViewExecute( view, NULL ))
1449 if (!MSI_ViewFetch( view, &rec ))
1451 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1452 folder->persistent = TRUE;
1453 msiobj_release( &rec->hdr );
1456 msiobj_release( &view->hdr );
1458 return ERROR_SUCCESS;
1461 static UINT load_folder( MSIRECORD *row, LPVOID param )
1463 MSIPACKAGE *package = param;
1464 static WCHAR szEmpty[] = { 0 };
1465 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1468 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1469 list_init( &folder->children );
1470 folder->Directory = msi_dup_record_field( row, 1 );
1471 folder->Parent = msi_dup_record_field( row, 2 );
1472 p = msi_dup_record_field(row, 3);
1474 TRACE("%s\n", debugstr_w(folder->Directory));
1476 /* split src and target dir */
1478 src_short = folder_split_path( p, ':' );
1480 /* split the long and short paths */
1481 tgt_long = folder_split_path( tgt_short, '|' );
1482 src_long = folder_split_path( src_short, '|' );
1484 /* check for no-op dirs */
1485 if (tgt_short && !strcmpW( szDot, tgt_short ))
1486 tgt_short = szEmpty;
1487 if (src_short && !strcmpW( szDot, src_short ))
1488 src_short = szEmpty;
1491 tgt_long = tgt_short;
1494 src_short = tgt_short;
1495 src_long = tgt_long;
1499 src_long = src_short;
1501 /* FIXME: use the target short path too */
1502 folder->TargetDefault = strdupW(tgt_long);
1503 folder->SourceShortPath = strdupW(src_short);
1504 folder->SourceLongPath = strdupW(src_long);
1507 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1508 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1509 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1511 load_folder_persistence( package, folder );
1513 list_add_tail( &package->folders, &folder->entry );
1514 return ERROR_SUCCESS;
1517 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1521 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1523 list_add_tail( &parent->children, &fl->entry );
1524 return ERROR_SUCCESS;
1527 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1529 MSIPACKAGE *package = param;
1530 MSIFOLDER *parent, *child;
1532 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1533 return ERROR_FUNCTION_FAILED;
1535 if (!child->Parent) return ERROR_SUCCESS;
1537 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1538 return ERROR_FUNCTION_FAILED;
1540 return add_folder_child( parent, child );
1543 static UINT load_all_folders( MSIPACKAGE *package )
1545 static const WCHAR query[] = {
1546 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1547 '`','D','i','r','e','c','t','o','r','y','`',0};
1551 if (!list_empty(&package->folders))
1552 return ERROR_SUCCESS;
1554 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1555 if (r != ERROR_SUCCESS)
1558 r = MSI_IterateRecords( view, NULL, load_folder, package );
1559 if (r != ERROR_SUCCESS)
1561 msiobj_release( &view->hdr );
1564 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1565 msiobj_release( &view->hdr );
1569 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1571 msi_set_property( package->db, szCostingComplete, szZero, -1 );
1572 msi_set_property( package->db, szRootDrive, szCRoot, -1 );
1574 load_all_folders( package );
1575 msi_load_all_components( package );
1576 msi_load_all_features( package );
1577 load_all_files( package );
1578 load_all_patches( package );
1579 load_all_media( package );
1581 return ERROR_SUCCESS;
1584 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1586 const WCHAR *action = package->script->Actions[script][index];
1587 ui_actionstart( package, action );
1588 TRACE("executing %s\n", debugstr_w(action));
1589 return ACTION_PerformAction( package, action, script );
1592 static UINT execute_script( MSIPACKAGE *package, UINT script )
1594 UINT i, rc = ERROR_SUCCESS;
1596 TRACE("executing script %u\n", script);
1598 if (!package->script)
1600 ERR("no script!\n");
1601 return ERROR_FUNCTION_FAILED;
1603 if (script == SCRIPT_ROLLBACK)
1605 for (i = package->script->ActionCount[script]; i > 0; i--)
1607 rc = execute_script_action( package, script, i - 1 );
1608 if (rc != ERROR_SUCCESS) break;
1613 for (i = 0; i < package->script->ActionCount[script]; i++)
1615 rc = execute_script_action( package, script, i );
1616 if (rc != ERROR_SUCCESS) break;
1619 msi_free_action_script(package, script);
1623 static UINT ACTION_FileCost(MSIPACKAGE *package)
1625 return ERROR_SUCCESS;
1628 static void get_client_counts( MSIPACKAGE *package )
1633 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1635 if (!comp->ComponentId) continue;
1637 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE ) &&
1638 MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ))
1640 comp->num_clients = 0;
1643 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
1644 NULL, NULL, NULL, NULL );
1645 RegCloseKey( hkey );
1649 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1654 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1656 if (!comp->ComponentId) continue;
1658 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1659 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1661 if (r == ERROR_SUCCESS) continue;
1663 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1664 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1666 if (r == ERROR_SUCCESS) continue;
1668 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1669 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1671 if (r == ERROR_SUCCESS) continue;
1673 comp->Installed = INSTALLSTATE_ABSENT;
1677 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1679 MSIFEATURE *feature;
1681 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1685 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1686 feature->Installed = INSTALLSTATE_ABSENT;
1688 feature->Installed = state;
1692 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1694 return (feature->Level > 0 && feature->Level <= level);
1697 static BOOL process_state_property(MSIPACKAGE* package, int level,
1698 LPCWSTR property, INSTALLSTATE state)
1701 MSIFEATURE *feature;
1703 override = msi_dup_property( package->db, property );
1707 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1709 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1712 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1714 if (!strcmpiW( override, szAll ))
1716 if (feature->Installed != state)
1718 feature->Action = state;
1719 feature->ActionRequest = state;
1724 LPWSTR ptr = override;
1725 LPWSTR ptr2 = strchrW(override,',');
1729 int len = ptr2 - ptr;
1731 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1732 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1734 if (feature->Installed != state)
1736 feature->Action = state;
1737 feature->ActionRequest = state;
1744 ptr2 = strchrW(ptr,',');
1755 static BOOL process_overrides( MSIPACKAGE *package, int level )
1757 static const WCHAR szAddLocal[] =
1758 {'A','D','D','L','O','C','A','L',0};
1759 static const WCHAR szAddSource[] =
1760 {'A','D','D','S','O','U','R','C','E',0};
1761 static const WCHAR szAdvertise[] =
1762 {'A','D','V','E','R','T','I','S','E',0};
1765 /* all these activation/deactivation things happen in order and things
1766 * later on the list override things earlier on the list.
1768 * 0 INSTALLLEVEL processing
1781 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1782 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1783 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1784 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1785 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1788 msi_set_property( package->db, szPreselected, szOne, -1 );
1793 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1796 MSICOMPONENT* component;
1797 MSIFEATURE *feature;
1799 TRACE("Checking Install Level\n");
1801 level = msi_get_property_int(package->db, szInstallLevel, 1);
1803 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1805 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1807 if (!is_feature_selected( feature, level )) continue;
1809 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1811 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1813 feature->Action = INSTALLSTATE_SOURCE;
1814 feature->ActionRequest = INSTALLSTATE_SOURCE;
1816 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1818 feature->Action = INSTALLSTATE_ADVERTISED;
1819 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1823 feature->Action = INSTALLSTATE_LOCAL;
1824 feature->ActionRequest = INSTALLSTATE_LOCAL;
1828 /* disable child features of unselected parent or follow parent */
1829 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1833 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1835 if (!is_feature_selected( feature, level ))
1837 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1838 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1840 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1842 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1843 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1844 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1845 fl->feature->Action = feature->Action;
1846 fl->feature->ActionRequest = feature->ActionRequest;
1851 else /* preselected */
1853 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1855 if (!is_feature_selected( feature, level )) continue;
1857 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1859 if (feature->Installed == INSTALLSTATE_ABSENT)
1861 feature->Action = INSTALLSTATE_UNKNOWN;
1862 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1866 feature->Action = feature->Installed;
1867 feature->ActionRequest = feature->Installed;
1871 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1875 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1877 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1878 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1880 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1881 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1882 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1883 fl->feature->Action = feature->Action;
1884 fl->feature->ActionRequest = feature->ActionRequest;
1890 /* now we want to set component state based based on feature state */
1891 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1895 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1896 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1897 feature->ActionRequest, feature->Action);
1899 if (!is_feature_selected( feature, level )) continue;
1901 /* features with components that have compressed files are made local */
1902 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1904 if (cl->component->ForceLocalState &&
1905 feature->ActionRequest == INSTALLSTATE_SOURCE)
1907 feature->Action = INSTALLSTATE_LOCAL;
1908 feature->ActionRequest = INSTALLSTATE_LOCAL;
1913 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1915 component = cl->component;
1917 switch (feature->ActionRequest)
1919 case INSTALLSTATE_ABSENT:
1920 component->anyAbsent = 1;
1922 case INSTALLSTATE_ADVERTISED:
1923 component->hasAdvertiseFeature = 1;
1925 case INSTALLSTATE_SOURCE:
1926 component->hasSourceFeature = 1;
1928 case INSTALLSTATE_LOCAL:
1929 component->hasLocalFeature = 1;
1931 case INSTALLSTATE_DEFAULT:
1932 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1933 component->hasAdvertiseFeature = 1;
1934 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1935 component->hasSourceFeature = 1;
1937 component->hasLocalFeature = 1;
1945 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1947 /* check if it's local or source */
1948 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1949 (component->hasLocalFeature || component->hasSourceFeature))
1951 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1952 !component->ForceLocalState)
1954 component->Action = INSTALLSTATE_SOURCE;
1955 component->ActionRequest = INSTALLSTATE_SOURCE;
1959 component->Action = INSTALLSTATE_LOCAL;
1960 component->ActionRequest = INSTALLSTATE_LOCAL;
1965 /* if any feature is local, the component must be local too */
1966 if (component->hasLocalFeature)
1968 component->Action = INSTALLSTATE_LOCAL;
1969 component->ActionRequest = INSTALLSTATE_LOCAL;
1972 if (component->hasSourceFeature)
1974 component->Action = INSTALLSTATE_SOURCE;
1975 component->ActionRequest = INSTALLSTATE_SOURCE;
1978 if (component->hasAdvertiseFeature)
1980 component->Action = INSTALLSTATE_ADVERTISED;
1981 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1984 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1985 if (component->anyAbsent &&
1986 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1988 component->Action = INSTALLSTATE_ABSENT;
1989 component->ActionRequest = INSTALLSTATE_ABSENT;
1993 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1995 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1997 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1998 component->Action = INSTALLSTATE_LOCAL;
1999 component->ActionRequest = INSTALLSTATE_LOCAL;
2002 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2003 component->Installed == INSTALLSTATE_SOURCE &&
2004 component->hasSourceFeature)
2006 component->Action = INSTALLSTATE_UNKNOWN;
2007 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2010 TRACE("component %s (installed %d request %d action %d)\n",
2011 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2013 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
2014 component->num_clients++;
2015 else if (component->Action == INSTALLSTATE_ABSENT)
2016 component->num_clients--;
2019 return ERROR_SUCCESS;
2022 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2024 MSIPACKAGE *package = param;
2026 MSIFEATURE *feature;
2028 name = MSI_RecordGetString( row, 1 );
2030 feature = msi_get_loaded_feature( package, name );
2032 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2036 Condition = MSI_RecordGetString(row,3);
2038 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2040 int level = MSI_RecordGetInteger(row,2);
2041 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2042 feature->Level = level;
2045 return ERROR_SUCCESS;
2048 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2050 static const WCHAR name[] = {'\\',0};
2051 VS_FIXEDFILEINFO *ptr, *ret;
2053 DWORD versize, handle;
2056 versize = GetFileVersionInfoSizeW( filename, &handle );
2060 version = msi_alloc( versize );
2064 GetFileVersionInfoW( filename, 0, versize, version );
2066 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2068 msi_free( version );
2072 ret = msi_alloc( sz );
2073 memcpy( ret, ptr, sz );
2075 msi_free( version );
2079 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2083 msi_parse_version_string( version, &ms, &ls );
2085 if (fi->dwFileVersionMS > ms) return 1;
2086 else if (fi->dwFileVersionMS < ms) return -1;
2087 else if (fi->dwFileVersionLS > ls) return 1;
2088 else if (fi->dwFileVersionLS < ls) return -1;
2092 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2096 msi_parse_version_string( ver1, &ms1, NULL );
2097 msi_parse_version_string( ver2, &ms2, NULL );
2099 if (ms1 > ms2) return 1;
2100 else if (ms1 < ms2) return -1;
2104 DWORD msi_get_disk_file_size( LPCWSTR filename )
2109 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2110 if (file == INVALID_HANDLE_VALUE)
2111 return INVALID_FILE_SIZE;
2113 size = GetFileSize( file, NULL );
2114 TRACE("size is %u\n", size);
2115 CloseHandle( file );
2119 BOOL msi_file_hash_matches( MSIFILE *file )
2122 MSIFILEHASHINFO hash;
2124 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2125 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2126 if (r != ERROR_SUCCESS)
2129 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2132 static WCHAR *get_temp_dir( void )
2135 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2137 GetTempPathW( MAX_PATH, tmp );
2140 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2141 if (CreateDirectoryW( dir, NULL )) break;
2143 return strdupW( dir );
2147 * msi_build_directory_name()
2149 * This function is to save messing round with directory names
2150 * It handles adding backslashes between path segments,
2151 * and can add \ at the end of the directory name if told to.
2153 * It takes a variable number of arguments.
2154 * It always allocates a new string for the result, so make sure
2155 * to free the return value when finished with it.
2157 * The first arg is the number of path segments that follow.
2158 * The arguments following count are a list of path segments.
2159 * A path segment may be NULL.
2161 * Path segments will be added with a \ separating them.
2162 * A \ will not be added after the last segment, however if the
2163 * last segment is NULL, then the last character will be a \
2165 WCHAR *msi_build_directory_name( DWORD count, ... )
2171 va_start( va, count );
2172 for (i = 0; i < count; i++)
2174 const WCHAR *str = va_arg( va, const WCHAR * );
2175 if (str) sz += strlenW( str ) + 1;
2179 dir = msi_alloc( sz * sizeof(WCHAR) );
2182 va_start( va, count );
2183 for (i = 0; i < count; i++)
2185 const WCHAR *str = va_arg( va, const WCHAR * );
2187 strcatW( dir, str );
2188 if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2194 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2196 MSIASSEMBLY *assembly = file->Component->assembly;
2198 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2200 msi_free( file->TargetPath );
2201 if (assembly && !assembly->application)
2203 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2204 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2205 msi_track_tempfile( package, file->TargetPath );
2209 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2210 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2213 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2216 static UINT calculate_file_cost( MSIPACKAGE *package )
2218 VS_FIXEDFILEINFO *file_version;
2219 WCHAR *font_version;
2222 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2224 MSICOMPONENT *comp = file->Component;
2227 if (!comp->Enabled) continue;
2229 if (file->IsCompressed)
2230 comp->ForceLocalState = TRUE;
2232 set_target_path( package, file );
2234 if ((comp->assembly && !comp->assembly->installed) ||
2235 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2237 comp->Cost += file->FileSize;
2240 file_size = msi_get_disk_file_size( file->TargetPath );
2244 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2246 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2248 comp->Cost += file->FileSize - file_size;
2250 msi_free( file_version );
2253 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2255 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2257 comp->Cost += file->FileSize - file_size;
2259 msi_free( font_version );
2263 if (file_size != file->FileSize)
2265 comp->Cost += file->FileSize - file_size;
2268 return ERROR_SUCCESS;
2271 WCHAR *msi_normalize_path( const WCHAR *in )
2273 const WCHAR *p = in;
2275 int n, len = strlenW( in ) + 2;
2277 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2282 /* copy until the end of the string or a space */
2283 while (*p != ' ' && (*q = *p))
2286 /* reduce many backslashes to one */
2287 if (*p != '\\' || *q != '\\')
2291 /* quit at the end of the string */
2295 /* count the number of spaces */
2300 /* if it's leading or trailing space, skip it */
2301 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2303 else /* copy n spaces */
2304 while (n && (*q++ = *p++)) n--;
2306 while (q - ret > 0 && q[-1] == ' ') q--;
2307 if (q - ret > 0 && q[-1] != '\\')
2315 static WCHAR *get_install_location( MSIPACKAGE *package )
2320 if (!package->ProductCode) return NULL;
2321 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ))
2323 path = msi_reg_get_val_str( hkey, szInstallLocation );
2324 RegCloseKey( hkey );
2328 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2331 MSIFOLDER *folder, *parent, *child;
2332 WCHAR *path, *normalized_path;
2334 TRACE("resolving %s\n", debugstr_w(name));
2336 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2338 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2340 if (!(path = get_install_location( package )) &&
2341 (!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))))
2343 path = msi_dup_property( package->db, szRootDrive );
2346 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2348 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2350 parent = msi_get_loaded_folder( package, folder->Parent );
2351 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2354 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2356 normalized_path = msi_normalize_path( path );
2358 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2360 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2361 msi_free( normalized_path );
2364 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2365 msi_free( folder->ResolvedTarget );
2366 folder->ResolvedTarget = normalized_path;
2368 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2371 msi_resolve_target_folder( package, child->Directory, load_prop );
2373 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2376 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2378 static const WCHAR query[] = {
2379 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2380 '`','C','o','n','d','i','t','i','o','n','`',0};
2381 static const WCHAR szOutOfDiskSpace[] = {
2382 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2388 TRACE("Building directory properties\n");
2389 msi_resolve_target_folder( package, szTargetDir, TRUE );
2391 TRACE("Evaluating component conditions\n");
2392 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2394 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2396 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2397 comp->Enabled = FALSE;
2400 comp->Enabled = TRUE;
2402 get_client_counts( package );
2404 /* read components states from the registry */
2405 ACTION_GetComponentInstallStates(package);
2406 ACTION_GetFeatureInstallStates(package);
2408 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2410 TRACE("Evaluating feature conditions\n");
2412 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2413 if (rc == ERROR_SUCCESS)
2415 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2416 msiobj_release( &view->hdr );
2417 if (rc != ERROR_SUCCESS)
2422 TRACE("Calculating file cost\n");
2423 calculate_file_cost( package );
2425 msi_set_property( package->db, szCostingComplete, szOne, -1 );
2426 /* set default run level if not set */
2427 level = msi_dup_property( package->db, szInstallLevel );
2429 msi_set_property( package->db, szInstallLevel, szOne, -1 );
2432 /* FIXME: check volume disk space */
2433 msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
2435 return MSI_SetFeatureStates(package);
2438 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type, DWORD *size )
2444 *size = sizeof(WCHAR);
2446 if ((data = msi_alloc( *size ))) *(WCHAR *)data = 0;
2449 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2455 LPWSTR deformated = NULL;
2458 deformat_string(package, &value[2], &deformated);
2460 /* binary value type */
2464 *size = (strlenW(ptr)/2)+1;
2466 *size = strlenW(ptr)/2;
2468 data = msi_alloc(*size);
2474 /* if uneven pad with a zero in front */
2480 data[count] = (BYTE)strtol(byte,NULL,0);
2482 TRACE("Uneven byte count\n");
2490 data[count] = (BYTE)strtol(byte,NULL,0);
2493 msi_free(deformated);
2495 TRACE("Data %i bytes(%i)\n",*size,count);
2502 deformat_string(package, &value[1], &deformated);
2505 *size = sizeof(DWORD);
2506 data = msi_alloc(*size);
2512 if ( (*p < '0') || (*p > '9') )
2518 if (deformated[0] == '-')
2521 TRACE("DWORD %i\n",*(LPDWORD)data);
2523 msi_free(deformated);
2528 const WCHAR *ptr = value;
2532 if (value[0] == '#')
2535 if (value[1] == '%')
2538 *type = REG_EXPAND_SZ;
2541 len = deformat_string( package, ptr, (WCHAR **)&data );
2542 if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
2543 *size = (len + 1) * sizeof(WCHAR);
2548 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2555 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2557 *root_key = HKEY_LOCAL_MACHINE;
2562 *root_key = HKEY_CURRENT_USER;
2567 *root_key = HKEY_CLASSES_ROOT;
2571 *root_key = HKEY_CURRENT_USER;
2575 *root_key = HKEY_LOCAL_MACHINE;
2579 *root_key = HKEY_USERS;
2583 ERR("Unknown root %i\n", root);
2590 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2592 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2593 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2595 if ((is_64bit || is_wow64) &&
2596 !(comp->Attributes & msidbComponentAttributes64bit) &&
2597 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2602 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2603 if (!(path_32node = msi_alloc( size ))) return NULL;
2605 memcpy( path_32node, path, len * sizeof(WCHAR) );
2606 strcpyW( path_32node + len, szWow6432Node );
2607 strcatW( path_32node, szBackSlash );
2608 strcatW( path_32node, path + len );
2611 return strdupW( path );
2614 static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
2616 REGSAM access = KEY_ALL_ACCESS;
2617 WCHAR *subkey, *p, *q;
2618 HKEY hkey, ret = NULL;
2621 if (is_wow64) access |= KEY_WOW64_64KEY;
2623 if (!(subkey = strdupW( path ))) return NULL;
2625 if ((q = strchrW( p, '\\' ))) *q = 0;
2627 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2629 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2632 TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
2638 ret = open_key( hkey, q + 1, create );
2639 RegCloseKey( hkey );
2646 static BOOL is_special_entry( const WCHAR *name )
2648 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2651 static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count )
2653 const WCHAR *p = str;
2658 if (!str) return NULL;
2659 while ((p - str) < len)
2661 p += strlenW( p ) + 1;
2664 if (!(ret = msi_alloc( *count * sizeof(WCHAR *) ))) return NULL;
2666 while ((p - str) < len)
2668 if (!(ret[i] = strdupW( p )))
2670 for (; i >= 0; i--) msi_free( ret[i] );
2674 p += strlenW( p ) + 1;
2680 static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count,
2681 WCHAR **right, DWORD right_count, DWORD *size )
2686 *size = sizeof(WCHAR);
2687 for (i = 0; i < left_count; i++) *size += (strlenW( left[i] ) + 1) * sizeof(WCHAR);
2688 for (i = 0; i < right_count; i++) *size += (strlenW( right[i] ) + 1) * sizeof(WCHAR);
2690 if (!(ret = p = msi_alloc( *size ))) return NULL;
2692 for (i = 0; i < left_count; i++)
2694 strcpyW( p, left[i] );
2695 p += strlenW( p ) + 1;
2697 for (i = 0; i < right_count; i++)
2699 strcpyW( p, right[i] );
2700 p += strlenW( p ) + 1;
2706 static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
2707 WCHAR **new, DWORD new_count )
2709 DWORD ret = old_count;
2710 unsigned int i, j, k;
2712 for (i = 0; i < new_count; i++)
2714 for (j = 0; j < old_count; j++)
2716 if (old[j] && !strcmpW( new[i], old[j] ))
2719 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
2735 static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
2736 WCHAR **new, DWORD new_count, DWORD *size )
2740 case JOIN_OP_APPEND:
2741 old_count = remove_duplicate_values( old, old_count, new, new_count );
2742 return flatten_multi_string_values( old, old_count, new, new_count, size );
2744 case JOIN_OP_PREPEND:
2745 old_count = remove_duplicate_values( old, old_count, new, new_count );
2746 return flatten_multi_string_values( new, new_count, old, old_count, size );
2748 case JOIN_OP_REPLACE:
2749 return flatten_multi_string_values( new, new_count, NULL, 0, size );
2752 ERR("unhandled join op %u\n", op);
2757 static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size,
2758 BYTE *new_value, DWORD new_size, DWORD *size )
2760 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
2761 const WCHAR *new_ptr = NULL, *old_ptr = NULL;
2762 enum join_op op = JOIN_OP_REPLACE;
2763 WCHAR **old = NULL, **new = NULL;
2766 if (new_size / sizeof(WCHAR) - 1 > 1)
2768 new_ptr = (const WCHAR *)new_value;
2769 new_len = new_size / sizeof(WCHAR) - 1;
2771 if (!new_ptr[0] && new_ptr[new_len - 1])
2773 op = JOIN_OP_APPEND;
2777 else if (new_ptr[0] && !new_ptr[new_len - 1])
2779 op = JOIN_OP_PREPEND;
2782 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2784 op = JOIN_OP_REPLACE;
2788 new = split_multi_string_values( new_ptr, new_len, &new_count );
2790 if (old_size / sizeof(WCHAR) - 1 > 1)
2792 old_ptr = (const WCHAR *)old_value;
2793 old_len = old_size / sizeof(WCHAR) - 1;
2794 old = split_multi_string_values( old_ptr, old_len, &old_count );
2796 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
2797 for (i = 0; i < old_count; i++) msi_free( old[i] );
2798 for (i = 0; i < new_count; i++) msi_free( new[i] );
2804 static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
2807 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
2808 if (!(ret = msi_alloc( *size ))) return NULL;
2809 RegQueryValueExW( hkey, name, NULL, type, ret, size );
2813 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2815 MSIPACKAGE *package = param;
2816 BYTE *new_value, *old_value = NULL;
2817 HKEY root_key, hkey;
2818 DWORD type, old_type, new_size, old_size = 0;
2819 LPWSTR deformated, uikey, keypath;
2820 const WCHAR *szRoot, *component, *name, *key, *str;
2824 BOOL check_first = FALSE;
2827 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2829 component = MSI_RecordGetString(row, 6);
2830 comp = msi_get_loaded_component(package,component);
2832 return ERROR_SUCCESS;
2834 comp->Action = msi_get_component_action( package, comp );
2835 if (comp->Action != INSTALLSTATE_LOCAL)
2837 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2838 return ERROR_SUCCESS;
2841 name = MSI_RecordGetString(row, 4);
2842 if( MSI_RecordIsNull(row,5) && name )
2844 /* null values can have special meanings */
2845 if (name[0]=='-' && name[1] == 0)
2846 return ERROR_SUCCESS;
2847 if ((name[0] == '+' || name[0] == '*') && !name[1])
2851 root = MSI_RecordGetInteger(row,2);
2852 key = MSI_RecordGetString(row, 3);
2854 szRoot = get_root_key( package, root, &root_key );
2856 return ERROR_SUCCESS;
2858 deformat_string(package, key , &deformated);
2859 uikey = msi_alloc( (strlenW(deformated) + strlenW(szRoot) + 1) * sizeof(WCHAR) );
2860 strcpyW(uikey,szRoot);
2861 strcatW(uikey,deformated);
2863 keypath = get_keypath( comp, root_key, deformated );
2864 msi_free( deformated );
2865 if (!(hkey = open_key( root_key, keypath, TRUE )))
2867 ERR("Could not create key %s\n", debugstr_w(keypath));
2870 return ERROR_FUNCTION_FAILED;
2872 str = msi_record_get_string( row, 5, &len );
2873 if (str && len > strlenW( str ))
2875 type = REG_MULTI_SZ;
2876 new_size = (len + 1) * sizeof(WCHAR);
2877 new_value = (BYTE *)msi_strdupW( str, len );
2879 else new_value = parse_value( package, str, &type, &new_size );
2880 deformat_string(package, name, &deformated);
2882 if (!is_special_entry( name ))
2884 old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
2885 if (type == REG_MULTI_SZ)
2888 if (old_type != REG_MULTI_SZ)
2890 msi_free( old_value );
2894 new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size );
2895 msi_free( new_value );
2900 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2901 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2903 else if (!old_value)
2905 if (deformated || new_size)
2907 TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
2908 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2911 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
2915 uirow = MSI_CreateRecord(3);
2916 MSI_RecordSetStringW(uirow,2,deformated);
2917 MSI_RecordSetStringW(uirow,1,uikey);
2918 if (type == REG_SZ || type == REG_EXPAND_SZ)
2919 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
2920 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2921 msiobj_release( &uirow->hdr );
2923 msi_free(new_value);
2924 msi_free(old_value);
2925 msi_free(deformated);
2929 return ERROR_SUCCESS;
2932 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2934 static const WCHAR query[] = {
2935 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2936 '`','R','e','g','i','s','t','r','y','`',0};
2940 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2941 if (rc != ERROR_SUCCESS)
2942 return ERROR_SUCCESS;
2944 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2945 msiobj_release(&view->hdr);
2949 static void delete_key( HKEY root, const WCHAR *path )
2956 if (is_wow64) access |= KEY_WOW64_64KEY;
2958 if (!(subkey = strdupW( path ))) return;
2961 if ((p = strrchrW( subkey, '\\' ))) *p = 0;
2962 hkey = open_key( root, subkey, FALSE );
2965 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2967 res = RegDeleteKeyExW( root, subkey, access, 0 );
2970 TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
2973 if (p && p[1]) RegCloseKey( hkey );
2979 static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
2983 DWORD num_subkeys, num_values;
2985 if ((hkey = open_key( root, path, FALSE )))
2987 if ((res = RegDeleteValueW( hkey, value )))
2988 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2990 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2991 NULL, NULL, NULL, NULL );
2992 RegCloseKey( hkey );
2993 if (!res && !num_subkeys && !num_values)
2995 TRACE("removing empty key %s\n", debugstr_w(path));
2996 delete_key( root, path );
3001 static void delete_tree( HKEY root, const WCHAR *path )
3006 if (!(hkey = open_key( root, path, FALSE ))) return;
3007 res = RegDeleteTreeW( hkey, NULL );
3008 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
3009 delete_key( root, path );
3010 RegCloseKey( hkey );
3013 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
3015 MSIPACKAGE *package = param;
3016 LPCWSTR component, name, key_str, root_key_str;
3017 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3020 BOOL delete_key = FALSE;
3025 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
3027 component = MSI_RecordGetString( row, 6 );
3028 comp = msi_get_loaded_component( package, component );
3030 return ERROR_SUCCESS;
3032 comp->Action = msi_get_component_action( package, comp );
3033 if (comp->Action != INSTALLSTATE_ABSENT)
3035 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3036 return ERROR_SUCCESS;
3039 name = MSI_RecordGetString( row, 4 );
3040 if (MSI_RecordIsNull( row, 5 ) && name )
3042 if (name[0] == '+' && !name[1])
3043 return ERROR_SUCCESS;
3044 if ((name[0] == '-' || name[0] == '*') && !name[1])
3051 root = MSI_RecordGetInteger( row, 2 );
3052 key_str = MSI_RecordGetString( row, 3 );
3054 root_key_str = get_root_key( package, root, &hkey_root );
3056 return ERROR_SUCCESS;
3058 deformat_string( package, key_str, &deformated_key );
3059 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3060 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3061 strcpyW( ui_key_str, root_key_str );
3062 strcatW( ui_key_str, deformated_key );
3064 deformat_string( package, name, &deformated_name );
3066 keypath = get_keypath( comp, hkey_root, deformated_key );
3067 msi_free( deformated_key );
3068 if (delete_key) delete_tree( hkey_root, keypath );
3069 else delete_value( hkey_root, keypath, deformated_name );
3070 msi_free( keypath );
3072 uirow = MSI_CreateRecord( 2 );
3073 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3074 MSI_RecordSetStringW( uirow, 2, deformated_name );
3075 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3076 msiobj_release( &uirow->hdr );
3078 msi_free( ui_key_str );
3079 msi_free( deformated_name );
3080 return ERROR_SUCCESS;
3083 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
3085 MSIPACKAGE *package = param;
3086 LPCWSTR component, name, key_str, root_key_str;
3087 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3090 BOOL delete_key = FALSE;
3095 component = MSI_RecordGetString( row, 5 );
3096 comp = msi_get_loaded_component( package, component );
3098 return ERROR_SUCCESS;
3100 comp->Action = msi_get_component_action( package, comp );
3101 if (comp->Action != INSTALLSTATE_LOCAL)
3103 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3104 return ERROR_SUCCESS;
3107 if ((name = MSI_RecordGetString( row, 4 )))
3109 if (name[0] == '-' && !name[1])
3116 root = MSI_RecordGetInteger( row, 2 );
3117 key_str = MSI_RecordGetString( row, 3 );
3119 root_key_str = get_root_key( package, root, &hkey_root );
3121 return ERROR_SUCCESS;
3123 deformat_string( package, key_str, &deformated_key );
3124 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3125 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3126 strcpyW( ui_key_str, root_key_str );
3127 strcatW( ui_key_str, deformated_key );
3129 deformat_string( package, name, &deformated_name );
3131 keypath = get_keypath( comp, hkey_root, deformated_key );
3132 msi_free( deformated_key );
3133 if (delete_key) delete_tree( hkey_root, keypath );
3134 else delete_value( hkey_root, keypath, deformated_name );
3135 msi_free( keypath );
3137 uirow = MSI_CreateRecord( 2 );
3138 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3139 MSI_RecordSetStringW( uirow, 2, deformated_name );
3140 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
3141 msiobj_release( &uirow->hdr );
3143 msi_free( ui_key_str );
3144 msi_free( deformated_name );
3145 return ERROR_SUCCESS;
3148 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3150 static const WCHAR registry_query[] = {
3151 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3152 '`','R','e','g','i','s','t','r','y','`',0};
3153 static const WCHAR remove_registry_query[] = {
3154 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3155 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
3159 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3160 if (rc == ERROR_SUCCESS)
3162 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3163 msiobj_release( &view->hdr );
3164 if (rc != ERROR_SUCCESS)
3167 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3168 if (rc == ERROR_SUCCESS)
3170 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3171 msiobj_release( &view->hdr );
3172 if (rc != ERROR_SUCCESS)
3175 return ERROR_SUCCESS;
3178 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3180 package->script->CurrentlyScripting = TRUE;
3182 return ERROR_SUCCESS;
3186 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3188 static const WCHAR query[]= {
3189 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3190 '`','R','e','g','i','s','t','r','y','`',0};
3192 DWORD total = 0, count = 0;
3194 MSIFEATURE *feature;
3198 TRACE("InstallValidate\n");
3200 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3201 if (rc == ERROR_SUCCESS)
3203 rc = MSI_IterateRecords( view, &count, NULL, package );
3204 msiobj_release( &view->hdr );
3205 if (rc != ERROR_SUCCESS)
3207 total += count * REG_PROGRESS_VALUE;
3209 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3210 total += COMPONENT_PROGRESS_VALUE;
3212 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3213 total += file->FileSize;
3215 msi_ui_progress( package, 0, total, 0, 0 );
3217 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3219 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3220 debugstr_w(feature->Feature), feature->Installed,
3221 feature->ActionRequest, feature->Action);
3223 return ERROR_SUCCESS;
3226 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3228 MSIPACKAGE* package = param;
3229 LPCWSTR cond = NULL;
3230 LPCWSTR message = NULL;
3233 static const WCHAR title[]=
3234 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3236 cond = MSI_RecordGetString(row,1);
3238 r = MSI_EvaluateConditionW(package,cond);
3239 if (r == MSICONDITION_FALSE)
3241 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3244 message = MSI_RecordGetString(row,2);
3245 deformat_string(package,message,&deformated);
3246 MessageBoxW(NULL,deformated,title,MB_OK);
3247 msi_free(deformated);
3250 return ERROR_INSTALL_FAILURE;
3253 return ERROR_SUCCESS;
3256 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3258 static const WCHAR query[] = {
3259 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3260 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3264 TRACE("Checking launch conditions\n");
3266 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3267 if (rc != ERROR_SUCCESS)
3268 return ERROR_SUCCESS;
3270 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3271 msiobj_release(&view->hdr);
3275 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3279 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3281 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3283 static const WCHAR query[] = {
3284 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3285 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3286 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3287 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3288 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3291 LPWSTR deformated, buffer, deformated_name;
3294 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3298 root = MSI_RecordGetInteger(row,2);
3299 key = MSI_RecordGetString(row, 3);
3300 name = MSI_RecordGetString(row, 4);
3301 deformat_string(package, key , &deformated);
3302 deformat_string(package, name, &deformated_name);
3304 len = strlenW(deformated) + 6;
3305 if (deformated_name)
3306 len+=strlenW(deformated_name);
3308 buffer = msi_alloc( len *sizeof(WCHAR));
3310 if (deformated_name)
3311 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3313 sprintfW(buffer,fmt,root,deformated);
3315 msi_free(deformated);
3316 msi_free(deformated_name);
3317 msiobj_release(&row->hdr);
3321 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3323 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3328 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3331 return strdupW( file->TargetPath );
3336 static HKEY openSharedDLLsKey(void)
3339 static const WCHAR path[] =
3340 {'S','o','f','t','w','a','r','e','\\',
3341 'M','i','c','r','o','s','o','f','t','\\',
3342 'W','i','n','d','o','w','s','\\',
3343 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3344 'S','h','a','r','e','d','D','L','L','s',0};
3346 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3350 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3355 DWORD sz = sizeof(count);
3358 hkey = openSharedDLLsKey();
3359 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3360 if (rc != ERROR_SUCCESS)
3366 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3370 hkey = openSharedDLLsKey();
3372 msi_reg_set_val_dword( hkey, path, count );
3374 RegDeleteValueW(hkey,path);
3379 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3381 MSIFEATURE *feature;
3385 /* only refcount DLLs */
3386 if (comp->KeyPath == NULL ||
3388 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3389 comp->Attributes & msidbComponentAttributesODBCDataSource)
3393 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3394 write = (count > 0);
3396 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3400 /* increment counts */
3401 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3405 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3408 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3410 if ( cl->component == comp )
3415 /* decrement counts */
3416 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3420 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3423 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3425 if ( cl->component == comp )
3430 /* ref count all the files in the component */
3435 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3437 if (file->Component == comp)
3438 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3442 /* add a count for permanent */
3443 if (comp->Attributes & msidbComponentAttributesPermanent)
3446 comp->RefCount = count;
3449 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3452 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3456 const WCHAR prefixW[] = {'<','\\',0};
3457 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3458 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3462 strcpyW( keypath, prefixW );
3463 strcatW( keypath, comp->assembly->display_name );
3467 return resolve_keypath( package, comp );
3470 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3472 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3479 squash_guid(package->ProductCode,squished_pc);
3480 msi_set_sourcedir_props(package, FALSE);
3482 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3485 INSTALLSTATE action;
3487 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3488 if (!comp->ComponentId)
3491 squash_guid( comp->ComponentId, squished_cc );
3492 msi_free( comp->FullKeypath );
3493 comp->FullKeypath = build_full_keypath( package, comp );
3495 ACTION_RefCountComponent( package, comp );
3497 if (package->need_rollback) action = comp->Installed;
3498 else action = comp->ActionRequest;
3500 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3501 debugstr_w(comp->Component), debugstr_w(squished_cc),
3502 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3504 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3506 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3507 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3509 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3511 if (rc != ERROR_SUCCESS)
3514 if (comp->Attributes & msidbComponentAttributesPermanent)
3516 static const WCHAR szPermKey[] =
3517 { '0','0','0','0','0','0','0','0','0','0','0','0',
3518 '0','0','0','0','0','0','0','0','0','0','0','0',
3519 '0','0','0','0','0','0','0','0',0 };
3521 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3523 if (action == INSTALLSTATE_LOCAL)
3524 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3530 WCHAR source[MAX_PATH];
3531 WCHAR base[MAX_PATH];
3534 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3535 static const WCHAR query[] = {
3536 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3537 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3538 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3539 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3540 '`','D','i','s','k','I','d','`',0};
3542 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3545 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3546 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3547 ptr2 = strrchrW(source, '\\') + 1;
3548 msiobj_release(&row->hdr);
3550 lstrcpyW(base, package->PackagePath);
3551 ptr = strrchrW(base, '\\');
3554 sourcepath = msi_resolve_file_source(package, file);
3555 ptr = sourcepath + lstrlenW(base);
3556 lstrcpyW(ptr2, ptr);
3557 msi_free(sourcepath);
3559 msi_reg_set_val_str(hkey, squished_pc, source);
3563 else if (action == INSTALLSTATE_ABSENT)
3565 if (comp->num_clients <= 0)
3567 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3568 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid );
3570 MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
3575 uirow = MSI_CreateRecord(3);
3576 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3577 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3578 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3579 msi_ui_actiondata( package, szProcessComponents, uirow );
3580 msiobj_release( &uirow->hdr );
3582 return ERROR_SUCCESS;
3593 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3594 LPWSTR lpszName, LONG_PTR lParam)
3597 typelib_struct *tl_struct = (typelib_struct*) lParam;
3598 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3602 if (!IS_INTRESOURCE(lpszName))
3604 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3608 sz = strlenW(tl_struct->source)+4;
3609 sz *= sizeof(WCHAR);
3611 if ((INT_PTR)lpszName == 1)
3612 tl_struct->path = strdupW(tl_struct->source);
3615 tl_struct->path = msi_alloc(sz);
3616 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3619 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3620 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3623 msi_free(tl_struct->path);
3624 tl_struct->path = NULL;
3629 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3630 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3632 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3636 msi_free(tl_struct->path);
3637 tl_struct->path = NULL;
3639 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3640 ITypeLib_Release(tl_struct->ptLib);
3645 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3647 MSIPACKAGE* package = param;
3651 typelib_struct tl_struct;
3656 component = MSI_RecordGetString(row,3);
3657 comp = msi_get_loaded_component(package,component);
3659 return ERROR_SUCCESS;
3661 comp->Action = msi_get_component_action( package, comp );
3662 if (comp->Action != INSTALLSTATE_LOCAL)
3664 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3665 return ERROR_SUCCESS;
3668 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3670 TRACE("component has no key path\n");
3671 return ERROR_SUCCESS;
3673 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3675 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3679 guid = MSI_RecordGetString(row,1);
3680 CLSIDFromString( guid, &tl_struct.clsid);
3681 tl_struct.source = strdupW( file->TargetPath );
3682 tl_struct.path = NULL;
3684 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3685 (LONG_PTR)&tl_struct);
3689 LPCWSTR helpid, help_path = NULL;
3692 helpid = MSI_RecordGetString(row,6);
3694 if (helpid) help_path = msi_get_target_folder( package, helpid );
3695 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3698 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3700 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3702 ITypeLib_Release(tl_struct.ptLib);
3703 msi_free(tl_struct.path);
3705 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3707 FreeLibrary(module);
3708 msi_free(tl_struct.source);
3712 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3715 ERR("Failed to load type library: %08x\n", hr);
3716 return ERROR_INSTALL_FAILURE;
3719 ITypeLib_Release(tlib);
3722 return ERROR_SUCCESS;
3725 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3727 static const WCHAR query[] = {
3728 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3729 '`','T','y','p','e','L','i','b','`',0};
3733 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3734 if (rc != ERROR_SUCCESS)
3735 return ERROR_SUCCESS;
3737 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3738 msiobj_release(&view->hdr);
3742 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3744 MSIPACKAGE *package = param;
3745 LPCWSTR component, guid;
3753 component = MSI_RecordGetString( row, 3 );
3754 comp = msi_get_loaded_component( package, component );
3756 return ERROR_SUCCESS;
3758 comp->Action = msi_get_component_action( package, comp );
3759 if (comp->Action != INSTALLSTATE_ABSENT)
3761 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3762 return ERROR_SUCCESS;
3764 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3766 guid = MSI_RecordGetString( row, 1 );
3767 CLSIDFromString( guid, &libid );
3768 version = MSI_RecordGetInteger( row, 4 );
3769 language = MSI_RecordGetInteger( row, 2 );
3772 syskind = SYS_WIN64;
3774 syskind = SYS_WIN32;
3777 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3780 WARN("Failed to unregister typelib: %08x\n", hr);
3783 return ERROR_SUCCESS;
3786 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3788 static const WCHAR query[] = {
3789 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3790 '`','T','y','p','e','L','i','b','`',0};
3794 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3795 if (rc != ERROR_SUCCESS)
3796 return ERROR_SUCCESS;
3798 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3799 msiobj_release( &view->hdr );
3803 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3805 static const WCHAR szlnk[] = {'.','l','n','k',0};
3806 LPCWSTR directory, extension, link_folder;
3807 LPWSTR link_file, filename;
3809 directory = MSI_RecordGetString( row, 2 );
3810 link_folder = msi_get_target_folder( package, directory );
3813 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3816 /* may be needed because of a bug somewhere else */
3817 msi_create_full_path( link_folder );
3819 filename = msi_dup_record_field( row, 3 );
3820 msi_reduce_to_long_filename( filename );
3822 extension = strchrW( filename, '.' );
3823 if (!extension || strcmpiW( extension, szlnk ))
3825 int len = strlenW( filename );
3826 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3827 memcpy( filename + len, szlnk, sizeof(szlnk) );
3829 link_file = msi_build_directory_name( 2, link_folder, filename );
3830 msi_free( filename );
3835 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3837 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3838 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3839 WCHAR *folder, *dest, *path;
3841 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3842 folder = msi_dup_property( package->db, szWindowsFolder );
3845 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3846 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3847 msi_free( appdata );
3849 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3850 msi_create_full_path( dest );
3851 path = msi_build_directory_name( 2, dest, icon_name );
3857 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3859 MSIPACKAGE *package = param;
3860 LPWSTR link_file, deformated, path;
3861 LPCWSTR component, target;
3863 IShellLinkW *sl = NULL;
3864 IPersistFile *pf = NULL;
3867 component = MSI_RecordGetString(row, 4);
3868 comp = msi_get_loaded_component(package, component);
3870 return ERROR_SUCCESS;
3872 comp->Action = msi_get_component_action( package, comp );
3873 if (comp->Action != INSTALLSTATE_LOCAL)
3875 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3876 return ERROR_SUCCESS;
3878 msi_ui_actiondata( package, szCreateShortcuts, row );
3880 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3881 &IID_IShellLinkW, (LPVOID *) &sl );
3885 ERR("CLSID_ShellLink not available\n");
3889 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3892 ERR("QueryInterface(IID_IPersistFile) failed\n");
3896 target = MSI_RecordGetString(row, 5);
3897 if (strchrW(target, '['))
3899 deformat_string( package, target, &path );
3900 TRACE("target path is %s\n", debugstr_w(path));
3901 IShellLinkW_SetPath( sl, path );
3906 FIXME("poorly handled shortcut format, advertised shortcut\n");
3907 IShellLinkW_SetPath(sl,comp->FullKeypath);
3910 if (!MSI_RecordIsNull(row,6))
3912 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3913 deformat_string(package, arguments, &deformated);
3914 IShellLinkW_SetArguments(sl,deformated);
3915 msi_free(deformated);
3918 if (!MSI_RecordIsNull(row,7))
3920 LPCWSTR description = MSI_RecordGetString(row, 7);
3921 IShellLinkW_SetDescription(sl, description);
3924 if (!MSI_RecordIsNull(row,8))
3925 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3927 if (!MSI_RecordIsNull(row,9))
3930 LPCWSTR icon = MSI_RecordGetString(row, 9);
3932 path = msi_build_icon_path(package, icon);
3933 index = MSI_RecordGetInteger(row,10);
3935 /* no value means 0 */
3936 if (index == MSI_NULL_INTEGER)
3939 IShellLinkW_SetIconLocation(sl, path, index);
3943 if (!MSI_RecordIsNull(row,11))
3944 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3946 if (!MSI_RecordIsNull(row,12))
3948 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3949 full_path = msi_get_target_folder( package, wkdir );
3950 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3952 link_file = get_link_file(package, row);
3954 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3955 IPersistFile_Save(pf, link_file, FALSE);
3956 msi_free(link_file);
3960 IPersistFile_Release( pf );
3962 IShellLinkW_Release( sl );
3964 return ERROR_SUCCESS;
3967 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3969 static const WCHAR query[] = {
3970 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3971 '`','S','h','o','r','t','c','u','t','`',0};
3976 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3977 if (rc != ERROR_SUCCESS)
3978 return ERROR_SUCCESS;
3980 res = CoInitialize( NULL );
3982 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3983 msiobj_release(&view->hdr);
3985 if (SUCCEEDED(res)) CoUninitialize();
3989 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3991 MSIPACKAGE *package = param;
3996 component = MSI_RecordGetString( row, 4 );
3997 comp = msi_get_loaded_component( package, component );
3999 return ERROR_SUCCESS;
4001 comp->Action = msi_get_component_action( package, comp );
4002 if (comp->Action != INSTALLSTATE_ABSENT)
4004 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4005 return ERROR_SUCCESS;
4007 msi_ui_actiondata( package, szRemoveShortcuts, row );
4009 link_file = get_link_file( package, row );
4011 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
4012 if (!DeleteFileW( link_file ))
4014 WARN("Failed to remove shortcut file %u\n", GetLastError());
4016 msi_free( link_file );
4018 return ERROR_SUCCESS;
4021 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4023 static const WCHAR query[] = {
4024 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4025 '`','S','h','o','r','t','c','u','t','`',0};
4029 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4030 if (rc != ERROR_SUCCESS)
4031 return ERROR_SUCCESS;
4033 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
4034 msiobj_release( &view->hdr );
4038 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
4040 MSIPACKAGE* package = param;
4048 FileName = MSI_RecordGetString(row,1);
4051 ERR("Unable to get FileName\n");
4052 return ERROR_SUCCESS;
4055 FilePath = msi_build_icon_path(package, FileName);
4057 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4059 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4060 FILE_ATTRIBUTE_NORMAL, NULL);
4062 if (the_file == INVALID_HANDLE_VALUE)
4064 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4066 return ERROR_SUCCESS;
4073 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4074 if (rc != ERROR_SUCCESS)
4076 ERR("Failed to get stream\n");
4077 CloseHandle(the_file);
4078 DeleteFileW(FilePath);
4081 WriteFile(the_file,buffer,sz,&write,NULL);
4082 } while (sz == 1024);
4085 CloseHandle(the_file);
4087 return ERROR_SUCCESS;
4090 static UINT msi_publish_icons(MSIPACKAGE *package)
4092 static const WCHAR query[]= {
4093 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4094 '`','I','c','o','n','`',0};
4098 r = MSI_DatabaseOpenViewW(package->db, query, &view);
4099 if (r == ERROR_SUCCESS)
4101 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
4102 msiobj_release(&view->hdr);
4103 if (r != ERROR_SUCCESS)
4106 return ERROR_SUCCESS;
4109 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
4115 MSISOURCELISTINFO *info;
4117 r = RegCreateKeyW(hkey, szSourceList, &source);
4118 if (r != ERROR_SUCCESS)
4121 RegCloseKey(source);
4123 buffer = strrchrW(package->PackagePath, '\\') + 1;
4124 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4125 package->Context, MSICODE_PRODUCT,
4126 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4127 if (r != ERROR_SUCCESS)
4130 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4131 package->Context, MSICODE_PRODUCT,
4132 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4133 if (r != ERROR_SUCCESS)
4136 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4137 package->Context, MSICODE_PRODUCT,
4138 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4139 if (r != ERROR_SUCCESS)
4142 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4144 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4145 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4146 info->options, info->value);
4148 MsiSourceListSetInfoW(package->ProductCode, NULL,
4149 info->context, info->options,
4150 info->property, info->value);
4153 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4155 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4156 disk->context, disk->options,
4157 disk->disk_id, disk->volume_label, disk->disk_prompt);
4160 return ERROR_SUCCESS;
4163 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4165 MSIHANDLE hdb, suminfo;
4166 WCHAR guids[MAX_PATH];
4167 WCHAR packcode[SQUISH_GUID_SIZE];
4174 static const WCHAR szARPProductIcon[] =
4175 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4176 static const WCHAR szAssignment[] =
4177 {'A','s','s','i','g','n','m','e','n','t',0};
4178 static const WCHAR szAdvertiseFlags[] =
4179 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4180 static const WCHAR szClients[] =
4181 {'C','l','i','e','n','t','s',0};
4182 static const WCHAR szColon[] = {':',0};
4184 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4185 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4188 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4189 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4192 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4194 buffer = msi_dup_property(package->db, szARPProductIcon);
4197 LPWSTR path = msi_build_icon_path(package, buffer);
4198 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4203 buffer = msi_dup_property(package->db, szProductVersion);
4206 DWORD verdword = msi_version_str_to_dword(buffer);
4207 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4211 msi_reg_set_val_dword(hkey, szAssignment, 0);
4212 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4213 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4214 msi_reg_set_val_str(hkey, szClients, szColon);
4216 hdb = alloc_msihandle(&package->db->hdr);
4218 return ERROR_NOT_ENOUGH_MEMORY;
4220 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4221 MsiCloseHandle(hdb);
4222 if (r != ERROR_SUCCESS)
4226 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4227 NULL, guids, &size);
4228 if (r != ERROR_SUCCESS)
4231 ptr = strchrW(guids, ';');
4233 squash_guid(guids, packcode);
4234 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4237 MsiCloseHandle(suminfo);
4238 return ERROR_SUCCESS;
4241 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4246 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4248 upgrade = msi_dup_property(package->db, szUpgradeCode);
4250 return ERROR_SUCCESS;
4252 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4253 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4255 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4257 if (r != ERROR_SUCCESS)
4259 WARN("failed to open upgrade code key\n");
4261 return ERROR_SUCCESS;
4263 squash_guid(package->ProductCode, squashed_pc);
4264 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4267 return ERROR_SUCCESS;
4270 static BOOL msi_check_publish(MSIPACKAGE *package)
4272 MSIFEATURE *feature;
4274 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4276 feature->Action = msi_get_feature_action( package, feature );
4277 if (feature->Action == INSTALLSTATE_LOCAL)
4284 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4286 MSIFEATURE *feature;
4288 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4290 feature->Action = msi_get_feature_action( package, feature );
4291 if (feature->Action != INSTALLSTATE_ABSENT)
4298 static UINT msi_publish_patches( MSIPACKAGE *package )
4300 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4301 WCHAR patch_squashed[GUID_SIZE];
4302 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4304 MSIPATCHINFO *patch;
4306 WCHAR *p, *all_patches = NULL;
4309 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4310 if (r != ERROR_SUCCESS)
4311 return ERROR_FUNCTION_FAILED;
4313 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4314 if (res != ERROR_SUCCESS)
4316 r = ERROR_FUNCTION_FAILED;
4320 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4321 if (r != ERROR_SUCCESS)
4324 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4326 squash_guid( patch->patchcode, patch_squashed );
4327 len += strlenW( patch_squashed ) + 1;
4330 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4334 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4338 squash_guid( patch->patchcode, p );
4339 p += strlenW( p ) + 1;
4341 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4342 (const BYTE *)patch->transforms,
4343 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4344 if (res != ERROR_SUCCESS)
4347 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4348 if (r != ERROR_SUCCESS)
4351 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4352 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4353 RegCloseKey( patch_key );
4354 if (res != ERROR_SUCCESS)
4357 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4359 res = GetLastError();
4360 ERR("Unable to copy patch package %d\n", res);
4363 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4364 if (res != ERROR_SUCCESS)
4367 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4368 RegCloseKey( patch_key );
4369 if (res != ERROR_SUCCESS)
4373 all_patches[len] = 0;
4374 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4375 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4376 if (res != ERROR_SUCCESS)
4379 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4380 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4381 if (res != ERROR_SUCCESS)
4382 r = ERROR_FUNCTION_FAILED;
4385 RegCloseKey( product_patches_key );
4386 RegCloseKey( patches_key );
4387 RegCloseKey( product_key );
4388 msi_free( all_patches );
4392 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4395 HKEY hukey = NULL, hudkey = NULL;
4398 if (!list_empty(&package->patches))
4400 rc = msi_publish_patches(package);
4401 if (rc != ERROR_SUCCESS)
4405 /* FIXME: also need to publish if the product is in advertise mode */
4406 if (!msi_check_publish(package))
4407 return ERROR_SUCCESS;
4409 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4411 if (rc != ERROR_SUCCESS)
4414 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4415 NULL, &hudkey, TRUE);
4416 if (rc != ERROR_SUCCESS)
4419 rc = msi_publish_upgrade_code(package);
4420 if (rc != ERROR_SUCCESS)
4423 rc = msi_publish_product_properties(package, hukey);
4424 if (rc != ERROR_SUCCESS)
4427 rc = msi_publish_sourcelist(package, hukey);
4428 if (rc != ERROR_SUCCESS)
4431 rc = msi_publish_icons(package);
4434 uirow = MSI_CreateRecord( 1 );
4435 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4436 msi_ui_actiondata( package, szPublishProduct, uirow );
4437 msiobj_release( &uirow->hdr );
4440 RegCloseKey(hudkey);
4444 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4446 WCHAR *filename, *ptr, *folder, *ret;
4447 const WCHAR *dirprop;
4449 filename = msi_dup_record_field( row, 2 );
4450 if (filename && (ptr = strchrW( filename, '|' )))
4455 dirprop = MSI_RecordGetString( row, 3 );
4458 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4459 if (!folder) folder = msi_dup_property( package->db, dirprop );
4462 folder = msi_dup_property( package->db, szWindowsFolder );
4466 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4467 msi_free( filename );
4471 ret = msi_build_directory_name( 2, folder, ptr );
4473 msi_free( filename );
4478 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4480 MSIPACKAGE *package = param;
4481 LPCWSTR component, section, key, value, identifier;
4482 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4487 component = MSI_RecordGetString(row, 8);
4488 comp = msi_get_loaded_component(package,component);
4490 return ERROR_SUCCESS;
4492 comp->Action = msi_get_component_action( package, comp );
4493 if (comp->Action != INSTALLSTATE_LOCAL)
4495 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4496 return ERROR_SUCCESS;
4499 identifier = MSI_RecordGetString(row,1);
4500 section = MSI_RecordGetString(row,4);
4501 key = MSI_RecordGetString(row,5);
4502 value = MSI_RecordGetString(row,6);
4503 action = MSI_RecordGetInteger(row,7);
4505 deformat_string(package,section,&deformated_section);
4506 deformat_string(package,key,&deformated_key);
4507 deformat_string(package,value,&deformated_value);
4509 fullname = get_ini_file_name(package, row);
4513 TRACE("Adding value %s to section %s in %s\n",
4514 debugstr_w(deformated_key), debugstr_w(deformated_section),
4515 debugstr_w(fullname));
4516 WritePrivateProfileStringW(deformated_section, deformated_key,
4517 deformated_value, fullname);
4519 else if (action == 1)
4522 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4523 returned, 10, fullname);
4524 if (returned[0] == 0)
4526 TRACE("Adding value %s to section %s in %s\n",
4527 debugstr_w(deformated_key), debugstr_w(deformated_section),
4528 debugstr_w(fullname));
4530 WritePrivateProfileStringW(deformated_section, deformated_key,
4531 deformated_value, fullname);
4534 else if (action == 3)
4535 FIXME("Append to existing section not yet implemented\n");
4537 uirow = MSI_CreateRecord(4);
4538 MSI_RecordSetStringW(uirow,1,identifier);
4539 MSI_RecordSetStringW(uirow,2,deformated_section);
4540 MSI_RecordSetStringW(uirow,3,deformated_key);
4541 MSI_RecordSetStringW(uirow,4,deformated_value);
4542 msi_ui_actiondata( package, szWriteIniValues, uirow );
4543 msiobj_release( &uirow->hdr );
4546 msi_free(deformated_key);
4547 msi_free(deformated_value);
4548 msi_free(deformated_section);
4549 return ERROR_SUCCESS;
4552 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4554 static const WCHAR query[] = {
4555 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4556 '`','I','n','i','F','i','l','e','`',0};
4560 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4561 if (rc != ERROR_SUCCESS)
4562 return ERROR_SUCCESS;
4564 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4565 msiobj_release(&view->hdr);
4569 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4571 MSIPACKAGE *package = param;
4572 LPCWSTR component, section, key, value, identifier;
4573 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4578 component = MSI_RecordGetString( row, 8 );
4579 comp = msi_get_loaded_component( package, component );
4581 return ERROR_SUCCESS;
4583 comp->Action = msi_get_component_action( package, comp );
4584 if (comp->Action != INSTALLSTATE_ABSENT)
4586 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4587 return ERROR_SUCCESS;
4590 identifier = MSI_RecordGetString( row, 1 );
4591 section = MSI_RecordGetString( row, 4 );
4592 key = MSI_RecordGetString( row, 5 );
4593 value = MSI_RecordGetString( row, 6 );
4594 action = MSI_RecordGetInteger( row, 7 );
4596 deformat_string( package, section, &deformated_section );
4597 deformat_string( package, key, &deformated_key );
4598 deformat_string( package, value, &deformated_value );
4600 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4602 filename = get_ini_file_name( package, row );
4604 TRACE("Removing key %s from section %s in %s\n",
4605 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4607 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4609 WARN("Unable to remove key %u\n", GetLastError());
4611 msi_free( filename );
4614 FIXME("Unsupported action %d\n", action);
4617 uirow = MSI_CreateRecord( 4 );
4618 MSI_RecordSetStringW( uirow, 1, identifier );
4619 MSI_RecordSetStringW( uirow, 2, deformated_section );
4620 MSI_RecordSetStringW( uirow, 3, deformated_key );
4621 MSI_RecordSetStringW( uirow, 4, deformated_value );
4622 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4623 msiobj_release( &uirow->hdr );
4625 msi_free( deformated_key );
4626 msi_free( deformated_value );
4627 msi_free( deformated_section );
4628 return ERROR_SUCCESS;
4631 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4633 MSIPACKAGE *package = param;
4634 LPCWSTR component, section, key, value, identifier;
4635 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4640 component = MSI_RecordGetString( row, 8 );
4641 comp = msi_get_loaded_component( package, component );
4643 return ERROR_SUCCESS;
4645 comp->Action = msi_get_component_action( package, comp );
4646 if (comp->Action != INSTALLSTATE_LOCAL)
4648 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4649 return ERROR_SUCCESS;
4652 identifier = MSI_RecordGetString( row, 1 );
4653 section = MSI_RecordGetString( row, 4 );
4654 key = MSI_RecordGetString( row, 5 );
4655 value = MSI_RecordGetString( row, 6 );
4656 action = MSI_RecordGetInteger( row, 7 );
4658 deformat_string( package, section, &deformated_section );
4659 deformat_string( package, key, &deformated_key );
4660 deformat_string( package, value, &deformated_value );
4662 if (action == msidbIniFileActionRemoveLine)
4664 filename = get_ini_file_name( package, row );
4666 TRACE("Removing key %s from section %s in %s\n",
4667 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4669 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4671 WARN("Unable to remove key %u\n", GetLastError());
4673 msi_free( filename );
4676 FIXME("Unsupported action %d\n", action);
4678 uirow = MSI_CreateRecord( 4 );
4679 MSI_RecordSetStringW( uirow, 1, identifier );
4680 MSI_RecordSetStringW( uirow, 2, deformated_section );
4681 MSI_RecordSetStringW( uirow, 3, deformated_key );
4682 MSI_RecordSetStringW( uirow, 4, deformated_value );
4683 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4684 msiobj_release( &uirow->hdr );
4686 msi_free( deformated_key );
4687 msi_free( deformated_value );
4688 msi_free( deformated_section );
4689 return ERROR_SUCCESS;
4692 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4694 static const WCHAR query[] = {
4695 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4696 '`','I','n','i','F','i','l','e','`',0};
4697 static const WCHAR remove_query[] = {
4698 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4699 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4703 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4704 if (rc == ERROR_SUCCESS)
4706 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4707 msiobj_release( &view->hdr );
4708 if (rc != ERROR_SUCCESS)
4711 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4712 if (rc == ERROR_SUCCESS)
4714 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4715 msiobj_release( &view->hdr );
4716 if (rc != ERROR_SUCCESS)
4719 return ERROR_SUCCESS;
4722 static void register_dll( const WCHAR *dll, BOOL unregister )
4726 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4729 HRESULT (WINAPI *func_ptr)( void );
4730 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4732 func_ptr = (void *)GetProcAddress( hmod, func );
4735 HRESULT hr = func_ptr();
4737 WARN("failed to register dll 0x%08x\n", hr);
4740 WARN("entry point %s not found\n", func);
4741 FreeLibrary( hmod );
4744 WARN("failed to load library %u\n", GetLastError());
4747 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4749 MSIPACKAGE *package = param;
4754 filename = MSI_RecordGetString( row, 1 );
4755 file = msi_get_loaded_file( package, filename );
4758 WARN("unable to find file %s\n", debugstr_w(filename));
4759 return ERROR_SUCCESS;
4761 file->Component->Action = msi_get_component_action( package, file->Component );
4762 if (file->Component->Action != INSTALLSTATE_LOCAL)
4764 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4765 return ERROR_SUCCESS;
4768 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4769 register_dll( file->TargetPath, FALSE );
4771 uirow = MSI_CreateRecord( 2 );
4772 MSI_RecordSetStringW( uirow, 1, file->File );
4773 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4774 msi_ui_actiondata( package, szSelfRegModules, uirow );
4775 msiobj_release( &uirow->hdr );
4777 return ERROR_SUCCESS;
4780 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4782 static const WCHAR query[] = {
4783 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4784 '`','S','e','l','f','R','e','g','`',0};
4788 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4789 if (rc != ERROR_SUCCESS)
4790 return ERROR_SUCCESS;
4792 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4793 msiobj_release(&view->hdr);
4797 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4799 MSIPACKAGE *package = param;
4804 filename = MSI_RecordGetString( row, 1 );
4805 file = msi_get_loaded_file( package, filename );
4808 WARN("unable to find file %s\n", debugstr_w(filename));
4809 return ERROR_SUCCESS;
4811 file->Component->Action = msi_get_component_action( package, file->Component );
4812 if (file->Component->Action != INSTALLSTATE_ABSENT)
4814 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4815 return ERROR_SUCCESS;
4818 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4819 register_dll( file->TargetPath, TRUE );
4821 uirow = MSI_CreateRecord( 2 );
4822 MSI_RecordSetStringW( uirow, 1, file->File );
4823 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4824 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4825 msiobj_release( &uirow->hdr );
4827 return ERROR_SUCCESS;
4830 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4832 static const WCHAR query[] = {
4833 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4834 '`','S','e','l','f','R','e','g','`',0};
4838 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4839 if (rc != ERROR_SUCCESS)
4840 return ERROR_SUCCESS;
4842 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4843 msiobj_release( &view->hdr );
4847 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4849 MSIFEATURE *feature;
4851 HKEY hkey = NULL, userdata = NULL;
4853 if (!msi_check_publish(package))
4854 return ERROR_SUCCESS;
4856 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4858 if (rc != ERROR_SUCCESS)
4861 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4863 if (rc != ERROR_SUCCESS)
4866 /* here the guids are base 85 encoded */
4867 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4873 BOOL absent = FALSE;
4876 if (feature->Action != INSTALLSTATE_LOCAL &&
4877 feature->Action != INSTALLSTATE_SOURCE &&
4878 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4881 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4885 if (feature->Feature_Parent)
4886 size += strlenW( feature->Feature_Parent )+2;
4888 data = msi_alloc(size * sizeof(WCHAR));
4891 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4893 MSICOMPONENT* component = cl->component;
4897 if (component->ComponentId)
4899 TRACE("From %s\n",debugstr_w(component->ComponentId));
4900 CLSIDFromString(component->ComponentId, &clsid);
4901 encode_base85_guid(&clsid,buf);
4902 TRACE("to %s\n",debugstr_w(buf));
4907 if (feature->Feature_Parent)
4909 static const WCHAR sep[] = {'\2',0};
4911 strcatW(data,feature->Feature_Parent);
4914 msi_reg_set_val_str( userdata, feature->Feature, data );
4918 if (feature->Feature_Parent)
4919 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4922 size += sizeof(WCHAR);
4923 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4924 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4928 size += 2*sizeof(WCHAR);
4929 data = msi_alloc(size);
4932 if (feature->Feature_Parent)
4933 strcpyW( &data[1], feature->Feature_Parent );
4934 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4940 uirow = MSI_CreateRecord( 1 );
4941 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4942 msi_ui_actiondata( package, szPublishFeatures, uirow );
4943 msiobj_release( &uirow->hdr );
4944 /* FIXME: call msi_ui_progress? */
4949 RegCloseKey(userdata);
4953 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4959 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4961 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4963 if (r == ERROR_SUCCESS)
4965 RegDeleteValueW(hkey, feature->Feature);
4969 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4971 if (r == ERROR_SUCCESS)
4973 RegDeleteValueW(hkey, feature->Feature);
4977 uirow = MSI_CreateRecord( 1 );
4978 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4979 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4980 msiobj_release( &uirow->hdr );
4982 return ERROR_SUCCESS;
4985 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4987 MSIFEATURE *feature;
4989 if (!msi_check_unpublish(package))
4990 return ERROR_SUCCESS;
4992 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4994 msi_unpublish_feature(package, feature);
4997 return ERROR_SUCCESS;
5000 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
5004 WCHAR date[9], *val, *buffer;
5005 const WCHAR *prop, *key;
5007 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
5008 static const WCHAR modpath_fmt[] =
5009 {'M','s','i','E','x','e','c','.','e','x','e',' ',
5010 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
5011 static const WCHAR szModifyPath[] =
5012 {'M','o','d','i','f','y','P','a','t','h',0};
5013 static const WCHAR szUninstallString[] =
5014 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5015 static const WCHAR szEstimatedSize[] =
5016 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5017 static const WCHAR szDisplayVersion[] =
5018 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5019 static const WCHAR szInstallSource[] =
5020 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5021 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
5022 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5023 static const WCHAR szAuthorizedCDFPrefix[] =
5024 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5025 static const WCHAR szARPCONTACT[] =
5026 {'A','R','P','C','O','N','T','A','C','T',0};
5027 static const WCHAR szContact[] =
5028 {'C','o','n','t','a','c','t',0};
5029 static const WCHAR szARPCOMMENTS[] =
5030 {'A','R','P','C','O','M','M','E','N','T','S',0};
5031 static const WCHAR szComments[] =
5032 {'C','o','m','m','e','n','t','s',0};
5033 static const WCHAR szProductName[] =
5034 {'P','r','o','d','u','c','t','N','a','m','e',0};
5035 static const WCHAR szDisplayName[] =
5036 {'D','i','s','p','l','a','y','N','a','m','e',0};
5037 static const WCHAR szARPHELPLINK[] =
5038 {'A','R','P','H','E','L','P','L','I','N','K',0};
5039 static const WCHAR szHelpLink[] =
5040 {'H','e','l','p','L','i','n','k',0};
5041 static const WCHAR szARPHELPTELEPHONE[] =
5042 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5043 static const WCHAR szHelpTelephone[] =
5044 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5045 static const WCHAR szARPINSTALLLOCATION[] =
5046 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5047 static const WCHAR szManufacturer[] =
5048 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5049 static const WCHAR szPublisher[] =
5050 {'P','u','b','l','i','s','h','e','r',0};
5051 static const WCHAR szARPREADME[] =
5052 {'A','R','P','R','E','A','D','M','E',0};
5053 static const WCHAR szReadme[] =
5054 {'R','e','a','d','M','e',0};
5055 static const WCHAR szARPSIZE[] =
5056 {'A','R','P','S','I','Z','E',0};
5057 static const WCHAR szSize[] =
5058 {'S','i','z','e',0};
5059 static const WCHAR szARPURLINFOABOUT[] =
5060 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5061 static const WCHAR szURLInfoAbout[] =
5062 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5063 static const WCHAR szARPURLUPDATEINFO[] =
5064 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5065 static const WCHAR szURLUpdateInfo[] =
5066 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5067 static const WCHAR szARPSYSTEMCOMPONENT[] =
5068 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
5069 static const WCHAR szSystemComponent[] =
5070 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
5072 static const WCHAR *propval[] = {
5073 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
5074 szARPCONTACT, szContact,
5075 szARPCOMMENTS, szComments,
5076 szProductName, szDisplayName,
5077 szARPHELPLINK, szHelpLink,
5078 szARPHELPTELEPHONE, szHelpTelephone,
5079 szARPINSTALLLOCATION, szInstallLocation,
5080 szSourceDir, szInstallSource,
5081 szManufacturer, szPublisher,
5082 szARPREADME, szReadme,
5084 szARPURLINFOABOUT, szURLInfoAbout,
5085 szARPURLUPDATEINFO, szURLUpdateInfo,
5088 const WCHAR **p = propval;
5094 val = msi_dup_property(package->db, prop);
5095 msi_reg_set_val_str(hkey, key, val);
5099 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5100 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
5102 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
5104 size = deformat_string(package, modpath_fmt, &buffer) * sizeof(WCHAR);
5105 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5106 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5109 /* FIXME: Write real Estimated Size when we have it */
5110 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5112 GetLocalTime(&systime);
5113 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5114 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5116 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5117 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5119 buffer = msi_dup_property(package->db, szProductVersion);
5120 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5123 DWORD verdword = msi_version_str_to_dword(buffer);
5125 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5126 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5127 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5131 return ERROR_SUCCESS;
5134 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5136 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5138 LPWSTR upgrade_code;
5139 HKEY hkey, props, upgrade_key;
5142 /* FIXME: also need to publish if the product is in advertise mode */
5143 if (!msi_check_publish(package))
5144 return ERROR_SUCCESS;
5146 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
5147 if (rc != ERROR_SUCCESS)
5150 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
5151 if (rc != ERROR_SUCCESS)
5154 rc = msi_publish_install_properties(package, hkey);
5155 if (rc != ERROR_SUCCESS)
5158 rc = msi_publish_install_properties(package, props);
5159 if (rc != ERROR_SUCCESS)
5162 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5165 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
5166 if (rc == ERROR_SUCCESS)
5168 squash_guid( package->ProductCode, squashed_pc );
5169 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
5170 RegCloseKey( upgrade_key );
5172 msi_free( upgrade_code );
5174 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
5175 package->delete_on_close = FALSE;
5178 uirow = MSI_CreateRecord( 1 );
5179 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5180 msi_ui_actiondata( package, szRegisterProduct, uirow );
5181 msiobj_release( &uirow->hdr );
5184 return ERROR_SUCCESS;
5187 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5189 return execute_script(package, SCRIPT_INSTALL);
5192 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5194 MSIPACKAGE *package = param;
5195 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5196 WCHAR *p, *icon_path;
5198 if (!icon) return ERROR_SUCCESS;
5199 if ((icon_path = msi_build_icon_path( package, icon )))
5201 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5202 DeleteFileW( icon_path );
5203 if ((p = strrchrW( icon_path, '\\' )))
5206 RemoveDirectoryW( icon_path );
5208 msi_free( icon_path );
5210 return ERROR_SUCCESS;
5213 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5215 static const WCHAR query[]= {
5216 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
5220 r = MSI_DatabaseOpenViewW( package->db, query, &view );
5221 if (r == ERROR_SUCCESS)
5223 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5224 msiobj_release( &view->hdr );
5225 if (r != ERROR_SUCCESS)
5228 return ERROR_SUCCESS;
5231 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
5233 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
5234 WCHAR *upgrade, **features;
5235 BOOL full_uninstall = TRUE;
5236 MSIFEATURE *feature;
5237 MSIPATCHINFO *patch;
5240 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5242 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
5244 features = msi_split_string( remove, ',' );
5245 for (i = 0; features && features[i]; i++)
5247 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
5251 if (!full_uninstall)
5252 return ERROR_SUCCESS;
5254 MSIREG_DeleteProductKey(package->ProductCode);
5255 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5256 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5258 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5259 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5260 MSIREG_DeleteUserProductKey(package->ProductCode);
5261 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5263 upgrade = msi_dup_property(package->db, szUpgradeCode);
5266 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5267 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5271 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5273 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5274 if (!strcmpW( package->ProductCode, patch->products ))
5276 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5277 patch->delete_on_close = TRUE;
5279 /* FIXME: remove local patch package if this is the last product */
5281 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5282 package->delete_on_close = TRUE;
5284 msi_unpublish_icons( package );
5285 return ERROR_SUCCESS;
5288 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5293 /* turn off scheduling */
5294 package->script->CurrentlyScripting= FALSE;
5296 /* first do the same as an InstallExecute */
5297 rc = ACTION_InstallExecute(package);
5298 if (rc != ERROR_SUCCESS)
5301 /* then handle commit actions */
5302 rc = execute_script(package, SCRIPT_COMMIT);
5303 if (rc != ERROR_SUCCESS)
5306 remove = msi_dup_property(package->db, szRemove);
5307 rc = msi_unpublish_product(package, remove);
5312 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5314 static const WCHAR RunOnce[] = {
5315 'S','o','f','t','w','a','r','e','\\',
5316 'M','i','c','r','o','s','o','f','t','\\',
5317 'W','i','n','d','o','w','s','\\',
5318 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5319 'R','u','n','O','n','c','e',0};
5320 static const WCHAR InstallRunOnce[] = {
5321 'S','o','f','t','w','a','r','e','\\',
5322 'M','i','c','r','o','s','o','f','t','\\',
5323 'W','i','n','d','o','w','s','\\',
5324 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5325 'I','n','s','t','a','l','l','e','r','\\',
5326 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5328 static const WCHAR msiexec_fmt[] = {
5330 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5331 '\"','%','s','\"',0};
5332 static const WCHAR install_fmt[] = {
5333 '/','I',' ','\"','%','s','\"',' ',
5334 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5335 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5336 WCHAR buffer[256], sysdir[MAX_PATH];
5338 WCHAR squished_pc[100];
5340 squash_guid(package->ProductCode,squished_pc);
5342 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5343 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5344 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5347 msi_reg_set_val_str( hkey, squished_pc, buffer );
5350 TRACE("Reboot command %s\n",debugstr_w(buffer));
5352 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5353 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5355 msi_reg_set_val_str( hkey, squished_pc, buffer );
5358 return ERROR_INSTALL_SUSPEND;
5361 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5363 static const WCHAR query[] =
5364 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5365 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5366 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5367 MSIRECORD *rec, *row;
5373 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5375 rec = MSI_CreateRecord( count + 2 );
5376 str = MSI_RecordGetString( row, 1 );
5377 MSI_RecordSetStringW( rec, 0, str );
5378 msiobj_release( &row->hdr );
5379 MSI_RecordSetInteger( rec, 1, error );
5381 va_start( va, count );
5382 for (i = 0; i < count; i++)
5384 str = va_arg( va, const WCHAR *);
5385 MSI_RecordSetStringW( rec, i + 2, str );
5389 MSI_FormatRecordW( package, rec, NULL, &size );
5391 data = msi_alloc( size * sizeof(WCHAR) );
5392 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5394 msiobj_release( &rec->hdr );
5398 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5404 * We are currently doing what should be done here in the top level Install
5405 * however for Administrative and uninstalls this step will be needed
5407 if (!package->PackagePath)
5408 return ERROR_SUCCESS;
5410 msi_set_sourcedir_props(package, TRUE);
5412 attrib = GetFileAttributesW(package->db->path);
5413 if (attrib == INVALID_FILE_ATTRIBUTES)
5418 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5419 package->Context, MSICODE_PRODUCT,
5420 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5421 if (rc == ERROR_MORE_DATA)
5423 prompt = msi_alloc(size * sizeof(WCHAR));
5424 MsiSourceListGetInfoW(package->ProductCode, NULL,
5425 package->Context, MSICODE_PRODUCT,
5426 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5429 prompt = strdupW(package->db->path);
5431 msg = msi_build_error_string(package, 1302, 1, prompt);
5433 while(attrib == INVALID_FILE_ATTRIBUTES)
5435 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5439 return ERROR_INSTALL_USEREXIT;
5441 attrib = GetFileAttributesW(package->db->path);
5447 return ERROR_SUCCESS;
5452 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5455 LPWSTR buffer, productid = NULL;
5456 UINT i, rc = ERROR_SUCCESS;
5459 static const WCHAR szPropKeys[][80] =
5461 {'P','r','o','d','u','c','t','I','D',0},
5462 {'U','S','E','R','N','A','M','E',0},
5463 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5467 static const WCHAR szRegKeys[][80] =
5469 {'P','r','o','d','u','c','t','I','D',0},
5470 {'R','e','g','O','w','n','e','r',0},
5471 {'R','e','g','C','o','m','p','a','n','y',0},
5475 if (msi_check_unpublish(package))
5477 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5481 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5485 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5487 if (rc != ERROR_SUCCESS)
5490 for( i = 0; szPropKeys[i][0]; i++ )
5492 buffer = msi_dup_property( package->db, szPropKeys[i] );
5493 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5498 uirow = MSI_CreateRecord( 1 );
5499 MSI_RecordSetStringW( uirow, 1, productid );
5500 msi_ui_actiondata( package, szRegisterUser, uirow );
5501 msiobj_release( &uirow->hdr );
5503 msi_free(productid);
5509 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5513 package->script->InWhatSequence |= SEQUENCE_EXEC;
5514 rc = ACTION_ProcessExecSequence(package,FALSE);
5518 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5520 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5521 WCHAR productid_85[21], component_85[21], *ret;
5525 /* > is used if there is a component GUID and < if not. */
5527 productid_85[0] = 0;
5528 component_85[0] = 0;
5529 CLSIDFromString( package->ProductCode, &clsid );
5531 encode_base85_guid( &clsid, productid_85 );
5534 CLSIDFromString( component->ComponentId, &clsid );
5535 encode_base85_guid( &clsid, component_85 );
5538 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5539 debugstr_w(component_85));
5541 sz = 20 + strlenW( feature ) + 20 + 3;
5542 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5543 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5547 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5549 MSIPACKAGE *package = param;
5550 LPCWSTR compgroupid, component, feature, qualifier, text;
5551 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5560 feature = MSI_RecordGetString(rec, 5);
5561 feat = msi_get_loaded_feature(package, feature);
5563 return ERROR_SUCCESS;
5565 feat->Action = msi_get_feature_action( package, feat );
5566 if (feat->Action != INSTALLSTATE_LOCAL &&
5567 feat->Action != INSTALLSTATE_SOURCE &&
5568 feat->Action != INSTALLSTATE_ADVERTISED)
5570 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5571 return ERROR_SUCCESS;
5574 component = MSI_RecordGetString(rec, 3);
5575 comp = msi_get_loaded_component(package, component);
5577 return ERROR_SUCCESS;
5579 compgroupid = MSI_RecordGetString(rec,1);
5580 qualifier = MSI_RecordGetString(rec,2);
5582 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5583 if (rc != ERROR_SUCCESS)
5586 advertise = msi_create_component_advertise_string( package, comp, feature );
5587 text = MSI_RecordGetString( rec, 4 );
5590 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5591 strcpyW( p, advertise );
5593 msi_free( advertise );
5596 existing = msi_reg_get_val_str( hkey, qualifier );
5598 sz = strlenW( advertise ) + 1;
5601 for (p = existing; *p; p += len)
5603 len = strlenW( p ) + 1;
5604 if (strcmpW( advertise, p )) sz += len;
5607 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5609 rc = ERROR_OUTOFMEMORY;
5615 for (p = existing; *p; p += len)
5617 len = strlenW( p ) + 1;
5618 if (strcmpW( advertise, p ))
5620 memcpy( q, p, len * sizeof(WCHAR) );
5625 strcpyW( q, advertise );
5626 q[strlenW( q ) + 1] = 0;
5628 msi_reg_set_val_multi_str( hkey, qualifier, output );
5633 msi_free( advertise );
5634 msi_free( existing );
5637 uirow = MSI_CreateRecord( 2 );
5638 MSI_RecordSetStringW( uirow, 1, compgroupid );
5639 MSI_RecordSetStringW( uirow, 2, qualifier);
5640 msi_ui_actiondata( package, szPublishComponents, uirow );
5641 msiobj_release( &uirow->hdr );
5642 /* FIXME: call ui_progress? */
5648 * At present I am ignorning the advertised components part of this and only
5649 * focusing on the qualified component sets
5651 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5653 static const WCHAR query[] = {
5654 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5655 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5659 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5660 if (rc != ERROR_SUCCESS)
5661 return ERROR_SUCCESS;
5663 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5664 msiobj_release(&view->hdr);
5668 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5670 static const WCHAR szInstallerComponents[] = {
5671 'S','o','f','t','w','a','r','e','\\',
5672 'M','i','c','r','o','s','o','f','t','\\',
5673 'I','n','s','t','a','l','l','e','r','\\',
5674 'C','o','m','p','o','n','e','n','t','s','\\',0};
5676 MSIPACKAGE *package = param;
5677 LPCWSTR compgroupid, component, feature, qualifier;
5681 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5684 feature = MSI_RecordGetString( rec, 5 );
5685 feat = msi_get_loaded_feature( package, feature );
5687 return ERROR_SUCCESS;
5689 feat->Action = msi_get_feature_action( package, feat );
5690 if (feat->Action != INSTALLSTATE_ABSENT)
5692 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5693 return ERROR_SUCCESS;
5696 component = MSI_RecordGetString( rec, 3 );
5697 comp = msi_get_loaded_component( package, component );
5699 return ERROR_SUCCESS;
5701 compgroupid = MSI_RecordGetString( rec, 1 );
5702 qualifier = MSI_RecordGetString( rec, 2 );
5704 squash_guid( compgroupid, squashed );
5705 strcpyW( keypath, szInstallerComponents );
5706 strcatW( keypath, squashed );
5708 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5709 if (res != ERROR_SUCCESS)
5711 WARN("Unable to delete component key %d\n", res);
5714 uirow = MSI_CreateRecord( 2 );
5715 MSI_RecordSetStringW( uirow, 1, compgroupid );
5716 MSI_RecordSetStringW( uirow, 2, qualifier );
5717 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5718 msiobj_release( &uirow->hdr );
5720 return ERROR_SUCCESS;
5723 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5725 static const WCHAR query[] = {
5726 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5727 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5731 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5732 if (rc != ERROR_SUCCESS)
5733 return ERROR_SUCCESS;
5735 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5736 msiobj_release( &view->hdr );
5740 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5742 static const WCHAR query[] =
5743 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5744 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5745 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5746 MSIPACKAGE *package = param;
5747 MSICOMPONENT *component;
5750 SC_HANDLE hscm = NULL, service = NULL;
5752 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5753 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5754 DWORD serv_type, start_type, err_control;
5755 SERVICE_DESCRIPTIONW sd = {NULL};
5757 comp = MSI_RecordGetString( rec, 12 );
5758 component = msi_get_loaded_component( package, comp );
5761 WARN("service component not found\n");
5764 component->Action = msi_get_component_action( package, component );
5765 if (component->Action != INSTALLSTATE_LOCAL)
5767 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5770 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5773 ERR("Failed to open the SC Manager!\n");
5777 start_type = MSI_RecordGetInteger(rec, 5);
5778 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5781 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5782 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5783 serv_type = MSI_RecordGetInteger(rec, 4);
5784 err_control = MSI_RecordGetInteger(rec, 6);
5785 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5786 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5787 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5788 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5789 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5790 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5792 /* fetch the service path */
5793 row = MSI_QueryGetRecord(package->db, query, comp);
5796 ERR("Query failed\n");
5799 key = MSI_RecordGetString(row, 6);
5800 file = msi_get_loaded_file(package, key);
5801 msiobj_release(&row->hdr);
5804 ERR("Failed to load the service file\n");
5808 if (!args || !args[0]) image_path = file->TargetPath;
5811 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5812 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5813 return ERROR_OUTOFMEMORY;
5815 strcpyW(image_path, file->TargetPath);
5816 strcatW(image_path, szSpace);
5817 strcatW(image_path, args);
5819 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5820 start_type, err_control, image_path, load_order,
5821 NULL, depends, serv_name, pass);
5825 if (GetLastError() != ERROR_SERVICE_EXISTS)
5826 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5828 else if (sd.lpDescription)
5830 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5831 WARN("failed to set service description %u\n", GetLastError());
5834 if (image_path != file->TargetPath) msi_free(image_path);
5836 CloseServiceHandle(service);
5837 CloseServiceHandle(hscm);
5840 msi_free(sd.lpDescription);
5841 msi_free(load_order);
5842 msi_free(serv_name);
5847 return ERROR_SUCCESS;
5850 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5852 static const WCHAR query[] = {
5853 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5854 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5858 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5859 if (rc != ERROR_SUCCESS)
5860 return ERROR_SUCCESS;
5862 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5863 msiobj_release(&view->hdr);
5867 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5868 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5870 LPCWSTR *vector, *temp_vector;
5874 static const WCHAR separator[] = {'[','~',']',0};
5877 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5882 vector = msi_alloc(sizeof(LPWSTR));
5890 vector[*numargs - 1] = p;
5892 if ((q = strstrW(p, separator)))
5896 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5902 vector = temp_vector;
5911 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5913 MSIPACKAGE *package = param;
5916 SC_HANDLE scm = NULL, service = NULL;
5917 LPCWSTR component, *vector = NULL;
5918 LPWSTR name, args, display_name = NULL;
5919 DWORD event, numargs, len, wait, dummy;
5920 UINT r = ERROR_FUNCTION_FAILED;
5921 SERVICE_STATUS_PROCESS status;
5922 ULONGLONG start_time;
5924 component = MSI_RecordGetString(rec, 6);
5925 comp = msi_get_loaded_component(package, component);
5927 return ERROR_SUCCESS;
5929 comp->Action = msi_get_component_action( package, comp );
5930 if (comp->Action != INSTALLSTATE_LOCAL)
5932 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5933 return ERROR_SUCCESS;
5936 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5937 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5938 event = MSI_RecordGetInteger(rec, 3);
5939 wait = MSI_RecordGetInteger(rec, 5);
5941 if (!(event & msidbServiceControlEventStart))
5947 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5950 ERR("Failed to open the service control manager\n");
5955 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5956 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5958 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5959 GetServiceDisplayNameW( scm, name, display_name, &len );
5962 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5965 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5969 vector = msi_service_args_to_vector(args, &numargs);
5971 if (!StartServiceW(service, numargs, vector) &&
5972 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5974 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5981 /* wait for at most 30 seconds for the service to be up and running */
5982 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5983 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5985 TRACE("failed to query service status (%u)\n", GetLastError());
5988 start_time = GetTickCount64();
5989 while (status.dwCurrentState == SERVICE_START_PENDING)
5991 if (GetTickCount64() - start_time > 30000) break;
5993 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5994 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5996 TRACE("failed to query service status (%u)\n", GetLastError());
6000 if (status.dwCurrentState != SERVICE_RUNNING)
6002 WARN("service failed to start %u\n", status.dwCurrentState);
6003 r = ERROR_FUNCTION_FAILED;
6008 uirow = MSI_CreateRecord( 2 );
6009 MSI_RecordSetStringW( uirow, 1, display_name );
6010 MSI_RecordSetStringW( uirow, 2, name );
6011 msi_ui_actiondata( package, szStartServices, uirow );
6012 msiobj_release( &uirow->hdr );
6014 CloseServiceHandle(service);
6015 CloseServiceHandle(scm);
6020 msi_free(display_name);
6024 static UINT ACTION_StartServices( MSIPACKAGE *package )
6026 static const WCHAR query[] = {
6027 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6028 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6032 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6033 if (rc != ERROR_SUCCESS)
6034 return ERROR_SUCCESS;
6036 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
6037 msiobj_release(&view->hdr);
6041 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6043 DWORD i, needed, count;
6044 ENUM_SERVICE_STATUSW *dependencies;
6048 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6049 0, &needed, &count))
6052 if (GetLastError() != ERROR_MORE_DATA)
6055 dependencies = msi_alloc(needed);
6059 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6060 needed, &needed, &count))
6063 for (i = 0; i < count; i++)
6065 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6066 SERVICE_STOP | SERVICE_QUERY_STATUS);
6070 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
6077 msi_free(dependencies);
6081 static UINT stop_service( LPCWSTR name )
6083 SC_HANDLE scm = NULL, service = NULL;
6084 SERVICE_STATUS status;
6085 SERVICE_STATUS_PROCESS ssp;
6088 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6091 WARN("Failed to open the SCM: %d\n", GetLastError());
6095 service = OpenServiceW(scm, name,
6097 SERVICE_QUERY_STATUS |
6098 SERVICE_ENUMERATE_DEPENDENTS);
6101 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
6105 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
6106 sizeof(SERVICE_STATUS_PROCESS), &needed))
6108 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
6112 if (ssp.dwCurrentState == SERVICE_STOPPED)
6115 stop_service_dependents(scm, service);
6117 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6118 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
6121 CloseServiceHandle(service);
6122 CloseServiceHandle(scm);
6124 return ERROR_SUCCESS;
6127 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6129 MSIPACKAGE *package = param;
6133 LPWSTR name = NULL, display_name = NULL;
6137 event = MSI_RecordGetInteger( rec, 3 );
6138 if (!(event & msidbServiceControlEventStop))
6139 return ERROR_SUCCESS;
6141 component = MSI_RecordGetString( rec, 6 );
6142 comp = msi_get_loaded_component( package, component );
6144 return ERROR_SUCCESS;
6146 comp->Action = msi_get_component_action( package, comp );
6147 if (comp->Action != INSTALLSTATE_ABSENT)
6149 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6150 return ERROR_SUCCESS;
6153 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6156 ERR("Failed to open the service control manager\n");
6161 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6162 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6164 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6165 GetServiceDisplayNameW( scm, name, display_name, &len );
6167 CloseServiceHandle( scm );
6169 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6170 stop_service( name );
6173 uirow = MSI_CreateRecord( 2 );
6174 MSI_RecordSetStringW( uirow, 1, display_name );
6175 MSI_RecordSetStringW( uirow, 2, name );
6176 msi_ui_actiondata( package, szStopServices, uirow );
6177 msiobj_release( &uirow->hdr );
6180 msi_free( display_name );
6181 return ERROR_SUCCESS;
6184 static UINT ACTION_StopServices( MSIPACKAGE *package )
6186 static const WCHAR query[] = {
6187 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6188 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6192 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6193 if (rc != ERROR_SUCCESS)
6194 return ERROR_SUCCESS;
6196 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6197 msiobj_release(&view->hdr);
6201 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6203 MSIPACKAGE *package = param;
6206 LPWSTR name = NULL, display_name = NULL;
6208 SC_HANDLE scm = NULL, service = NULL;
6210 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6212 return ERROR_SUCCESS;
6214 event = MSI_RecordGetInteger( rec, 3 );
6215 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6217 comp->Action = msi_get_component_action( package, comp );
6218 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6219 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6221 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6223 return ERROR_SUCCESS;
6225 stop_service( name );
6227 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6230 WARN("Failed to open the SCM: %d\n", GetLastError());
6235 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6236 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6238 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6239 GetServiceDisplayNameW( scm, name, display_name, &len );
6242 service = OpenServiceW( scm, name, DELETE );
6245 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6249 if (!DeleteService( service ))
6250 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6253 uirow = MSI_CreateRecord( 2 );
6254 MSI_RecordSetStringW( uirow, 1, display_name );
6255 MSI_RecordSetStringW( uirow, 2, name );
6256 msi_ui_actiondata( package, szDeleteServices, uirow );
6257 msiobj_release( &uirow->hdr );
6259 CloseServiceHandle( service );
6260 CloseServiceHandle( scm );
6262 msi_free( display_name );
6264 return ERROR_SUCCESS;
6267 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6269 static const WCHAR query[] = {
6270 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6271 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6275 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6276 if (rc != ERROR_SUCCESS)
6277 return ERROR_SUCCESS;
6279 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6280 msiobj_release( &view->hdr );
6284 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6286 MSIPACKAGE *package = param;
6287 LPWSTR driver, driver_path, ptr;
6288 WCHAR outpath[MAX_PATH];
6289 MSIFILE *driver_file = NULL, *setup_file = NULL;
6292 LPCWSTR desc, file_key, component;
6294 UINT r = ERROR_SUCCESS;
6296 static const WCHAR driver_fmt[] = {
6297 'D','r','i','v','e','r','=','%','s',0};
6298 static const WCHAR setup_fmt[] = {
6299 'S','e','t','u','p','=','%','s',0};
6300 static const WCHAR usage_fmt[] = {
6301 'F','i','l','e','U','s','a','g','e','=','1',0};
6303 component = MSI_RecordGetString( rec, 2 );
6304 comp = msi_get_loaded_component( package, component );
6306 return ERROR_SUCCESS;
6308 comp->Action = msi_get_component_action( package, comp );
6309 if (comp->Action != INSTALLSTATE_LOCAL)
6311 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6312 return ERROR_SUCCESS;
6314 desc = MSI_RecordGetString(rec, 3);
6316 file_key = MSI_RecordGetString( rec, 4 );
6317 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6319 file_key = MSI_RecordGetString( rec, 5 );
6320 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6324 ERR("ODBC Driver entry not found!\n");
6325 return ERROR_FUNCTION_FAILED;
6328 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6330 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6331 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6333 driver = msi_alloc(len * sizeof(WCHAR));
6335 return ERROR_OUTOFMEMORY;
6338 lstrcpyW(ptr, desc);
6339 ptr += lstrlenW(ptr) + 1;
6341 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6346 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6350 lstrcpyW(ptr, usage_fmt);
6351 ptr += lstrlenW(ptr) + 1;
6354 if (!driver_file->TargetPath)
6356 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6357 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6359 driver_path = strdupW(driver_file->TargetPath);
6360 ptr = strrchrW(driver_path, '\\');
6361 if (ptr) *ptr = '\0';
6363 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6364 NULL, ODBC_INSTALL_COMPLETE, &usage))
6366 ERR("Failed to install SQL driver!\n");
6367 r = ERROR_FUNCTION_FAILED;
6370 uirow = MSI_CreateRecord( 5 );
6371 MSI_RecordSetStringW( uirow, 1, desc );
6372 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6373 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6374 msi_ui_actiondata( package, szInstallODBC, uirow );
6375 msiobj_release( &uirow->hdr );
6378 msi_free(driver_path);
6383 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6385 MSIPACKAGE *package = param;
6386 LPWSTR translator, translator_path, ptr;
6387 WCHAR outpath[MAX_PATH];
6388 MSIFILE *translator_file = NULL, *setup_file = NULL;
6391 LPCWSTR desc, file_key, component;
6393 UINT r = ERROR_SUCCESS;
6395 static const WCHAR translator_fmt[] = {
6396 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6397 static const WCHAR setup_fmt[] = {
6398 'S','e','t','u','p','=','%','s',0};
6400 component = MSI_RecordGetString( rec, 2 );
6401 comp = msi_get_loaded_component( package, component );
6403 return ERROR_SUCCESS;
6405 comp->Action = msi_get_component_action( package, comp );
6406 if (comp->Action != INSTALLSTATE_LOCAL)
6408 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6409 return ERROR_SUCCESS;
6411 desc = MSI_RecordGetString(rec, 3);
6413 file_key = MSI_RecordGetString( rec, 4 );
6414 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6416 file_key = MSI_RecordGetString( rec, 5 );
6417 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6419 if (!translator_file)
6421 ERR("ODBC Translator entry not found!\n");
6422 return ERROR_FUNCTION_FAILED;
6425 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6427 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6429 translator = msi_alloc(len * sizeof(WCHAR));
6431 return ERROR_OUTOFMEMORY;
6434 lstrcpyW(ptr, desc);
6435 ptr += lstrlenW(ptr) + 1;
6437 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6442 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6447 translator_path = strdupW(translator_file->TargetPath);
6448 ptr = strrchrW(translator_path, '\\');
6449 if (ptr) *ptr = '\0';
6451 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6452 NULL, ODBC_INSTALL_COMPLETE, &usage))
6454 ERR("Failed to install SQL translator!\n");
6455 r = ERROR_FUNCTION_FAILED;
6458 uirow = MSI_CreateRecord( 5 );
6459 MSI_RecordSetStringW( uirow, 1, desc );
6460 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6461 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6462 msi_ui_actiondata( package, szInstallODBC, uirow );
6463 msiobj_release( &uirow->hdr );
6465 msi_free(translator);
6466 msi_free(translator_path);
6471 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6473 MSIPACKAGE *package = param;
6476 LPCWSTR desc, driver, component;
6477 WORD request = ODBC_ADD_SYS_DSN;
6480 UINT r = ERROR_SUCCESS;
6483 static const WCHAR attrs_fmt[] = {
6484 'D','S','N','=','%','s',0 };
6486 component = MSI_RecordGetString( rec, 2 );
6487 comp = msi_get_loaded_component( package, component );
6489 return ERROR_SUCCESS;
6491 comp->Action = msi_get_component_action( package, comp );
6492 if (comp->Action != INSTALLSTATE_LOCAL)
6494 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6495 return ERROR_SUCCESS;
6498 desc = MSI_RecordGetString(rec, 3);
6499 driver = MSI_RecordGetString(rec, 4);
6500 registration = MSI_RecordGetInteger(rec, 5);
6502 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6503 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6505 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6506 attrs = msi_alloc(len * sizeof(WCHAR));
6508 return ERROR_OUTOFMEMORY;
6510 len = sprintfW(attrs, attrs_fmt, desc);
6513 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6515 ERR("Failed to install SQL data source!\n");
6516 r = ERROR_FUNCTION_FAILED;
6519 uirow = MSI_CreateRecord( 5 );
6520 MSI_RecordSetStringW( uirow, 1, desc );
6521 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6522 MSI_RecordSetInteger( uirow, 3, request );
6523 msi_ui_actiondata( package, szInstallODBC, uirow );
6524 msiobj_release( &uirow->hdr );
6531 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6533 static const WCHAR driver_query[] = {
6534 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6535 'O','D','B','C','D','r','i','v','e','r',0};
6536 static const WCHAR translator_query[] = {
6537 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6538 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6539 static const WCHAR source_query[] = {
6540 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6541 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6545 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6546 if (rc == ERROR_SUCCESS)
6548 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6549 msiobj_release(&view->hdr);
6550 if (rc != ERROR_SUCCESS)
6553 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6554 if (rc == ERROR_SUCCESS)
6556 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6557 msiobj_release(&view->hdr);
6558 if (rc != ERROR_SUCCESS)
6561 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6562 if (rc == ERROR_SUCCESS)
6564 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6565 msiobj_release(&view->hdr);
6566 if (rc != ERROR_SUCCESS)
6569 return ERROR_SUCCESS;
6572 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6574 MSIPACKAGE *package = param;
6578 LPCWSTR desc, component;
6580 component = MSI_RecordGetString( rec, 2 );
6581 comp = msi_get_loaded_component( package, component );
6583 return ERROR_SUCCESS;
6585 comp->Action = msi_get_component_action( package, comp );
6586 if (comp->Action != INSTALLSTATE_ABSENT)
6588 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6589 return ERROR_SUCCESS;
6592 desc = MSI_RecordGetString( rec, 3 );
6593 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6595 WARN("Failed to remove ODBC driver\n");
6599 FIXME("Usage count reached 0\n");
6602 uirow = MSI_CreateRecord( 2 );
6603 MSI_RecordSetStringW( uirow, 1, desc );
6604 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6605 msi_ui_actiondata( package, szRemoveODBC, uirow );
6606 msiobj_release( &uirow->hdr );
6608 return ERROR_SUCCESS;
6611 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6613 MSIPACKAGE *package = param;
6617 LPCWSTR desc, component;
6619 component = MSI_RecordGetString( rec, 2 );
6620 comp = msi_get_loaded_component( package, component );
6622 return ERROR_SUCCESS;
6624 comp->Action = msi_get_component_action( package, comp );
6625 if (comp->Action != INSTALLSTATE_ABSENT)
6627 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6628 return ERROR_SUCCESS;
6631 desc = MSI_RecordGetString( rec, 3 );
6632 if (!SQLRemoveTranslatorW( desc, &usage ))
6634 WARN("Failed to remove ODBC translator\n");
6638 FIXME("Usage count reached 0\n");
6641 uirow = MSI_CreateRecord( 2 );
6642 MSI_RecordSetStringW( uirow, 1, desc );
6643 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6644 msi_ui_actiondata( package, szRemoveODBC, uirow );
6645 msiobj_release( &uirow->hdr );
6647 return ERROR_SUCCESS;
6650 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6652 MSIPACKAGE *package = param;
6656 LPCWSTR desc, driver, component;
6657 WORD request = ODBC_REMOVE_SYS_DSN;
6661 static const WCHAR attrs_fmt[] = {
6662 'D','S','N','=','%','s',0 };
6664 component = MSI_RecordGetString( rec, 2 );
6665 comp = msi_get_loaded_component( package, component );
6667 return ERROR_SUCCESS;
6669 comp->Action = msi_get_component_action( package, comp );
6670 if (comp->Action != INSTALLSTATE_ABSENT)
6672 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6673 return ERROR_SUCCESS;
6676 desc = MSI_RecordGetString( rec, 3 );
6677 driver = MSI_RecordGetString( rec, 4 );
6678 registration = MSI_RecordGetInteger( rec, 5 );
6680 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6681 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6683 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6684 attrs = msi_alloc( len * sizeof(WCHAR) );
6686 return ERROR_OUTOFMEMORY;
6688 FIXME("Use ODBCSourceAttribute table\n");
6690 len = sprintfW( attrs, attrs_fmt, desc );
6693 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6695 WARN("Failed to remove ODBC data source\n");
6699 uirow = MSI_CreateRecord( 3 );
6700 MSI_RecordSetStringW( uirow, 1, desc );
6701 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6702 MSI_RecordSetInteger( uirow, 3, request );
6703 msi_ui_actiondata( package, szRemoveODBC, uirow );
6704 msiobj_release( &uirow->hdr );
6706 return ERROR_SUCCESS;
6709 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6711 static const WCHAR driver_query[] = {
6712 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6713 'O','D','B','C','D','r','i','v','e','r',0};
6714 static const WCHAR translator_query[] = {
6715 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6716 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6717 static const WCHAR source_query[] = {
6718 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6719 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6723 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6724 if (rc == ERROR_SUCCESS)
6726 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6727 msiobj_release( &view->hdr );
6728 if (rc != ERROR_SUCCESS)
6731 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6732 if (rc == ERROR_SUCCESS)
6734 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6735 msiobj_release( &view->hdr );
6736 if (rc != ERROR_SUCCESS)
6739 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6740 if (rc == ERROR_SUCCESS)
6742 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6743 msiobj_release( &view->hdr );
6744 if (rc != ERROR_SUCCESS)
6747 return ERROR_SUCCESS;
6750 #define ENV_ACT_SETALWAYS 0x1
6751 #define ENV_ACT_SETABSENT 0x2
6752 #define ENV_ACT_REMOVE 0x4
6753 #define ENV_ACT_REMOVEMATCH 0x8
6755 #define ENV_MOD_MACHINE 0x20000000
6756 #define ENV_MOD_APPEND 0x40000000
6757 #define ENV_MOD_PREFIX 0x80000000
6758 #define ENV_MOD_MASK 0xC0000000
6760 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6762 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6764 LPCWSTR cptr = *name;
6766 static const WCHAR prefix[] = {'[','~',']',0};
6767 static const int prefix_len = 3;
6773 *flags |= ENV_ACT_SETALWAYS;
6774 else if (*cptr == '+')
6775 *flags |= ENV_ACT_SETABSENT;
6776 else if (*cptr == '-')
6777 *flags |= ENV_ACT_REMOVE;
6778 else if (*cptr == '!')
6779 *flags |= ENV_ACT_REMOVEMATCH;
6780 else if (*cptr == '*')
6781 *flags |= ENV_MOD_MACHINE;
6791 ERR("Missing environment variable\n");
6792 return ERROR_FUNCTION_FAILED;
6797 LPCWSTR ptr = *value;
6798 if (!strncmpW(ptr, prefix, prefix_len))
6800 if (ptr[prefix_len] == szSemiColon[0])
6802 *flags |= ENV_MOD_APPEND;
6803 *value += lstrlenW(prefix);
6810 else if (lstrlenW(*value) >= prefix_len)
6812 ptr += lstrlenW(ptr) - prefix_len;
6813 if (!strcmpW( ptr, prefix ))
6815 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6817 *flags |= ENV_MOD_PREFIX;
6818 /* the "[~]" will be removed by deformat_string */;
6828 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6829 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6830 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6831 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6833 ERR("Invalid flags: %08x\n", *flags);
6834 return ERROR_FUNCTION_FAILED;
6838 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6840 return ERROR_SUCCESS;
6843 static UINT open_env_key( DWORD flags, HKEY *key )
6845 static const WCHAR user_env[] =
6846 {'E','n','v','i','r','o','n','m','e','n','t',0};
6847 static const WCHAR machine_env[] =
6848 {'S','y','s','t','e','m','\\',
6849 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6850 'C','o','n','t','r','o','l','\\',
6851 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6852 'E','n','v','i','r','o','n','m','e','n','t',0};
6857 if (flags & ENV_MOD_MACHINE)
6860 root = HKEY_LOCAL_MACHINE;
6865 root = HKEY_CURRENT_USER;
6868 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6869 if (res != ERROR_SUCCESS)
6871 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6872 return ERROR_FUNCTION_FAILED;
6875 return ERROR_SUCCESS;
6878 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6880 MSIPACKAGE *package = param;
6881 LPCWSTR name, value, component;
6882 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6883 DWORD flags, type, size;
6890 component = MSI_RecordGetString(rec, 4);
6891 comp = msi_get_loaded_component(package, component);
6893 return ERROR_SUCCESS;
6895 comp->Action = msi_get_component_action( package, comp );
6896 if (comp->Action != INSTALLSTATE_LOCAL)
6898 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6899 return ERROR_SUCCESS;
6901 name = MSI_RecordGetString(rec, 2);
6902 value = MSI_RecordGetString(rec, 3);
6904 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6906 res = env_parse_flags(&name, &value, &flags);
6907 if (res != ERROR_SUCCESS || !value)
6910 if (value && !deformat_string(package, value, &deformatted))
6912 res = ERROR_OUTOFMEMORY;
6916 value = deformatted;
6918 res = open_env_key( flags, &env );
6919 if (res != ERROR_SUCCESS)
6922 if (flags & ENV_MOD_MACHINE)
6923 action |= 0x20000000;
6927 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6928 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6929 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6932 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6936 /* Nothing to do. */
6939 res = ERROR_SUCCESS;
6943 /* If we are appending but the string was empty, strip ; */
6944 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6946 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6947 newval = strdupW(value);
6950 res = ERROR_OUTOFMEMORY;
6958 /* Contrary to MSDN, +-variable to [~];path works */
6959 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6961 res = ERROR_SUCCESS;
6965 data = msi_alloc(size);
6969 return ERROR_OUTOFMEMORY;
6972 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6973 if (res != ERROR_SUCCESS)
6976 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6979 res = RegDeleteValueW(env, name);
6980 if (res != ERROR_SUCCESS)
6981 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6985 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6986 if (flags & ENV_MOD_MASK)
6990 if (flags & ENV_MOD_APPEND) multiplier++;
6991 if (flags & ENV_MOD_PREFIX) multiplier++;
6992 mod_size = lstrlenW(value) * multiplier;
6993 size += mod_size * sizeof(WCHAR);
6996 newval = msi_alloc(size);
7000 res = ERROR_OUTOFMEMORY;
7004 if (flags & ENV_MOD_PREFIX)
7006 lstrcpyW(newval, value);
7007 ptr = newval + lstrlenW(value);
7008 action |= 0x80000000;
7011 lstrcpyW(ptr, data);
7013 if (flags & ENV_MOD_APPEND)
7015 lstrcatW(newval, value);
7016 action |= 0x40000000;
7019 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
7020 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
7023 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7027 uirow = MSI_CreateRecord( 3 );
7028 MSI_RecordSetStringW( uirow, 1, name );
7029 MSI_RecordSetStringW( uirow, 2, newval );
7030 MSI_RecordSetInteger( uirow, 3, action );
7031 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
7032 msiobj_release( &uirow->hdr );
7034 if (env) RegCloseKey(env);
7035 msi_free(deformatted);
7041 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7043 static const WCHAR query[] = {
7044 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7045 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7049 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
7050 if (rc != ERROR_SUCCESS)
7051 return ERROR_SUCCESS;
7053 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7054 msiobj_release(&view->hdr);
7058 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7060 MSIPACKAGE *package = param;
7061 LPCWSTR name, value, component;
7062 LPWSTR deformatted = NULL;
7071 component = MSI_RecordGetString( rec, 4 );
7072 comp = msi_get_loaded_component( package, component );
7074 return ERROR_SUCCESS;
7076 comp->Action = msi_get_component_action( package, comp );
7077 if (comp->Action != INSTALLSTATE_ABSENT)
7079 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
7080 return ERROR_SUCCESS;
7082 name = MSI_RecordGetString( rec, 2 );
7083 value = MSI_RecordGetString( rec, 3 );
7085 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7087 r = env_parse_flags( &name, &value, &flags );
7088 if (r != ERROR_SUCCESS)
7091 if (!(flags & ENV_ACT_REMOVE))
7093 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7094 return ERROR_SUCCESS;
7097 if (value && !deformat_string( package, value, &deformatted ))
7098 return ERROR_OUTOFMEMORY;
7100 value = deformatted;
7102 r = open_env_key( flags, &env );
7103 if (r != ERROR_SUCCESS)
7109 if (flags & ENV_MOD_MACHINE)
7110 action |= 0x20000000;
7112 TRACE("Removing %s\n", debugstr_w(name));
7114 res = RegDeleteValueW( env, name );
7115 if (res != ERROR_SUCCESS)
7117 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
7122 uirow = MSI_CreateRecord( 3 );
7123 MSI_RecordSetStringW( uirow, 1, name );
7124 MSI_RecordSetStringW( uirow, 2, value );
7125 MSI_RecordSetInteger( uirow, 3, action );
7126 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
7127 msiobj_release( &uirow->hdr );
7129 if (env) RegCloseKey( env );
7130 msi_free( deformatted );
7134 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7136 static const WCHAR query[] = {
7137 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7138 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7142 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
7143 if (rc != ERROR_SUCCESS)
7144 return ERROR_SUCCESS;
7146 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7147 msiobj_release( &view->hdr );
7151 UINT msi_validate_product_id( MSIPACKAGE *package )
7153 LPWSTR key, template, id;
7154 UINT r = ERROR_SUCCESS;
7156 id = msi_dup_property( package->db, szProductID );
7160 return ERROR_SUCCESS;
7162 template = msi_dup_property( package->db, szPIDTemplate );
7163 key = msi_dup_property( package->db, szPIDKEY );
7164 if (key && template)
7166 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7167 r = msi_set_property( package->db, szProductID, key, -1 );
7169 msi_free( template );
7174 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7176 return msi_validate_product_id( package );
7179 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7182 package->need_reboot_at_end = 1;
7183 return ERROR_SUCCESS;
7186 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7188 static const WCHAR szAvailableFreeReg[] =
7189 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7191 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7193 TRACE("%p %d kilobytes\n", package, space);
7195 uirow = MSI_CreateRecord( 1 );
7196 MSI_RecordSetInteger( uirow, 1, space );
7197 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
7198 msiobj_release( &uirow->hdr );
7200 return ERROR_SUCCESS;
7203 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7205 TRACE("%p\n", package);
7207 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7208 return ERROR_SUCCESS;
7211 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7213 FIXME("%p\n", package);
7214 return ERROR_SUCCESS;
7217 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7219 static const WCHAR driver_query[] = {
7220 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7221 'O','D','B','C','D','r','i','v','e','r',0};
7222 static const WCHAR translator_query[] = {
7223 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7224 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
7228 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7229 if (r == ERROR_SUCCESS)
7232 r = MSI_IterateRecords( view, &count, NULL, package );
7233 msiobj_release( &view->hdr );
7234 if (r != ERROR_SUCCESS)
7236 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7238 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7239 if (r == ERROR_SUCCESS)
7242 r = MSI_IterateRecords( view, &count, NULL, package );
7243 msiobj_release( &view->hdr );
7244 if (r != ERROR_SUCCESS)
7246 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7248 return ERROR_SUCCESS;
7251 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7253 static const WCHAR fmtW[] =
7254 {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0};
7255 MSIPACKAGE *package = param;
7256 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7257 UINT len = sizeof(fmtW)/sizeof(fmtW[0]);
7258 WCHAR *product, *features, *cmd;
7260 PROCESS_INFORMATION info;
7263 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7265 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7267 len += strlenW( product );
7269 len += strlenW( features );
7271 len += sizeof(szAll) / sizeof(szAll[0]);
7273 if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
7275 msi_free( product );
7276 msi_free( features );
7277 return ERROR_OUTOFMEMORY;
7279 sprintfW( cmd, fmtW, product, features ? features : szAll );
7280 msi_free( product );
7281 msi_free( features );
7283 memset( &si, 0, sizeof(STARTUPINFOW) );
7284 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7286 if (!ret) return GetLastError();
7287 CloseHandle( info.hThread );
7289 WaitForSingleObject( info.hProcess, INFINITE );
7290 CloseHandle( info.hProcess );
7291 return ERROR_SUCCESS;
7294 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7296 static const WCHAR query[] = {
7297 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7301 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7302 if (r == ERROR_SUCCESS)
7304 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7305 msiobj_release( &view->hdr );
7306 if (r != ERROR_SUCCESS)
7309 return ERROR_SUCCESS;
7312 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7314 MSIPACKAGE *package = param;
7315 int attributes = MSI_RecordGetInteger( rec, 5 );
7317 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7319 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7320 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7321 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7322 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7326 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7328 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7329 if (r != ERROR_SUCCESS)
7330 return ERROR_SUCCESS;
7334 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7335 if (r != ERROR_SUCCESS)
7336 return ERROR_SUCCESS;
7338 RegCloseKey( hkey );
7340 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7341 debugstr_w(upgrade_code), debugstr_w(version_min),
7342 debugstr_w(version_max), debugstr_w(language));
7344 return ERROR_SUCCESS;
7347 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7349 static const WCHAR query[] = {
7350 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7351 'U','p','g','r','a','d','e',0};
7355 if (msi_get_property_int( package->db, szInstalled, 0 ))
7357 TRACE("product is installed, skipping action\n");
7358 return ERROR_SUCCESS;
7360 if (msi_get_property_int( package->db, szPreselected, 0 ))
7362 TRACE("Preselected property is set, not migrating feature states\n");
7363 return ERROR_SUCCESS;
7365 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7366 if (r == ERROR_SUCCESS)
7368 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7369 msiobj_release( &view->hdr );
7370 if (r != ERROR_SUCCESS)
7373 return ERROR_SUCCESS;
7376 static void bind_image( const char *filename, const char *path )
7378 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7380 WARN("failed to bind image %u\n", GetLastError());
7384 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7388 MSIPACKAGE *package = param;
7389 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7390 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7391 char *filenameA, *pathA;
7392 WCHAR *pathW, **path_list;
7394 if (!(file = msi_get_loaded_file( package, key )))
7396 WARN("file %s not found\n", debugstr_w(key));
7397 return ERROR_SUCCESS;
7399 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7400 path_list = msi_split_string( paths, ';' );
7401 if (!path_list) bind_image( filenameA, NULL );
7404 for (i = 0; path_list[i] && path_list[i][0]; i++)
7406 deformat_string( package, path_list[i], &pathW );
7407 if ((pathA = strdupWtoA( pathW )))
7409 bind_image( filenameA, pathA );
7415 msi_free( path_list );
7416 msi_free( filenameA );
7417 return ERROR_SUCCESS;
7420 static UINT ACTION_BindImage( MSIPACKAGE *package )
7422 static const WCHAR query[] = {
7423 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7424 'B','i','n','d','I','m','a','g','e',0};
7428 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7429 if (r == ERROR_SUCCESS)
7431 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7432 msiobj_release( &view->hdr );
7433 if (r != ERROR_SUCCESS)
7436 return ERROR_SUCCESS;
7439 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7441 static const WCHAR query[] = {
7442 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7447 r = MSI_OpenQuery( package->db, &view, query, table );
7448 if (r == ERROR_SUCCESS)
7450 r = MSI_IterateRecords(view, &count, NULL, package);
7451 msiobj_release(&view->hdr);
7452 if (r != ERROR_SUCCESS)
7455 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7456 return ERROR_SUCCESS;
7459 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7461 static const WCHAR table[] = {
7462 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7463 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7466 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7468 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7469 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7472 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7474 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7475 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7478 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7480 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7481 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7484 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7486 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7487 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7492 const WCHAR *action;
7493 UINT (*handler)(MSIPACKAGE *);
7494 const WCHAR *action_rollback;
7498 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7499 { szAppSearch, ACTION_AppSearch, NULL },
7500 { szBindImage, ACTION_BindImage, NULL },
7501 { szCCPSearch, ACTION_CCPSearch, NULL },
7502 { szCostFinalize, ACTION_CostFinalize, NULL },
7503 { szCostInitialize, ACTION_CostInitialize, NULL },
7504 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7505 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7506 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7507 { szDisableRollback, ACTION_DisableRollback, NULL },
7508 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7509 { szExecuteAction, ACTION_ExecuteAction, NULL },
7510 { szFileCost, ACTION_FileCost, NULL },
7511 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7512 { szForceReboot, ACTION_ForceReboot, NULL },
7513 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7514 { szInstallExecute, ACTION_InstallExecute, NULL },
7515 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7516 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7517 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7518 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7519 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7520 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7521 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7522 { szInstallValidate, ACTION_InstallValidate, NULL },
7523 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7524 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7525 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7526 { szMoveFiles, ACTION_MoveFiles, NULL },
7527 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7528 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7529 { szPatchFiles, ACTION_PatchFiles, NULL },
7530 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7531 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7532 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7533 { szPublishProduct, ACTION_PublishProduct, NULL },
7534 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7535 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7536 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7537 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7538 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7539 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7540 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7541 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7542 { szRegisterUser, ACTION_RegisterUser, NULL },
7543 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7544 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7545 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7546 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7547 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7548 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7549 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7550 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7551 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7552 { szResolveSource, ACTION_ResolveSource, NULL },
7553 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7554 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7555 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7556 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7557 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7558 { szStartServices, ACTION_StartServices, szStopServices },
7559 { szStopServices, ACTION_StopServices, szStartServices },
7560 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7561 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7562 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7563 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7564 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7565 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7566 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7567 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7568 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7569 { szValidateProductID, ACTION_ValidateProductID, NULL },
7570 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7571 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7572 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7573 { NULL, NULL, NULL }
7576 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7582 while (StandardActions[i].action != NULL)
7584 if (!strcmpW( StandardActions[i].action, action ))
7586 ui_actionstart( package, action );
7587 if (StandardActions[i].handler)
7589 ui_actioninfo( package, action, TRUE, 0 );
7590 *rc = StandardActions[i].handler( package );
7591 ui_actioninfo( package, action, FALSE, *rc );
7593 if (StandardActions[i].action_rollback && !package->need_rollback)
7595 TRACE("scheduling rollback action\n");
7596 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7601 FIXME("unhandled standard action %s\n", debugstr_w(action));
7602 *rc = ERROR_SUCCESS;
7612 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7614 UINT rc = ERROR_SUCCESS;
7617 TRACE("Performing action (%s)\n", debugstr_w(action));
7619 handled = ACTION_HandleStandardAction(package, action, &rc);
7622 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7626 WARN("unhandled msi action %s\n", debugstr_w(action));
7627 rc = ERROR_FUNCTION_NOT_CALLED;
7633 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7635 UINT rc = ERROR_SUCCESS;
7636 BOOL handled = FALSE;
7638 TRACE("Performing action (%s)\n", debugstr_w(action));
7640 package->action_progress_increment = 0;
7641 handled = ACTION_HandleStandardAction(package, action, &rc);
7644 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7646 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7651 WARN("unhandled msi action %s\n", debugstr_w(action));
7652 rc = ERROR_FUNCTION_NOT_CALLED;
7658 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7660 UINT rc = ERROR_SUCCESS;
7663 static const WCHAR query[] =
7664 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7665 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7666 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7667 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7668 static const WCHAR ui_query[] =
7669 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7670 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7671 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7672 ' ', '=',' ','%','i',0};
7674 if (needs_ui_sequence(package))
7675 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7677 row = MSI_QueryGetRecord(package->db, query, seq);
7681 LPCWSTR action, cond;
7683 TRACE("Running the actions\n");
7685 /* check conditions */
7686 cond = MSI_RecordGetString(row, 2);
7688 /* this is a hack to skip errors in the condition code */
7689 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7691 msiobj_release(&row->hdr);
7692 return ERROR_SUCCESS;
7695 action = MSI_RecordGetString(row, 1);
7698 ERR("failed to fetch action\n");
7699 msiobj_release(&row->hdr);
7700 return ERROR_FUNCTION_FAILED;
7703 if (needs_ui_sequence(package))
7704 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7706 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7708 msiobj_release(&row->hdr);
7714 /****************************************************
7715 * TOP level entry points
7716 *****************************************************/
7718 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7719 LPCWSTR szCommandLine )
7721 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7722 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7723 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7724 WCHAR *reinstall = NULL;
7728 msi_set_property( package->db, szAction, szInstall, -1 );
7730 package->script->InWhatSequence = SEQUENCE_INSTALL;
7737 dir = strdupW(szPackagePath);
7738 p = strrchrW(dir, '\\');
7742 file = szPackagePath + (p - dir);
7747 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7748 GetCurrentDirectoryW(MAX_PATH, dir);
7749 lstrcatW(dir, szBackSlash);
7750 file = szPackagePath;
7753 msi_free( package->PackagePath );
7754 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7755 if (!package->PackagePath)
7758 return ERROR_OUTOFMEMORY;
7761 lstrcpyW(package->PackagePath, dir);
7762 lstrcatW(package->PackagePath, file);
7765 msi_set_sourcedir_props(package, FALSE);
7768 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7769 if (rc != ERROR_SUCCESS)
7772 msi_apply_transforms( package );
7773 msi_apply_patches( package );
7775 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7777 TRACE("setting reinstall property\n");
7778 msi_set_property( package->db, szReinstall, szAll, -1 );
7781 /* properties may have been added by a transform */
7782 msi_clone_properties( package );
7784 msi_parse_command_line( package, szCommandLine, FALSE );
7785 msi_adjust_privilege_properties( package );
7786 msi_set_context( package );
7788 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7790 TRACE("disabling rollback\n");
7791 msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
7794 if (needs_ui_sequence( package))
7796 package->script->InWhatSequence |= SEQUENCE_UI;
7797 rc = ACTION_ProcessUISequence(package);
7798 ui_exists = ui_sequence_exists(package);
7799 if (rc == ERROR_SUCCESS || !ui_exists)
7801 package->script->InWhatSequence |= SEQUENCE_EXEC;
7802 rc = ACTION_ProcessExecSequence(package, ui_exists);
7806 rc = ACTION_ProcessExecSequence(package, FALSE);
7808 package->script->CurrentlyScripting = FALSE;
7810 /* process the ending type action */
7811 if (rc == ERROR_SUCCESS)
7812 ACTION_PerformActionSequence(package, -1);
7813 else if (rc == ERROR_INSTALL_USEREXIT)
7814 ACTION_PerformActionSequence(package, -2);
7815 else if (rc == ERROR_INSTALL_SUSPEND)
7816 ACTION_PerformActionSequence(package, -4);
7819 ACTION_PerformActionSequence(package, -3);
7820 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7822 package->need_rollback = TRUE;
7826 /* finish up running custom actions */
7827 ACTION_FinishCustomActions(package);
7829 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7831 WARN("installation failed, running rollback script\n");
7832 execute_script( package, SCRIPT_ROLLBACK );
7834 msi_free( reinstall );
7836 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7837 return ERROR_SUCCESS_REBOOT_REQUIRED;