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:
225 if (!count) goto done;
232 if (in_quotes && p[1] != '\"') count--;
237 if (!count) in_quotes = 0;
249 if (in_quotes) count--;
253 state = state_whitespace;
254 if (!count) goto done;
259 if (!count) in_quotes = 0;
270 if (in_quotes && p[1] != '\"') count--;
274 state = state_whitespace;
275 if (!count || (count > 1 && !len)) goto done;
281 if (!count) in_quotes = 0;
290 if (!ignore) *out++ = *p;
294 if (!len) *value = 0;
301 static void remove_quotes( WCHAR *str )
304 int len = strlenW( str );
306 while ((p = strchrW( p, '"' )))
308 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
313 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
323 return ERROR_SUCCESS;
328 while (*ptr == ' ') ptr++;
331 ptr2 = strchrW( ptr, '=' );
332 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
335 if (!len) return ERROR_INVALID_COMMAND_LINE;
337 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
338 memcpy( prop, ptr, len * sizeof(WCHAR) );
340 if (!preserve_case) struprW( prop );
343 while (*ptr2 == ' ') ptr2++;
346 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
347 len = parse_prop( ptr2, val, &num_quotes );
350 WARN("unbalanced quotes\n");
353 return ERROR_INVALID_COMMAND_LINE;
355 remove_quotes( val );
356 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
358 r = msi_set_property( package->db, prop, val );
359 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
360 msi_reset_folders( package, TRUE );
368 return ERROR_SUCCESS;
371 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
374 LPWSTR p, *ret = NULL;
380 /* count the number of substrings */
381 for ( pc = str, count = 0; pc; count++ )
383 pc = strchrW( pc, sep );
388 /* allocate space for an array of substring pointers and the substrings */
389 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
390 (lstrlenW(str)+1) * sizeof(WCHAR) );
394 /* copy the string and set the pointers */
395 p = (LPWSTR) &ret[count+1];
397 for( count = 0; (ret[count] = p); count++ )
399 p = strchrW( p, sep );
407 static BOOL ui_sequence_exists( MSIPACKAGE *package )
409 static const WCHAR query [] = {
410 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
411 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
412 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
413 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
417 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
418 if (rc == ERROR_SUCCESS)
420 msiobj_release(&view->hdr);
426 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
428 LPWSTR source, check;
430 if (msi_get_property_int( package->db, szInstalled, 0 ))
434 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
435 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
443 db = msi_dup_property( package->db, szOriginalDatabase );
445 return ERROR_OUTOFMEMORY;
447 p = strrchrW( db, '\\' );
450 p = strrchrW( db, '/' );
454 return ERROR_SUCCESS;
459 source = msi_alloc( len * sizeof(WCHAR) );
460 lstrcpynW( source, db, len );
464 check = msi_dup_property( package->db, szSourceDir );
465 if (!check || replace)
467 UINT r = msi_set_property( package->db, szSourceDir, source );
468 if (r == ERROR_SUCCESS)
469 msi_reset_folders( package, TRUE );
473 check = msi_dup_property( package->db, szSOURCEDIR );
474 if (!check || replace)
475 msi_set_property( package->db, szSOURCEDIR, source );
480 return ERROR_SUCCESS;
483 static BOOL needs_ui_sequence(MSIPACKAGE *package)
485 INT level = msi_get_property_int(package->db, szUILevel, 0);
486 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
489 UINT msi_set_context(MSIPACKAGE *package)
493 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
495 num = msi_get_property_int(package->db, szAllUsers, 0);
496 if (num == 1 || num == 2)
497 package->Context = MSIINSTALLCONTEXT_MACHINE;
499 return ERROR_SUCCESS;
502 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
505 LPCWSTR cond, action;
506 MSIPACKAGE *package = param;
508 action = MSI_RecordGetString(row,1);
511 ERR("Error is retrieving action name\n");
512 return ERROR_FUNCTION_FAILED;
515 /* check conditions */
516 cond = MSI_RecordGetString(row,2);
518 /* this is a hack to skip errors in the condition code */
519 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
521 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
522 return ERROR_SUCCESS;
525 if (needs_ui_sequence(package))
526 rc = ACTION_PerformUIAction(package, action, -1);
528 rc = ACTION_PerformAction(package, action, -1);
530 msi_dialog_check_messages( NULL );
532 if (package->CurrentInstallState != ERROR_SUCCESS)
533 rc = package->CurrentInstallState;
535 if (rc == ERROR_FUNCTION_NOT_CALLED)
538 if (rc != ERROR_SUCCESS)
539 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
544 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
546 static const WCHAR query[] = {
547 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
548 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
549 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
550 '`','S','e','q','u','e','n','c','e','`',0};
554 TRACE("%p %s\n", package, debugstr_w(table));
556 r = MSI_OpenQuery( package->db, &view, query, table );
557 if (r == ERROR_SUCCESS)
559 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
560 msiobj_release(&view->hdr);
565 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
567 static const WCHAR query[] = {
568 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
569 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
570 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
571 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
572 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
573 static const WCHAR query_validate[] = {
574 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
575 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
576 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
577 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
578 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
583 if (package->script->ExecuteSequenceRun)
585 TRACE("Execute Sequence already Run\n");
586 return ERROR_SUCCESS;
589 package->script->ExecuteSequenceRun = TRUE;
591 /* get the sequence number */
594 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
595 if (!row) return ERROR_FUNCTION_FAILED;
596 seq = MSI_RecordGetInteger(row,1);
597 msiobj_release(&row->hdr);
599 rc = MSI_OpenQuery(package->db, &view, query, seq);
600 if (rc == ERROR_SUCCESS)
602 TRACE("Running the actions\n");
604 msi_set_property(package->db, szSourceDir, NULL);
605 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
606 msiobj_release(&view->hdr);
611 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
613 static const WCHAR query[] = {
614 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
615 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
616 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
617 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
621 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
622 if (rc == ERROR_SUCCESS)
624 TRACE("Running the actions\n");
625 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
626 msiobj_release(&view->hdr);
631 /********************************************************
632 * ACTION helper functions and functions that perform the actions
633 *******************************************************/
634 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
635 UINT* rc, UINT script, BOOL force )
640 arc = ACTION_CustomAction(package, action, script, force);
642 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
650 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
654 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
656 if (!strcmpW( Component, comp->Component )) return comp;
661 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
665 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
667 if (!strcmpW( Feature, feature->Feature )) return feature;
672 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
676 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
678 if (!strcmpW( key, file->File )) return file;
683 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
687 /* FIXME: There might be more than one patch */
688 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
690 if (!strcmpW( key, patch->File->File )) return patch;
695 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
699 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
701 if (!strcmpW( dir, folder->Directory )) return folder;
707 * Recursively create all directories in the path.
708 * shamelessly stolen from setupapi/queue.c
710 BOOL msi_create_full_path( const WCHAR *path )
716 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
717 strcpyW( new_path, path );
719 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
720 new_path[len - 1] = 0;
722 while (!CreateDirectoryW( new_path, NULL ))
725 DWORD last_error = GetLastError();
726 if (last_error == ERROR_ALREADY_EXISTS) break;
727 if (last_error != ERROR_PATH_NOT_FOUND)
732 if (!(slash = strrchrW( new_path, '\\' )))
737 len = slash - new_path;
739 if (!msi_create_full_path( new_path ))
744 new_path[len] = '\\';
746 msi_free( new_path );
750 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
754 row = MSI_CreateRecord( 4 );
755 MSI_RecordSetInteger( row, 1, a );
756 MSI_RecordSetInteger( row, 2, b );
757 MSI_RecordSetInteger( row, 3, c );
758 MSI_RecordSetInteger( row, 4, d );
759 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
760 msiobj_release( &row->hdr );
762 msi_dialog_check_messages( NULL );
765 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
767 static const WCHAR query[] =
768 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
769 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
770 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
775 if (!package->LastAction || strcmpW( package->LastAction, action ))
777 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
779 if (MSI_RecordIsNull( row, 3 ))
781 msiobj_release( &row->hdr );
784 /* update the cached action format */
785 msi_free( package->ActionFormat );
786 package->ActionFormat = msi_dup_record_field( row, 3 );
787 msi_free( package->LastAction );
788 package->LastAction = strdupW( action );
789 msiobj_release( &row->hdr );
792 MSI_RecordSetStringW( record, 0, package->ActionFormat );
793 MSI_FormatRecordW( package, record, message, &size );
794 row = MSI_CreateRecord( 1 );
795 MSI_RecordSetStringW( row, 1, message );
796 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
797 msiobj_release( &row->hdr );
800 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
804 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
805 return INSTALLSTATE_UNKNOWN;
807 if (package->need_rollback) return comp->Installed;
808 return comp->ActionRequest;
811 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
813 if (package->need_rollback) return feature->Installed;
814 return feature->ActionRequest;
817 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
819 MSIPACKAGE *package = param;
820 LPCWSTR dir, component, full_path;
825 component = MSI_RecordGetString(row, 2);
827 return ERROR_SUCCESS;
829 comp = msi_get_loaded_component(package, component);
831 return ERROR_SUCCESS;
833 comp->Action = msi_get_component_action( package, comp );
834 if (comp->Action != INSTALLSTATE_LOCAL)
836 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
837 return ERROR_SUCCESS;
840 dir = MSI_RecordGetString(row,1);
843 ERR("Unable to get folder id\n");
844 return ERROR_SUCCESS;
847 uirow = MSI_CreateRecord(1);
848 MSI_RecordSetStringW(uirow, 1, dir);
849 msi_ui_actiondata(package, szCreateFolders, uirow);
850 msiobj_release(&uirow->hdr);
852 full_path = msi_get_target_folder( package, dir );
855 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
856 return ERROR_SUCCESS;
858 TRACE("folder is %s\n", debugstr_w(full_path));
860 folder = msi_get_loaded_folder( package, dir );
861 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
862 folder->State = FOLDER_STATE_CREATED;
863 return ERROR_SUCCESS;
866 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
868 static const WCHAR query[] = {
869 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
870 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
874 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
875 if (rc != ERROR_SUCCESS)
876 return ERROR_SUCCESS;
878 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
879 msiobj_release(&view->hdr);
883 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
885 MSIPACKAGE *package = param;
886 LPCWSTR dir, component, full_path;
891 component = MSI_RecordGetString(row, 2);
893 return ERROR_SUCCESS;
895 comp = msi_get_loaded_component(package, component);
897 return ERROR_SUCCESS;
899 comp->Action = msi_get_component_action( package, comp );
900 if (comp->Action != INSTALLSTATE_ABSENT)
902 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
903 return ERROR_SUCCESS;
906 dir = MSI_RecordGetString( row, 1 );
909 ERR("Unable to get folder id\n");
910 return ERROR_SUCCESS;
913 full_path = msi_get_target_folder( package, dir );
916 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
917 return ERROR_SUCCESS;
919 TRACE("folder is %s\n", debugstr_w(full_path));
921 uirow = MSI_CreateRecord( 1 );
922 MSI_RecordSetStringW( uirow, 1, dir );
923 msi_ui_actiondata( package, szRemoveFolders, uirow );
924 msiobj_release( &uirow->hdr );
926 RemoveDirectoryW( full_path );
927 folder = msi_get_loaded_folder( package, dir );
928 folder->State = FOLDER_STATE_REMOVED;
929 return ERROR_SUCCESS;
932 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
934 static const WCHAR query[] = {
935 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
936 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
940 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
941 if (rc != ERROR_SUCCESS)
942 return ERROR_SUCCESS;
944 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
945 msiobj_release( &view->hdr );
949 static UINT load_component( MSIRECORD *row, LPVOID param )
951 MSIPACKAGE *package = param;
954 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
956 return ERROR_FUNCTION_FAILED;
958 list_add_tail( &package->components, &comp->entry );
960 /* fill in the data */
961 comp->Component = msi_dup_record_field( row, 1 );
963 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
965 comp->ComponentId = msi_dup_record_field( row, 2 );
966 comp->Directory = msi_dup_record_field( row, 3 );
967 comp->Attributes = MSI_RecordGetInteger(row,4);
968 comp->Condition = msi_dup_record_field( row, 5 );
969 comp->KeyPath = msi_dup_record_field( row, 6 );
971 comp->Installed = INSTALLSTATE_UNKNOWN;
972 comp->Action = INSTALLSTATE_UNKNOWN;
973 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
975 comp->assembly = msi_load_assembly( package, comp );
976 return ERROR_SUCCESS;
979 UINT msi_load_all_components( MSIPACKAGE *package )
981 static const WCHAR query[] = {
982 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
983 '`','C','o','m','p','o','n','e','n','t','`',0};
987 if (!list_empty(&package->components))
988 return ERROR_SUCCESS;
990 r = MSI_DatabaseOpenViewW( package->db, query, &view );
991 if (r != ERROR_SUCCESS)
994 if (!msi_init_assembly_caches( package ))
996 ERR("can't initialize assembly caches\n");
997 msiobj_release( &view->hdr );
998 return ERROR_FUNCTION_FAILED;
1001 r = MSI_IterateRecords(view, NULL, load_component, package);
1002 msiobj_release(&view->hdr);
1003 msi_destroy_assembly_caches( package );
1008 MSIPACKAGE *package;
1009 MSIFEATURE *feature;
1012 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1016 cl = msi_alloc( sizeof (*cl) );
1018 return ERROR_NOT_ENOUGH_MEMORY;
1019 cl->component = comp;
1020 list_add_tail( &feature->Components, &cl->entry );
1022 return ERROR_SUCCESS;
1025 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1029 fl = msi_alloc( sizeof(*fl) );
1031 return ERROR_NOT_ENOUGH_MEMORY;
1032 fl->feature = child;
1033 list_add_tail( &parent->Children, &fl->entry );
1035 return ERROR_SUCCESS;
1038 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1040 _ilfs* ilfs = param;
1044 component = MSI_RecordGetString(row,1);
1046 /* check to see if the component is already loaded */
1047 comp = msi_get_loaded_component( ilfs->package, component );
1050 ERR("unknown component %s\n", debugstr_w(component));
1051 return ERROR_FUNCTION_FAILED;
1054 add_feature_component( ilfs->feature, comp );
1055 comp->Enabled = TRUE;
1057 return ERROR_SUCCESS;
1060 static UINT load_feature(MSIRECORD * row, LPVOID param)
1062 static const WCHAR query[] = {
1063 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1064 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1065 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1066 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1067 MSIPACKAGE *package = param;
1068 MSIFEATURE *feature;
1073 /* fill in the data */
1075 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1077 return ERROR_NOT_ENOUGH_MEMORY;
1079 list_init( &feature->Children );
1080 list_init( &feature->Components );
1082 feature->Feature = msi_dup_record_field( row, 1 );
1084 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1086 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1087 feature->Title = msi_dup_record_field( row, 3 );
1088 feature->Description = msi_dup_record_field( row, 4 );
1090 if (!MSI_RecordIsNull(row,5))
1091 feature->Display = MSI_RecordGetInteger(row,5);
1093 feature->Level= MSI_RecordGetInteger(row,6);
1094 feature->Directory = msi_dup_record_field( row, 7 );
1095 feature->Attributes = MSI_RecordGetInteger(row,8);
1097 feature->Installed = INSTALLSTATE_UNKNOWN;
1098 feature->Action = INSTALLSTATE_UNKNOWN;
1099 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1101 list_add_tail( &package->features, &feature->entry );
1103 /* load feature components */
1105 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1106 if (rc != ERROR_SUCCESS)
1107 return ERROR_SUCCESS;
1109 ilfs.package = package;
1110 ilfs.feature = feature;
1112 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1113 msiobj_release(&view->hdr);
1117 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1119 MSIPACKAGE *package = param;
1120 MSIFEATURE *parent, *child;
1122 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1124 return ERROR_FUNCTION_FAILED;
1126 if (!child->Feature_Parent)
1127 return ERROR_SUCCESS;
1129 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1131 return ERROR_FUNCTION_FAILED;
1133 add_feature_child( parent, child );
1134 return ERROR_SUCCESS;
1137 UINT msi_load_all_features( MSIPACKAGE *package )
1139 static const WCHAR query[] = {
1140 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1141 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1142 '`','D','i','s','p','l','a','y','`',0};
1146 if (!list_empty(&package->features))
1147 return ERROR_SUCCESS;
1149 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1150 if (r != ERROR_SUCCESS)
1153 r = MSI_IterateRecords( view, NULL, load_feature, package );
1154 if (r != ERROR_SUCCESS)
1156 msiobj_release( &view->hdr );
1159 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1160 msiobj_release( &view->hdr );
1164 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1175 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1177 static const WCHAR query[] = {
1178 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1179 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1180 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1181 MSIQUERY *view = NULL;
1182 MSIRECORD *row = NULL;
1185 TRACE("%s\n", debugstr_w(file->File));
1187 r = MSI_OpenQuery(package->db, &view, query, file->File);
1188 if (r != ERROR_SUCCESS)
1191 r = MSI_ViewExecute(view, NULL);
1192 if (r != ERROR_SUCCESS)
1195 r = MSI_ViewFetch(view, &row);
1196 if (r != ERROR_SUCCESS)
1199 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1200 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1201 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1202 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1203 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1206 if (view) msiobj_release(&view->hdr);
1207 if (row) msiobj_release(&row->hdr);
1211 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1214 static const WCHAR query[] = {
1215 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1216 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1217 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1219 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1222 WARN("query failed\n");
1223 return ERROR_FUNCTION_FAILED;
1226 file->disk_id = MSI_RecordGetInteger( row, 1 );
1227 msiobj_release( &row->hdr );
1228 return ERROR_SUCCESS;
1231 static UINT load_file(MSIRECORD *row, LPVOID param)
1233 MSIPACKAGE* package = param;
1237 /* fill in the data */
1239 file = msi_alloc_zero( sizeof (MSIFILE) );
1241 return ERROR_NOT_ENOUGH_MEMORY;
1243 file->File = msi_dup_record_field( row, 1 );
1245 component = MSI_RecordGetString( row, 2 );
1246 file->Component = msi_get_loaded_component( package, component );
1248 if (!file->Component)
1250 WARN("Component not found: %s\n", debugstr_w(component));
1251 msi_free(file->File);
1253 return ERROR_SUCCESS;
1256 file->FileName = msi_dup_record_field( row, 3 );
1257 msi_reduce_to_long_filename( file->FileName );
1259 file->ShortName = msi_dup_record_field( row, 3 );
1260 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1262 file->FileSize = MSI_RecordGetInteger( row, 4 );
1263 file->Version = msi_dup_record_field( row, 5 );
1264 file->Language = msi_dup_record_field( row, 6 );
1265 file->Attributes = MSI_RecordGetInteger( row, 7 );
1266 file->Sequence = MSI_RecordGetInteger( row, 8 );
1268 file->state = msifs_invalid;
1270 /* if the compressed bits are not set in the file attributes,
1271 * then read the information from the package word count property
1273 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1275 file->IsCompressed = FALSE;
1277 else if (file->Attributes &
1278 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1280 file->IsCompressed = TRUE;
1282 else if (file->Attributes & msidbFileAttributesNoncompressed)
1284 file->IsCompressed = FALSE;
1288 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1291 load_file_hash(package, file);
1292 load_file_disk_id(package, file);
1294 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1296 list_add_tail( &package->files, &file->entry );
1298 return ERROR_SUCCESS;
1301 static UINT load_all_files(MSIPACKAGE *package)
1303 static const WCHAR query[] = {
1304 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1305 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1306 '`','S','e','q','u','e','n','c','e','`', 0};
1310 if (!list_empty(&package->files))
1311 return ERROR_SUCCESS;
1313 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1314 if (rc != ERROR_SUCCESS)
1315 return ERROR_SUCCESS;
1317 rc = MSI_IterateRecords(view, NULL, load_file, package);
1318 msiobj_release(&view->hdr);
1322 static UINT load_media( MSIRECORD *row, LPVOID param )
1324 MSIPACKAGE *package = param;
1325 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1326 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1328 /* FIXME: load external cabinets and directory sources too */
1329 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1330 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1331 return ERROR_SUCCESS;
1334 static UINT load_all_media( MSIPACKAGE *package )
1336 static const WCHAR query[] = {
1337 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1338 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1339 '`','D','i','s','k','I','d','`',0};
1343 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1344 if (r != ERROR_SUCCESS)
1345 return ERROR_SUCCESS;
1347 r = MSI_IterateRecords( view, NULL, load_media, package );
1348 msiobj_release( &view->hdr );
1352 static UINT load_patch(MSIRECORD *row, LPVOID param)
1354 MSIPACKAGE *package = param;
1355 MSIFILEPATCH *patch;
1358 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1360 return ERROR_NOT_ENOUGH_MEMORY;
1362 file_key = msi_dup_record_field( row, 1 );
1363 patch->File = msi_get_loaded_file( package, file_key );
1368 ERR("Failed to find target for patch in File table\n");
1370 return ERROR_FUNCTION_FAILED;
1373 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1375 /* FIXME: The database should be properly transformed */
1376 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1378 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1379 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1380 patch->IsApplied = FALSE;
1383 * Header field - for patch validation.
1384 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1387 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1389 list_add_tail( &package->filepatches, &patch->entry );
1391 return ERROR_SUCCESS;
1394 static UINT load_all_patches(MSIPACKAGE *package)
1396 static const WCHAR query[] = {
1397 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1398 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1399 '`','S','e','q','u','e','n','c','e','`',0};
1403 if (!list_empty(&package->filepatches))
1404 return ERROR_SUCCESS;
1406 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1407 if (rc != ERROR_SUCCESS)
1408 return ERROR_SUCCESS;
1410 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1411 msiobj_release(&view->hdr);
1415 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1417 static const WCHAR query[] = {
1418 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1419 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1420 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1423 folder->persistent = FALSE;
1424 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1426 if (!MSI_ViewExecute( view, NULL ))
1429 if (!MSI_ViewFetch( view, &rec ))
1431 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1432 folder->persistent = TRUE;
1433 msiobj_release( &rec->hdr );
1436 msiobj_release( &view->hdr );
1438 return ERROR_SUCCESS;
1441 static UINT load_folder( MSIRECORD *row, LPVOID param )
1443 MSIPACKAGE *package = param;
1444 static WCHAR szEmpty[] = { 0 };
1445 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1448 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1449 list_init( &folder->children );
1450 folder->Directory = msi_dup_record_field( row, 1 );
1451 folder->Parent = msi_dup_record_field( row, 2 );
1452 p = msi_dup_record_field(row, 3);
1454 TRACE("%s\n", debugstr_w(folder->Directory));
1456 /* split src and target dir */
1458 src_short = folder_split_path( p, ':' );
1460 /* split the long and short paths */
1461 tgt_long = folder_split_path( tgt_short, '|' );
1462 src_long = folder_split_path( src_short, '|' );
1464 /* check for no-op dirs */
1465 if (tgt_short && !strcmpW( szDot, tgt_short ))
1466 tgt_short = szEmpty;
1467 if (src_short && !strcmpW( szDot, src_short ))
1468 src_short = szEmpty;
1471 tgt_long = tgt_short;
1474 src_short = tgt_short;
1475 src_long = tgt_long;
1479 src_long = src_short;
1481 /* FIXME: use the target short path too */
1482 folder->TargetDefault = strdupW(tgt_long);
1483 folder->SourceShortPath = strdupW(src_short);
1484 folder->SourceLongPath = strdupW(src_long);
1487 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1488 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1489 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1491 load_folder_persistence( package, folder );
1493 list_add_tail( &package->folders, &folder->entry );
1494 return ERROR_SUCCESS;
1497 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1501 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1503 list_add_tail( &parent->children, &fl->entry );
1504 return ERROR_SUCCESS;
1507 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1509 MSIPACKAGE *package = param;
1510 MSIFOLDER *parent, *child;
1512 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1513 return ERROR_FUNCTION_FAILED;
1515 if (!child->Parent) return ERROR_SUCCESS;
1517 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1518 return ERROR_FUNCTION_FAILED;
1520 return add_folder_child( parent, child );
1523 static UINT load_all_folders( MSIPACKAGE *package )
1525 static const WCHAR query[] = {
1526 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1527 '`','D','i','r','e','c','t','o','r','y','`',0};
1531 if (!list_empty(&package->folders))
1532 return ERROR_SUCCESS;
1534 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1535 if (r != ERROR_SUCCESS)
1538 r = MSI_IterateRecords( view, NULL, load_folder, package );
1539 if (r != ERROR_SUCCESS)
1541 msiobj_release( &view->hdr );
1544 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1545 msiobj_release( &view->hdr );
1549 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1551 msi_set_property( package->db, szCostingComplete, szZero );
1552 msi_set_property( package->db, szRootDrive, szCRoot );
1554 load_all_folders( package );
1555 msi_load_all_components( package );
1556 msi_load_all_features( package );
1557 load_all_files( package );
1558 load_all_patches( package );
1559 load_all_media( package );
1561 return ERROR_SUCCESS;
1564 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1566 const WCHAR *action = package->script->Actions[script][index];
1567 ui_actionstart( package, action );
1568 TRACE("executing %s\n", debugstr_w(action));
1569 return ACTION_PerformAction( package, action, script );
1572 static UINT execute_script( MSIPACKAGE *package, UINT script )
1574 UINT i, rc = ERROR_SUCCESS;
1576 TRACE("executing script %u\n", script);
1578 if (!package->script)
1580 ERR("no script!\n");
1581 return ERROR_FUNCTION_FAILED;
1583 if (script == ROLLBACK_SCRIPT)
1585 for (i = package->script->ActionCount[script]; i > 0; i--)
1587 rc = execute_script_action( package, script, i - 1 );
1588 if (rc != ERROR_SUCCESS) break;
1593 for (i = 0; i < package->script->ActionCount[script]; i++)
1595 rc = execute_script_action( package, script, i );
1596 if (rc != ERROR_SUCCESS) break;
1599 msi_free_action_script(package, script);
1603 static UINT ACTION_FileCost(MSIPACKAGE *package)
1605 return ERROR_SUCCESS;
1608 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1613 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1615 if (!comp->ComponentId) continue;
1617 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1618 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1620 if (r != ERROR_SUCCESS)
1621 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1622 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1624 if (r != ERROR_SUCCESS)
1625 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1626 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1628 if (r != ERROR_SUCCESS)
1629 comp->Installed = INSTALLSTATE_ABSENT;
1633 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1635 MSIFEATURE *feature;
1637 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1639 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1641 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1642 feature->Installed = INSTALLSTATE_ABSENT;
1644 feature->Installed = state;
1648 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1650 return (feature->Level > 0 && feature->Level <= level);
1653 static BOOL process_state_property(MSIPACKAGE* package, int level,
1654 LPCWSTR property, INSTALLSTATE state)
1657 MSIFEATURE *feature;
1659 override = msi_dup_property( package->db, property );
1663 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1665 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1668 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1670 if (!strcmpiW( override, szAll ))
1672 if (feature->Installed != state)
1674 feature->Action = state;
1675 feature->ActionRequest = state;
1680 LPWSTR ptr = override;
1681 LPWSTR ptr2 = strchrW(override,',');
1685 int len = ptr2 - ptr;
1687 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1688 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1690 if (feature->Installed != state)
1692 feature->Action = state;
1693 feature->ActionRequest = state;
1700 ptr2 = strchrW(ptr,',');
1711 static BOOL process_overrides( MSIPACKAGE *package, int level )
1713 static const WCHAR szAddLocal[] =
1714 {'A','D','D','L','O','C','A','L',0};
1715 static const WCHAR szAddSource[] =
1716 {'A','D','D','S','O','U','R','C','E',0};
1717 static const WCHAR szAdvertise[] =
1718 {'A','D','V','E','R','T','I','S','E',0};
1721 /* all these activation/deactivation things happen in order and things
1722 * later on the list override things earlier on the list.
1724 * 0 INSTALLLEVEL processing
1737 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1738 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1739 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1740 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1741 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1744 msi_set_property( package->db, szPreselected, szOne );
1749 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1752 MSICOMPONENT* component;
1753 MSIFEATURE *feature;
1755 TRACE("Checking Install Level\n");
1757 level = msi_get_property_int(package->db, szInstallLevel, 1);
1759 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1761 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1763 if (!is_feature_selected( feature, level )) continue;
1765 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1767 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1769 feature->Action = INSTALLSTATE_SOURCE;
1770 feature->ActionRequest = INSTALLSTATE_SOURCE;
1772 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1774 feature->Action = INSTALLSTATE_ADVERTISED;
1775 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1779 feature->Action = INSTALLSTATE_LOCAL;
1780 feature->ActionRequest = INSTALLSTATE_LOCAL;
1784 /* disable child features of unselected parent or follow parent */
1785 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1789 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1791 if (!is_feature_selected( feature, level ))
1793 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1794 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1796 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1798 fl->feature->Action = feature->Action;
1799 fl->feature->ActionRequest = feature->ActionRequest;
1804 else /* preselected */
1806 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1808 if (!is_feature_selected( feature, level )) continue;
1810 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1812 if (feature->Installed == INSTALLSTATE_ABSENT)
1814 feature->Action = INSTALLSTATE_UNKNOWN;
1815 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1819 feature->Action = feature->Installed;
1820 feature->ActionRequest = feature->Installed;
1824 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1828 if (!is_feature_selected( feature, level )) continue;
1830 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1832 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1834 fl->feature->Action = feature->Action;
1835 fl->feature->ActionRequest = feature->ActionRequest;
1841 /* now we want to set component state based based on feature state */
1842 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1846 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1847 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1848 feature->ActionRequest, feature->Action);
1850 if (!is_feature_selected( feature, level )) continue;
1852 /* features with components that have compressed files are made local */
1853 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1855 if (cl->component->ForceLocalState &&
1856 feature->ActionRequest == INSTALLSTATE_SOURCE)
1858 feature->Action = INSTALLSTATE_LOCAL;
1859 feature->ActionRequest = INSTALLSTATE_LOCAL;
1864 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1866 component = cl->component;
1868 switch (feature->ActionRequest)
1870 case INSTALLSTATE_ABSENT:
1871 component->anyAbsent = 1;
1873 case INSTALLSTATE_ADVERTISED:
1874 component->hasAdvertiseFeature = 1;
1876 case INSTALLSTATE_SOURCE:
1877 component->hasSourceFeature = 1;
1879 case INSTALLSTATE_LOCAL:
1880 component->hasLocalFeature = 1;
1882 case INSTALLSTATE_DEFAULT:
1883 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1884 component->hasAdvertiseFeature = 1;
1885 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1886 component->hasSourceFeature = 1;
1888 component->hasLocalFeature = 1;
1896 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1898 /* check if it's local or source */
1899 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1900 (component->hasLocalFeature || component->hasSourceFeature))
1902 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1903 !component->ForceLocalState)
1905 component->Action = INSTALLSTATE_SOURCE;
1906 component->ActionRequest = INSTALLSTATE_SOURCE;
1910 component->Action = INSTALLSTATE_LOCAL;
1911 component->ActionRequest = INSTALLSTATE_LOCAL;
1916 /* if any feature is local, the component must be local too */
1917 if (component->hasLocalFeature)
1919 component->Action = INSTALLSTATE_LOCAL;
1920 component->ActionRequest = INSTALLSTATE_LOCAL;
1923 if (component->hasSourceFeature)
1925 component->Action = INSTALLSTATE_SOURCE;
1926 component->ActionRequest = INSTALLSTATE_SOURCE;
1929 if (component->hasAdvertiseFeature)
1931 component->Action = INSTALLSTATE_ADVERTISED;
1932 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1935 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1936 if (component->anyAbsent &&
1937 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1939 component->Action = INSTALLSTATE_ABSENT;
1940 component->ActionRequest = INSTALLSTATE_ABSENT;
1944 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1946 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1948 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1949 component->Action = INSTALLSTATE_LOCAL;
1950 component->ActionRequest = INSTALLSTATE_LOCAL;
1953 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1954 component->Installed == INSTALLSTATE_SOURCE &&
1955 component->hasSourceFeature)
1957 component->Action = INSTALLSTATE_UNKNOWN;
1958 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1961 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1962 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1965 return ERROR_SUCCESS;
1968 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1970 MSIPACKAGE *package = param;
1972 MSIFEATURE *feature;
1974 name = MSI_RecordGetString( row, 1 );
1976 feature = msi_get_loaded_feature( package, name );
1978 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1982 Condition = MSI_RecordGetString(row,3);
1984 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1986 int level = MSI_RecordGetInteger(row,2);
1987 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1988 feature->Level = level;
1991 return ERROR_SUCCESS;
1994 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1996 static const WCHAR name[] = {'\\',0};
1997 VS_FIXEDFILEINFO *ptr, *ret;
1999 DWORD versize, handle;
2002 versize = GetFileVersionInfoSizeW( filename, &handle );
2006 version = msi_alloc( versize );
2010 GetFileVersionInfoW( filename, 0, versize, version );
2012 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2014 msi_free( version );
2018 ret = msi_alloc( sz );
2019 memcpy( ret, ptr, sz );
2021 msi_free( version );
2025 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2029 msi_parse_version_string( version, &ms, &ls );
2031 if (fi->dwFileVersionMS > ms) return 1;
2032 else if (fi->dwFileVersionMS < ms) return -1;
2033 else if (fi->dwFileVersionLS > ls) return 1;
2034 else if (fi->dwFileVersionLS < ls) return -1;
2038 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2042 msi_parse_version_string( ver1, &ms1, NULL );
2043 msi_parse_version_string( ver2, &ms2, NULL );
2045 if (ms1 > ms2) return 1;
2046 else if (ms1 < ms2) return -1;
2050 DWORD msi_get_disk_file_size( LPCWSTR filename )
2055 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2056 if (file == INVALID_HANDLE_VALUE)
2057 return INVALID_FILE_SIZE;
2059 size = GetFileSize( file, NULL );
2060 TRACE("size is %u\n", size);
2061 CloseHandle( file );
2065 BOOL msi_file_hash_matches( MSIFILE *file )
2068 MSIFILEHASHINFO hash;
2070 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2071 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2072 if (r != ERROR_SUCCESS)
2075 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2078 static WCHAR *get_temp_dir( void )
2081 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2083 GetTempPathW( MAX_PATH, tmp );
2086 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2087 if (CreateDirectoryW( dir, NULL )) break;
2089 return strdupW( dir );
2093 * msi_build_directory_name()
2095 * This function is to save messing round with directory names
2096 * It handles adding backslashes between path segments,
2097 * and can add \ at the end of the directory name if told to.
2099 * It takes a variable number of arguments.
2100 * It always allocates a new string for the result, so make sure
2101 * to free the return value when finished with it.
2103 * The first arg is the number of path segments that follow.
2104 * The arguments following count are a list of path segments.
2105 * A path segment may be NULL.
2107 * Path segments will be added with a \ separating them.
2108 * A \ will not be added after the last segment, however if the
2109 * last segment is NULL, then the last character will be a \
2111 WCHAR *msi_build_directory_name( DWORD count, ... )
2117 va_start( va, count );
2118 for (i = 0; i < count; i++)
2120 const WCHAR *str = va_arg( va, const WCHAR * );
2121 if (str) sz += strlenW( str ) + 1;
2125 dir = msi_alloc( sz * sizeof(WCHAR) );
2128 va_start( va, count );
2129 for (i = 0; i < count; i++)
2131 const WCHAR *str = va_arg( va, const WCHAR * );
2133 strcatW( dir, str );
2134 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2140 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2142 MSIASSEMBLY *assembly = file->Component->assembly;
2144 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2146 msi_free( file->TargetPath );
2147 if (assembly && !assembly->application)
2149 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2150 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2151 msi_track_tempfile( package, file->TargetPath );
2155 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2156 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2159 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2162 static UINT calculate_file_cost( MSIPACKAGE *package )
2164 VS_FIXEDFILEINFO *file_version;
2165 WCHAR *font_version;
2168 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2170 MSICOMPONENT *comp = file->Component;
2173 if (!comp->Enabled) continue;
2175 if (file->IsCompressed)
2176 comp->ForceLocalState = TRUE;
2178 set_target_path( package, file );
2180 if ((comp->assembly && !comp->assembly->installed) ||
2181 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2183 comp->Cost += file->FileSize;
2186 file_size = msi_get_disk_file_size( file->TargetPath );
2190 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2192 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2194 comp->Cost += file->FileSize - file_size;
2196 msi_free( file_version );
2199 else if ((font_version = font_version_from_file( file->TargetPath )))
2201 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2203 comp->Cost += file->FileSize - file_size;
2205 msi_free( font_version );
2209 if (file_size != file->FileSize)
2211 comp->Cost += file->FileSize - file_size;
2214 return ERROR_SUCCESS;
2217 void msi_clean_path( WCHAR *p )
2224 /* copy until the end of the string or a space */
2225 while (*p != ' ' && (*q = *p))
2228 /* reduce many backslashes to one */
2229 if (*p != '\\' || *q != '\\')
2233 /* quit at the end of the string */
2237 /* count the number of spaces */
2242 /* if it's leading or trailing space, skip it */
2243 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2245 else /* copy n spaces */
2246 while (n && (*q++ = *p++)) n--;
2250 static WCHAR *get_target_dir_property( MSIDATABASE *db )
2253 WCHAR *path, *target_dir = msi_dup_property( db, szTargetDir );
2255 if (!target_dir) return NULL;
2257 len = strlenW( target_dir );
2258 if (target_dir[len - 1] == '\\') return target_dir;
2259 if ((path = msi_alloc( (len + 2) * sizeof(WCHAR) )))
2261 strcpyW( path, target_dir );
2265 msi_free( target_dir );
2269 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2272 MSIFOLDER *folder, *parent, *child;
2275 TRACE("resolving %s\n", debugstr_w(name));
2277 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2279 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2281 if (!load_prop || !(path = get_target_dir_property( package->db )))
2283 path = msi_dup_property( package->db, szRootDrive );
2286 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2288 parent = msi_get_loaded_folder( package, folder->Parent );
2289 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2291 msi_clean_path( path );
2292 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2294 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2298 msi_set_property( package->db, folder->Directory, path );
2299 msi_free( folder->ResolvedTarget );
2300 folder->ResolvedTarget = path;
2302 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2305 msi_resolve_target_folder( package, child->Directory, load_prop );
2307 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2310 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2312 static const WCHAR query[] = {
2313 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2314 '`','C','o','n','d','i','t','i','o','n','`',0};
2315 static const WCHAR szOutOfDiskSpace[] = {
2316 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2322 TRACE("Building directory properties\n");
2323 msi_resolve_target_folder( package, szTargetDir, TRUE );
2325 TRACE("Evaluating component conditions\n");
2326 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2328 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2330 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2331 comp->Enabled = FALSE;
2334 comp->Enabled = TRUE;
2337 /* read components states from the registry */
2338 ACTION_GetComponentInstallStates(package);
2339 ACTION_GetFeatureInstallStates(package);
2341 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2343 TRACE("Evaluating feature conditions\n");
2345 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2346 if (rc == ERROR_SUCCESS)
2348 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2349 msiobj_release( &view->hdr );
2350 if (rc != ERROR_SUCCESS)
2355 TRACE("Calculating file cost\n");
2356 calculate_file_cost( package );
2358 msi_set_property( package->db, szCostingComplete, szOne );
2359 /* set default run level if not set */
2360 level = msi_dup_property( package->db, szInstallLevel );
2362 msi_set_property( package->db, szInstallLevel, szOne );
2365 /* FIXME: check volume disk space */
2366 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2368 return MSI_SetFeatureStates(package);
2371 /* OK this value is "interpreted" and then formatted based on the
2372 first few characters */
2373 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2378 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2384 LPWSTR deformated = NULL;
2387 deformat_string(package, &value[2], &deformated);
2389 /* binary value type */
2393 *size = (strlenW(ptr)/2)+1;
2395 *size = strlenW(ptr)/2;
2397 data = msi_alloc(*size);
2403 /* if uneven pad with a zero in front */
2409 data[count] = (BYTE)strtol(byte,NULL,0);
2411 TRACE("Uneven byte count\n");
2419 data[count] = (BYTE)strtol(byte,NULL,0);
2422 msi_free(deformated);
2424 TRACE("Data %i bytes(%i)\n",*size,count);
2431 deformat_string(package, &value[1], &deformated);
2434 *size = sizeof(DWORD);
2435 data = msi_alloc(*size);
2441 if ( (*p < '0') || (*p > '9') )
2447 if (deformated[0] == '-')
2450 TRACE("DWORD %i\n",*(LPDWORD)data);
2452 msi_free(deformated);
2457 static const WCHAR szMulti[] = {'[','~',']',0};
2466 *type=REG_EXPAND_SZ;
2474 if (strstrW(value, szMulti))
2475 *type = REG_MULTI_SZ;
2477 /* remove initial delimiter */
2478 if (!strncmpW(value, szMulti, 3))
2481 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2483 /* add double NULL terminator */
2484 if (*type == REG_MULTI_SZ)
2486 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2487 data = msi_realloc_zero(data, *size);
2493 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2500 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2502 *root_key = HKEY_LOCAL_MACHINE;
2507 *root_key = HKEY_CURRENT_USER;
2512 *root_key = HKEY_CLASSES_ROOT;
2516 *root_key = HKEY_CURRENT_USER;
2520 *root_key = HKEY_LOCAL_MACHINE;
2524 *root_key = HKEY_USERS;
2528 ERR("Unknown root %i\n", root);
2535 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2537 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2538 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2540 if (is_64bit && package->platform == PLATFORM_INTEL &&
2541 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2546 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2547 if (!(path_32node = msi_alloc( size ))) return NULL;
2549 memcpy( path_32node, path, len * sizeof(WCHAR) );
2550 strcpyW( path_32node + len, szWow6432Node );
2551 strcatW( path_32node, szBackSlash );
2552 strcatW( path_32node, path + len );
2556 return strdupW( path );
2559 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2561 MSIPACKAGE *package = param;
2562 LPSTR value_data = NULL;
2563 HKEY root_key, hkey;
2565 LPWSTR deformated, uikey, keypath;
2566 LPCWSTR szRoot, component, name, key, value;
2570 BOOL check_first = FALSE;
2573 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2575 component = MSI_RecordGetString(row, 6);
2576 comp = msi_get_loaded_component(package,component);
2578 return ERROR_SUCCESS;
2580 comp->Action = msi_get_component_action( package, comp );
2581 if (comp->Action != INSTALLSTATE_LOCAL)
2583 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2584 return ERROR_SUCCESS;
2587 name = MSI_RecordGetString(row, 4);
2588 if( MSI_RecordIsNull(row,5) && name )
2590 /* null values can have special meanings */
2591 if (name[0]=='-' && name[1] == 0)
2592 return ERROR_SUCCESS;
2593 else if ((name[0]=='+' && name[1] == 0) ||
2594 (name[0] == '*' && name[1] == 0))
2599 root = MSI_RecordGetInteger(row,2);
2600 key = MSI_RecordGetString(row, 3);
2602 szRoot = get_root_key( package, root, &root_key );
2604 return ERROR_SUCCESS;
2606 deformat_string(package, key , &deformated);
2607 size = strlenW(deformated) + strlenW(szRoot) + 1;
2608 uikey = msi_alloc(size*sizeof(WCHAR));
2609 strcpyW(uikey,szRoot);
2610 strcatW(uikey,deformated);
2612 keypath = get_keypath( package, root_key, deformated );
2613 msi_free( deformated );
2614 if (RegCreateKeyW( root_key, keypath, &hkey ))
2616 ERR("Could not create key %s\n", debugstr_w(keypath));
2619 return ERROR_SUCCESS;
2622 value = MSI_RecordGetString(row,5);
2624 value_data = parse_value(package, value, &type, &size);
2627 value_data = (LPSTR)strdupW(szEmpty);
2628 size = sizeof(szEmpty);
2632 deformat_string(package, name, &deformated);
2636 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2638 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2643 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2644 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2646 TRACE("value %s of %s checked already exists\n",
2647 debugstr_w(deformated), debugstr_w(uikey));
2651 TRACE("Checked and setting value %s of %s\n",
2652 debugstr_w(deformated), debugstr_w(uikey));
2653 if (deformated || size)
2654 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2659 uirow = MSI_CreateRecord(3);
2660 MSI_RecordSetStringW(uirow,2,deformated);
2661 MSI_RecordSetStringW(uirow,1,uikey);
2662 if (type == REG_SZ || type == REG_EXPAND_SZ)
2663 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2664 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2665 msiobj_release( &uirow->hdr );
2667 msi_free(value_data);
2668 msi_free(deformated);
2672 return ERROR_SUCCESS;
2675 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2677 static const WCHAR query[] = {
2678 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2679 '`','R','e','g','i','s','t','r','y','`',0};
2683 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2684 if (rc != ERROR_SUCCESS)
2685 return ERROR_SUCCESS;
2687 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2688 msiobj_release(&view->hdr);
2692 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2696 DWORD num_subkeys, num_values;
2700 if ((res = RegDeleteTreeW( hkey_root, key )))
2702 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2707 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2709 if ((res = RegDeleteValueW( hkey, value )))
2711 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2713 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2714 NULL, NULL, NULL, NULL );
2715 RegCloseKey( hkey );
2716 if (!res && !num_subkeys && !num_values)
2718 TRACE("Removing empty key %s\n", debugstr_w(key));
2719 RegDeleteKeyW( hkey_root, key );
2723 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2727 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2729 MSIPACKAGE *package = param;
2730 LPCWSTR component, name, key_str, root_key_str;
2731 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2734 BOOL delete_key = FALSE;
2739 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2741 component = MSI_RecordGetString( row, 6 );
2742 comp = msi_get_loaded_component( package, component );
2744 return ERROR_SUCCESS;
2746 comp->Action = msi_get_component_action( package, comp );
2747 if (comp->Action != INSTALLSTATE_ABSENT)
2749 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2750 return ERROR_SUCCESS;
2753 name = MSI_RecordGetString( row, 4 );
2754 if (MSI_RecordIsNull( row, 5 ) && name )
2756 if (name[0] == '+' && !name[1])
2757 return ERROR_SUCCESS;
2758 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2765 root = MSI_RecordGetInteger( row, 2 );
2766 key_str = MSI_RecordGetString( row, 3 );
2768 root_key_str = get_root_key( package, root, &hkey_root );
2770 return ERROR_SUCCESS;
2772 deformat_string( package, key_str, &deformated_key );
2773 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2774 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2775 strcpyW( ui_key_str, root_key_str );
2776 strcatW( ui_key_str, deformated_key );
2778 deformat_string( package, name, &deformated_name );
2780 keypath = get_keypath( package, hkey_root, deformated_key );
2781 msi_free( deformated_key );
2782 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2783 msi_free( keypath );
2785 uirow = MSI_CreateRecord( 2 );
2786 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2787 MSI_RecordSetStringW( uirow, 2, deformated_name );
2788 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2789 msiobj_release( &uirow->hdr );
2791 msi_free( ui_key_str );
2792 msi_free( deformated_name );
2793 return ERROR_SUCCESS;
2796 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2798 MSIPACKAGE *package = param;
2799 LPCWSTR component, name, key_str, root_key_str;
2800 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2803 BOOL delete_key = FALSE;
2808 component = MSI_RecordGetString( row, 5 );
2809 comp = msi_get_loaded_component( package, component );
2811 return ERROR_SUCCESS;
2813 comp->Action = msi_get_component_action( package, comp );
2814 if (comp->Action != INSTALLSTATE_LOCAL)
2816 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2817 return ERROR_SUCCESS;
2820 if ((name = MSI_RecordGetString( row, 4 )))
2822 if (name[0] == '-' && !name[1])
2829 root = MSI_RecordGetInteger( row, 2 );
2830 key_str = MSI_RecordGetString( row, 3 );
2832 root_key_str = get_root_key( package, root, &hkey_root );
2834 return ERROR_SUCCESS;
2836 deformat_string( package, key_str, &deformated_key );
2837 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2838 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2839 strcpyW( ui_key_str, root_key_str );
2840 strcatW( ui_key_str, deformated_key );
2842 deformat_string( package, name, &deformated_name );
2844 keypath = get_keypath( package, hkey_root, deformated_key );
2845 msi_free( deformated_key );
2846 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2847 msi_free( keypath );
2849 uirow = MSI_CreateRecord( 2 );
2850 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2851 MSI_RecordSetStringW( uirow, 2, deformated_name );
2852 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2853 msiobj_release( &uirow->hdr );
2855 msi_free( ui_key_str );
2856 msi_free( deformated_name );
2857 return ERROR_SUCCESS;
2860 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2862 static const WCHAR registry_query[] = {
2863 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2864 '`','R','e','g','i','s','t','r','y','`',0};
2865 static const WCHAR remove_registry_query[] = {
2866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2867 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2871 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2872 if (rc == ERROR_SUCCESS)
2874 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2875 msiobj_release( &view->hdr );
2876 if (rc != ERROR_SUCCESS)
2879 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2880 if (rc == ERROR_SUCCESS)
2882 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2883 msiobj_release( &view->hdr );
2884 if (rc != ERROR_SUCCESS)
2887 return ERROR_SUCCESS;
2890 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2892 package->script->CurrentlyScripting = TRUE;
2894 return ERROR_SUCCESS;
2898 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2900 static const WCHAR query[]= {
2901 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2902 '`','R','e','g','i','s','t','r','y','`',0};
2904 DWORD total = 0, count = 0;
2906 MSIFEATURE *feature;
2910 TRACE("InstallValidate\n");
2912 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2913 if (rc == ERROR_SUCCESS)
2915 rc = MSI_IterateRecords( view, &count, NULL, package );
2916 msiobj_release( &view->hdr );
2917 if (rc != ERROR_SUCCESS)
2919 total += count * REG_PROGRESS_VALUE;
2921 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2922 total += COMPONENT_PROGRESS_VALUE;
2924 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2925 total += file->FileSize;
2927 msi_ui_progress( package, 0, total, 0, 0 );
2929 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2931 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2932 debugstr_w(feature->Feature), feature->Installed,
2933 feature->ActionRequest, feature->Action);
2935 return ERROR_SUCCESS;
2938 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2940 MSIPACKAGE* package = param;
2941 LPCWSTR cond = NULL;
2942 LPCWSTR message = NULL;
2945 static const WCHAR title[]=
2946 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2948 cond = MSI_RecordGetString(row,1);
2950 r = MSI_EvaluateConditionW(package,cond);
2951 if (r == MSICONDITION_FALSE)
2953 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2956 message = MSI_RecordGetString(row,2);
2957 deformat_string(package,message,&deformated);
2958 MessageBoxW(NULL,deformated,title,MB_OK);
2959 msi_free(deformated);
2962 return ERROR_INSTALL_FAILURE;
2965 return ERROR_SUCCESS;
2968 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2970 static const WCHAR query[] = {
2971 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2972 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2976 TRACE("Checking launch conditions\n");
2978 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2979 if (rc != ERROR_SUCCESS)
2980 return ERROR_SUCCESS;
2982 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2983 msiobj_release(&view->hdr);
2987 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2991 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2993 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2995 static const WCHAR query[] = {
2996 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2997 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
2998 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
2999 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3000 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3003 LPWSTR deformated, buffer, deformated_name;
3006 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3010 root = MSI_RecordGetInteger(row,2);
3011 key = MSI_RecordGetString(row, 3);
3012 name = MSI_RecordGetString(row, 4);
3013 deformat_string(package, key , &deformated);
3014 deformat_string(package, name, &deformated_name);
3016 len = strlenW(deformated) + 6;
3017 if (deformated_name)
3018 len+=strlenW(deformated_name);
3020 buffer = msi_alloc( len *sizeof(WCHAR));
3022 if (deformated_name)
3023 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3025 sprintfW(buffer,fmt,root,deformated);
3027 msi_free(deformated);
3028 msi_free(deformated_name);
3029 msiobj_release(&row->hdr);
3033 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3035 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3040 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3043 return strdupW( file->TargetPath );
3048 static HKEY openSharedDLLsKey(void)
3051 static const WCHAR path[] =
3052 {'S','o','f','t','w','a','r','e','\\',
3053 'M','i','c','r','o','s','o','f','t','\\',
3054 'W','i','n','d','o','w','s','\\',
3055 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3056 'S','h','a','r','e','d','D','L','L','s',0};
3058 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3062 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3067 DWORD sz = sizeof(count);
3070 hkey = openSharedDLLsKey();
3071 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3072 if (rc != ERROR_SUCCESS)
3078 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3082 hkey = openSharedDLLsKey();
3084 msi_reg_set_val_dword( hkey, path, count );
3086 RegDeleteValueW(hkey,path);
3091 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3093 MSIFEATURE *feature;
3097 /* only refcount DLLs */
3098 if (comp->KeyPath == NULL ||
3100 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3101 comp->Attributes & msidbComponentAttributesODBCDataSource)
3105 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3106 write = (count > 0);
3108 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3112 /* increment counts */
3113 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3117 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3120 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3122 if ( cl->component == comp )
3127 /* decrement counts */
3128 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3132 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3135 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3137 if ( cl->component == comp )
3142 /* ref count all the files in the component */
3147 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3149 if (file->Component == comp)
3150 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3154 /* add a count for permanent */
3155 if (comp->Attributes & msidbComponentAttributesPermanent)
3158 comp->RefCount = count;
3161 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3164 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3168 const WCHAR prefixW[] = {'<','\\',0};
3169 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3170 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3174 strcpyW( keypath, prefixW );
3175 strcatW( keypath, comp->assembly->display_name );
3179 return resolve_keypath( package, comp );
3182 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3184 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3191 squash_guid(package->ProductCode,squished_pc);
3192 msi_set_sourcedir_props(package, FALSE);
3194 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3197 INSTALLSTATE action;
3199 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3200 if (!comp->ComponentId)
3203 squash_guid( comp->ComponentId, squished_cc );
3204 msi_free( comp->FullKeypath );
3205 comp->FullKeypath = build_full_keypath( package, comp );
3207 ACTION_RefCountComponent( package, comp );
3209 if (package->need_rollback) action = comp->Installed;
3210 else action = comp->ActionRequest;
3212 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3213 debugstr_w(comp->Component), debugstr_w(squished_cc),
3214 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3216 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3218 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3219 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3221 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3223 if (rc != ERROR_SUCCESS)
3226 if (comp->Attributes & msidbComponentAttributesPermanent)
3228 static const WCHAR szPermKey[] =
3229 { '0','0','0','0','0','0','0','0','0','0','0','0',
3230 '0','0','0','0','0','0','0','0','0','0','0','0',
3231 '0','0','0','0','0','0','0','0',0 };
3233 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3235 if (action == INSTALLSTATE_LOCAL)
3236 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3242 WCHAR source[MAX_PATH];
3243 WCHAR base[MAX_PATH];
3246 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3247 static const WCHAR query[] = {
3248 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3249 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3250 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3251 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3252 '`','D','i','s','k','I','d','`',0};
3254 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3257 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3258 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3259 ptr2 = strrchrW(source, '\\') + 1;
3260 msiobj_release(&row->hdr);
3262 lstrcpyW(base, package->PackagePath);
3263 ptr = strrchrW(base, '\\');
3266 sourcepath = msi_resolve_file_source(package, file);
3267 ptr = sourcepath + lstrlenW(base);
3268 lstrcpyW(ptr2, ptr);
3269 msi_free(sourcepath);
3271 msi_reg_set_val_str(hkey, squished_pc, source);
3275 else if (action == INSTALLSTATE_ABSENT)
3277 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3278 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3280 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3284 uirow = MSI_CreateRecord(3);
3285 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3286 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3287 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3288 msi_ui_actiondata( package, szProcessComponents, uirow );
3289 msiobj_release( &uirow->hdr );
3291 return ERROR_SUCCESS;
3302 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3303 LPWSTR lpszName, LONG_PTR lParam)
3306 typelib_struct *tl_struct = (typelib_struct*) lParam;
3307 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3311 if (!IS_INTRESOURCE(lpszName))
3313 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3317 sz = strlenW(tl_struct->source)+4;
3318 sz *= sizeof(WCHAR);
3320 if ((INT_PTR)lpszName == 1)
3321 tl_struct->path = strdupW(tl_struct->source);
3324 tl_struct->path = msi_alloc(sz);
3325 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3328 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3329 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3332 msi_free(tl_struct->path);
3333 tl_struct->path = NULL;
3338 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3339 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3341 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3345 msi_free(tl_struct->path);
3346 tl_struct->path = NULL;
3348 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3349 ITypeLib_Release(tl_struct->ptLib);
3354 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3356 MSIPACKAGE* package = param;
3360 typelib_struct tl_struct;
3365 component = MSI_RecordGetString(row,3);
3366 comp = msi_get_loaded_component(package,component);
3368 return ERROR_SUCCESS;
3370 comp->Action = msi_get_component_action( package, comp );
3371 if (comp->Action != INSTALLSTATE_LOCAL)
3373 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3374 return ERROR_SUCCESS;
3377 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3379 TRACE("component has no key path\n");
3380 return ERROR_SUCCESS;
3382 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3384 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3388 guid = MSI_RecordGetString(row,1);
3389 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3390 tl_struct.source = strdupW( file->TargetPath );
3391 tl_struct.path = NULL;
3393 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3394 (LONG_PTR)&tl_struct);
3398 LPCWSTR helpid, help_path = NULL;
3401 helpid = MSI_RecordGetString(row,6);
3403 if (helpid) help_path = msi_get_target_folder( package, helpid );
3404 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3407 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3409 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3411 ITypeLib_Release(tl_struct.ptLib);
3412 msi_free(tl_struct.path);
3414 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3416 FreeLibrary(module);
3417 msi_free(tl_struct.source);
3421 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3424 ERR("Failed to load type library: %08x\n", hr);
3425 return ERROR_INSTALL_FAILURE;
3428 ITypeLib_Release(tlib);
3431 return ERROR_SUCCESS;
3434 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3436 static const WCHAR query[] = {
3437 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3438 '`','T','y','p','e','L','i','b','`',0};
3442 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3443 if (rc != ERROR_SUCCESS)
3444 return ERROR_SUCCESS;
3446 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3447 msiobj_release(&view->hdr);
3451 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3453 MSIPACKAGE *package = param;
3454 LPCWSTR component, guid;
3462 component = MSI_RecordGetString( row, 3 );
3463 comp = msi_get_loaded_component( package, component );
3465 return ERROR_SUCCESS;
3467 comp->Action = msi_get_component_action( package, comp );
3468 if (comp->Action != INSTALLSTATE_ABSENT)
3470 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3471 return ERROR_SUCCESS;
3473 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3475 guid = MSI_RecordGetString( row, 1 );
3476 CLSIDFromString( (LPCWSTR)guid, &libid );
3477 version = MSI_RecordGetInteger( row, 4 );
3478 language = MSI_RecordGetInteger( row, 2 );
3481 syskind = SYS_WIN64;
3483 syskind = SYS_WIN32;
3486 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3489 WARN("Failed to unregister typelib: %08x\n", hr);
3492 return ERROR_SUCCESS;
3495 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3497 static const WCHAR query[] = {
3498 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3499 '`','T','y','p','e','L','i','b','`',0};
3503 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3504 if (rc != ERROR_SUCCESS)
3505 return ERROR_SUCCESS;
3507 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3508 msiobj_release( &view->hdr );
3512 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3514 static const WCHAR szlnk[] = {'.','l','n','k',0};
3515 LPCWSTR directory, extension, link_folder;
3516 LPWSTR link_file, filename;
3518 directory = MSI_RecordGetString( row, 2 );
3519 link_folder = msi_get_target_folder( package, directory );
3521 /* may be needed because of a bug somewhere else */
3522 msi_create_full_path( link_folder );
3524 filename = msi_dup_record_field( row, 3 );
3525 msi_reduce_to_long_filename( filename );
3527 extension = strchrW( filename, '.' );
3528 if (!extension || strcmpiW( extension, szlnk ))
3530 int len = strlenW( filename );
3531 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3532 memcpy( filename + len, szlnk, sizeof(szlnk) );
3534 link_file = msi_build_directory_name( 2, link_folder, filename );
3535 msi_free( filename );
3540 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3542 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3543 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3544 WCHAR *folder, *dest, *path;
3546 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3547 folder = msi_dup_property( package->db, szWindowsFolder );
3550 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3551 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3552 msi_free( appdata );
3554 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3555 msi_create_full_path( dest );
3556 path = msi_build_directory_name( 2, dest, icon_name );
3562 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3564 MSIPACKAGE *package = param;
3565 LPWSTR link_file, deformated, path;
3566 LPCWSTR component, target;
3568 IShellLinkW *sl = NULL;
3569 IPersistFile *pf = NULL;
3572 component = MSI_RecordGetString(row, 4);
3573 comp = msi_get_loaded_component(package, component);
3575 return ERROR_SUCCESS;
3577 comp->Action = msi_get_component_action( package, comp );
3578 if (comp->Action != INSTALLSTATE_LOCAL)
3580 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3581 return ERROR_SUCCESS;
3583 msi_ui_actiondata( package, szCreateShortcuts, row );
3585 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3586 &IID_IShellLinkW, (LPVOID *) &sl );
3590 ERR("CLSID_ShellLink not available\n");
3594 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3597 ERR("QueryInterface(IID_IPersistFile) failed\n");
3601 target = MSI_RecordGetString(row, 5);
3602 if (strchrW(target, '['))
3604 deformat_string(package, target, &deformated);
3605 IShellLinkW_SetPath(sl,deformated);
3606 msi_free(deformated);
3610 FIXME("poorly handled shortcut format, advertised shortcut\n");
3611 IShellLinkW_SetPath(sl,comp->FullKeypath);
3614 if (!MSI_RecordIsNull(row,6))
3616 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3617 deformat_string(package, arguments, &deformated);
3618 IShellLinkW_SetArguments(sl,deformated);
3619 msi_free(deformated);
3622 if (!MSI_RecordIsNull(row,7))
3624 LPCWSTR description = MSI_RecordGetString(row, 7);
3625 IShellLinkW_SetDescription(sl, description);
3628 if (!MSI_RecordIsNull(row,8))
3629 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3631 if (!MSI_RecordIsNull(row,9))
3634 LPCWSTR icon = MSI_RecordGetString(row, 9);
3636 path = msi_build_icon_path(package, icon);
3637 index = MSI_RecordGetInteger(row,10);
3639 /* no value means 0 */
3640 if (index == MSI_NULL_INTEGER)
3643 IShellLinkW_SetIconLocation(sl, path, index);
3647 if (!MSI_RecordIsNull(row,11))
3648 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3650 if (!MSI_RecordIsNull(row,12))
3652 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3653 full_path = msi_get_target_folder( package, wkdir );
3654 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3656 link_file = get_link_file(package, row);
3658 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3659 IPersistFile_Save(pf, link_file, FALSE);
3660 msi_free(link_file);
3664 IPersistFile_Release( pf );
3666 IShellLinkW_Release( sl );
3668 return ERROR_SUCCESS;
3671 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3673 static const WCHAR query[] = {
3674 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3675 '`','S','h','o','r','t','c','u','t','`',0};
3680 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3681 if (rc != ERROR_SUCCESS)
3682 return ERROR_SUCCESS;
3684 res = CoInitialize( NULL );
3686 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3687 msiobj_release(&view->hdr);
3689 if (SUCCEEDED(res)) CoUninitialize();
3693 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3695 MSIPACKAGE *package = param;
3700 component = MSI_RecordGetString( row, 4 );
3701 comp = msi_get_loaded_component( package, component );
3703 return ERROR_SUCCESS;
3705 comp->Action = msi_get_component_action( package, comp );
3706 if (comp->Action != INSTALLSTATE_ABSENT)
3708 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3709 return ERROR_SUCCESS;
3711 msi_ui_actiondata( package, szRemoveShortcuts, row );
3713 link_file = get_link_file( package, row );
3715 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3716 if (!DeleteFileW( link_file ))
3718 WARN("Failed to remove shortcut file %u\n", GetLastError());
3720 msi_free( link_file );
3722 return ERROR_SUCCESS;
3725 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3727 static const WCHAR query[] = {
3728 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3729 '`','S','h','o','r','t','c','u','t','`',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_RemoveShortcuts, package );
3738 msiobj_release( &view->hdr );
3742 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3744 MSIPACKAGE* package = param;
3752 FileName = MSI_RecordGetString(row,1);
3755 ERR("Unable to get FileName\n");
3756 return ERROR_SUCCESS;
3759 FilePath = msi_build_icon_path(package, FileName);
3761 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3763 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3764 FILE_ATTRIBUTE_NORMAL, NULL);
3766 if (the_file == INVALID_HANDLE_VALUE)
3768 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3770 return ERROR_SUCCESS;
3777 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3778 if (rc != ERROR_SUCCESS)
3780 ERR("Failed to get stream\n");
3781 CloseHandle(the_file);
3782 DeleteFileW(FilePath);
3785 WriteFile(the_file,buffer,sz,&write,NULL);
3786 } while (sz == 1024);
3789 CloseHandle(the_file);
3791 return ERROR_SUCCESS;
3794 static UINT msi_publish_icons(MSIPACKAGE *package)
3796 static const WCHAR query[]= {
3797 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3798 '`','I','c','o','n','`',0};
3802 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3803 if (r == ERROR_SUCCESS)
3805 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3806 msiobj_release(&view->hdr);
3807 if (r != ERROR_SUCCESS)
3810 return ERROR_SUCCESS;
3813 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3819 MSISOURCELISTINFO *info;
3821 r = RegCreateKeyW(hkey, szSourceList, &source);
3822 if (r != ERROR_SUCCESS)
3825 RegCloseKey(source);
3827 buffer = strrchrW(package->PackagePath, '\\') + 1;
3828 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3829 package->Context, MSICODE_PRODUCT,
3830 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3831 if (r != ERROR_SUCCESS)
3834 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3835 package->Context, MSICODE_PRODUCT,
3836 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3837 if (r != ERROR_SUCCESS)
3840 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3841 package->Context, MSICODE_PRODUCT,
3842 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3843 if (r != ERROR_SUCCESS)
3846 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3848 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3849 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3850 info->options, info->value);
3852 MsiSourceListSetInfoW(package->ProductCode, NULL,
3853 info->context, info->options,
3854 info->property, info->value);
3857 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3859 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3860 disk->context, disk->options,
3861 disk->disk_id, disk->volume_label, disk->disk_prompt);
3864 return ERROR_SUCCESS;
3867 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3869 MSIHANDLE hdb, suminfo;
3870 WCHAR guids[MAX_PATH];
3871 WCHAR packcode[SQUISH_GUID_SIZE];
3878 static const WCHAR szARPProductIcon[] =
3879 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3880 static const WCHAR szAssignment[] =
3881 {'A','s','s','i','g','n','m','e','n','t',0};
3882 static const WCHAR szAdvertiseFlags[] =
3883 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3884 static const WCHAR szClients[] =
3885 {'C','l','i','e','n','t','s',0};
3886 static const WCHAR szColon[] = {':',0};
3888 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3889 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3892 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3893 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3896 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3898 buffer = msi_dup_property(package->db, szARPProductIcon);
3901 LPWSTR path = msi_build_icon_path(package, buffer);
3902 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3907 buffer = msi_dup_property(package->db, szProductVersion);
3910 DWORD verdword = msi_version_str_to_dword(buffer);
3911 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3915 msi_reg_set_val_dword(hkey, szAssignment, 0);
3916 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3917 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3918 msi_reg_set_val_str(hkey, szClients, szColon);
3920 hdb = alloc_msihandle(&package->db->hdr);
3922 return ERROR_NOT_ENOUGH_MEMORY;
3924 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3925 MsiCloseHandle(hdb);
3926 if (r != ERROR_SUCCESS)
3930 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3931 NULL, guids, &size);
3932 if (r != ERROR_SUCCESS)
3935 ptr = strchrW(guids, ';');
3937 squash_guid(guids, packcode);
3938 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3941 MsiCloseHandle(suminfo);
3942 return ERROR_SUCCESS;
3945 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3950 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3952 upgrade = msi_dup_property(package->db, szUpgradeCode);
3954 return ERROR_SUCCESS;
3956 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3957 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3959 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3961 if (r != ERROR_SUCCESS)
3963 WARN("failed to open upgrade code key\n");
3965 return ERROR_SUCCESS;
3967 squash_guid(package->ProductCode, squashed_pc);
3968 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3971 return ERROR_SUCCESS;
3974 static BOOL msi_check_publish(MSIPACKAGE *package)
3976 MSIFEATURE *feature;
3978 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3980 feature->Action = msi_get_feature_action( package, feature );
3981 if (feature->Action == INSTALLSTATE_LOCAL)
3988 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3990 MSIFEATURE *feature;
3992 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3994 feature->Action = msi_get_feature_action( package, feature );
3995 if (feature->Action != INSTALLSTATE_ABSENT)
4002 static UINT msi_publish_patches( MSIPACKAGE *package )
4004 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4005 WCHAR patch_squashed[GUID_SIZE];
4006 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4008 MSIPATCHINFO *patch;
4010 WCHAR *p, *all_patches = NULL;
4013 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4014 if (r != ERROR_SUCCESS)
4015 return ERROR_FUNCTION_FAILED;
4017 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4018 if (res != ERROR_SUCCESS)
4020 r = ERROR_FUNCTION_FAILED;
4024 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4025 if (r != ERROR_SUCCESS)
4028 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4030 squash_guid( patch->patchcode, patch_squashed );
4031 len += strlenW( patch_squashed ) + 1;
4034 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4038 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4042 squash_guid( patch->patchcode, p );
4043 p += strlenW( p ) + 1;
4045 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4046 (const BYTE *)patch->transforms,
4047 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4048 if (res != ERROR_SUCCESS)
4051 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4052 if (r != ERROR_SUCCESS)
4055 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4056 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4057 RegCloseKey( patch_key );
4058 if (res != ERROR_SUCCESS)
4061 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4063 res = GetLastError();
4064 ERR("Unable to copy patch package %d\n", res);
4067 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4068 if (res != ERROR_SUCCESS)
4071 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4072 RegCloseKey( patch_key );
4073 if (res != ERROR_SUCCESS)
4077 all_patches[len] = 0;
4078 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4079 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4080 if (res != ERROR_SUCCESS)
4083 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4084 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4085 if (res != ERROR_SUCCESS)
4086 r = ERROR_FUNCTION_FAILED;
4089 RegCloseKey( product_patches_key );
4090 RegCloseKey( patches_key );
4091 RegCloseKey( product_key );
4092 msi_free( all_patches );
4096 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4099 HKEY hukey = NULL, hudkey = NULL;
4102 if (!list_empty(&package->patches))
4104 rc = msi_publish_patches(package);
4105 if (rc != ERROR_SUCCESS)
4109 /* FIXME: also need to publish if the product is in advertise mode */
4110 if (!msi_check_publish(package))
4111 return ERROR_SUCCESS;
4113 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4115 if (rc != ERROR_SUCCESS)
4118 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4119 NULL, &hudkey, TRUE);
4120 if (rc != ERROR_SUCCESS)
4123 rc = msi_publish_upgrade_code(package);
4124 if (rc != ERROR_SUCCESS)
4127 rc = msi_publish_product_properties(package, hukey);
4128 if (rc != ERROR_SUCCESS)
4131 rc = msi_publish_sourcelist(package, hukey);
4132 if (rc != ERROR_SUCCESS)
4135 rc = msi_publish_icons(package);
4138 uirow = MSI_CreateRecord( 1 );
4139 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4140 msi_ui_actiondata( package, szPublishProduct, uirow );
4141 msiobj_release( &uirow->hdr );
4144 RegCloseKey(hudkey);
4148 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4150 WCHAR *filename, *ptr, *folder, *ret;
4151 const WCHAR *dirprop;
4153 filename = msi_dup_record_field( row, 2 );
4154 if (filename && (ptr = strchrW( filename, '|' )))
4159 dirprop = MSI_RecordGetString( row, 3 );
4162 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4163 if (!folder) folder = msi_dup_property( package->db, dirprop );
4166 folder = msi_dup_property( package->db, szWindowsFolder );
4170 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4171 msi_free( filename );
4175 ret = msi_build_directory_name( 2, folder, ptr );
4177 msi_free( filename );
4182 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4184 MSIPACKAGE *package = param;
4185 LPCWSTR component, section, key, value, identifier;
4186 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4191 component = MSI_RecordGetString(row, 8);
4192 comp = msi_get_loaded_component(package,component);
4194 return ERROR_SUCCESS;
4196 comp->Action = msi_get_component_action( package, comp );
4197 if (comp->Action != INSTALLSTATE_LOCAL)
4199 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4200 return ERROR_SUCCESS;
4203 identifier = MSI_RecordGetString(row,1);
4204 section = MSI_RecordGetString(row,4);
4205 key = MSI_RecordGetString(row,5);
4206 value = MSI_RecordGetString(row,6);
4207 action = MSI_RecordGetInteger(row,7);
4209 deformat_string(package,section,&deformated_section);
4210 deformat_string(package,key,&deformated_key);
4211 deformat_string(package,value,&deformated_value);
4213 fullname = get_ini_file_name(package, row);
4217 TRACE("Adding value %s to section %s in %s\n",
4218 debugstr_w(deformated_key), debugstr_w(deformated_section),
4219 debugstr_w(fullname));
4220 WritePrivateProfileStringW(deformated_section, deformated_key,
4221 deformated_value, fullname);
4223 else if (action == 1)
4226 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4227 returned, 10, fullname);
4228 if (returned[0] == 0)
4230 TRACE("Adding value %s to section %s in %s\n",
4231 debugstr_w(deformated_key), debugstr_w(deformated_section),
4232 debugstr_w(fullname));
4234 WritePrivateProfileStringW(deformated_section, deformated_key,
4235 deformated_value, fullname);
4238 else if (action == 3)
4239 FIXME("Append to existing section not yet implemented\n");
4241 uirow = MSI_CreateRecord(4);
4242 MSI_RecordSetStringW(uirow,1,identifier);
4243 MSI_RecordSetStringW(uirow,2,deformated_section);
4244 MSI_RecordSetStringW(uirow,3,deformated_key);
4245 MSI_RecordSetStringW(uirow,4,deformated_value);
4246 msi_ui_actiondata( package, szWriteIniValues, uirow );
4247 msiobj_release( &uirow->hdr );
4250 msi_free(deformated_key);
4251 msi_free(deformated_value);
4252 msi_free(deformated_section);
4253 return ERROR_SUCCESS;
4256 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4258 static const WCHAR query[] = {
4259 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4260 '`','I','n','i','F','i','l','e','`',0};
4264 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4265 if (rc != ERROR_SUCCESS)
4266 return ERROR_SUCCESS;
4268 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4269 msiobj_release(&view->hdr);
4273 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4275 MSIPACKAGE *package = param;
4276 LPCWSTR component, section, key, value, identifier;
4277 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4282 component = MSI_RecordGetString( row, 8 );
4283 comp = msi_get_loaded_component( package, component );
4285 return ERROR_SUCCESS;
4287 comp->Action = msi_get_component_action( package, comp );
4288 if (comp->Action != INSTALLSTATE_ABSENT)
4290 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4291 return ERROR_SUCCESS;
4294 identifier = MSI_RecordGetString( row, 1 );
4295 section = MSI_RecordGetString( row, 4 );
4296 key = MSI_RecordGetString( row, 5 );
4297 value = MSI_RecordGetString( row, 6 );
4298 action = MSI_RecordGetInteger( row, 7 );
4300 deformat_string( package, section, &deformated_section );
4301 deformat_string( package, key, &deformated_key );
4302 deformat_string( package, value, &deformated_value );
4304 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4306 filename = get_ini_file_name( package, row );
4308 TRACE("Removing key %s from section %s in %s\n",
4309 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4311 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4313 WARN("Unable to remove key %u\n", GetLastError());
4315 msi_free( filename );
4318 FIXME("Unsupported action %d\n", action);
4321 uirow = MSI_CreateRecord( 4 );
4322 MSI_RecordSetStringW( uirow, 1, identifier );
4323 MSI_RecordSetStringW( uirow, 2, deformated_section );
4324 MSI_RecordSetStringW( uirow, 3, deformated_key );
4325 MSI_RecordSetStringW( uirow, 4, deformated_value );
4326 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4327 msiobj_release( &uirow->hdr );
4329 msi_free( deformated_key );
4330 msi_free( deformated_value );
4331 msi_free( deformated_section );
4332 return ERROR_SUCCESS;
4335 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4337 MSIPACKAGE *package = param;
4338 LPCWSTR component, section, key, value, identifier;
4339 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4344 component = MSI_RecordGetString( row, 8 );
4345 comp = msi_get_loaded_component( package, component );
4347 return ERROR_SUCCESS;
4349 comp->Action = msi_get_component_action( package, comp );
4350 if (comp->Action != INSTALLSTATE_LOCAL)
4352 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4353 return ERROR_SUCCESS;
4356 identifier = MSI_RecordGetString( row, 1 );
4357 section = MSI_RecordGetString( row, 4 );
4358 key = MSI_RecordGetString( row, 5 );
4359 value = MSI_RecordGetString( row, 6 );
4360 action = MSI_RecordGetInteger( row, 7 );
4362 deformat_string( package, section, &deformated_section );
4363 deformat_string( package, key, &deformated_key );
4364 deformat_string( package, value, &deformated_value );
4366 if (action == msidbIniFileActionRemoveLine)
4368 filename = get_ini_file_name( package, row );
4370 TRACE("Removing key %s from section %s in %s\n",
4371 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4373 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4375 WARN("Unable to remove key %u\n", GetLastError());
4377 msi_free( filename );
4380 FIXME("Unsupported action %d\n", action);
4382 uirow = MSI_CreateRecord( 4 );
4383 MSI_RecordSetStringW( uirow, 1, identifier );
4384 MSI_RecordSetStringW( uirow, 2, deformated_section );
4385 MSI_RecordSetStringW( uirow, 3, deformated_key );
4386 MSI_RecordSetStringW( uirow, 4, deformated_value );
4387 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4388 msiobj_release( &uirow->hdr );
4390 msi_free( deformated_key );
4391 msi_free( deformated_value );
4392 msi_free( deformated_section );
4393 return ERROR_SUCCESS;
4396 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4398 static const WCHAR query[] = {
4399 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4400 '`','I','n','i','F','i','l','e','`',0};
4401 static const WCHAR remove_query[] = {
4402 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4403 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4407 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4408 if (rc == ERROR_SUCCESS)
4410 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4411 msiobj_release( &view->hdr );
4412 if (rc != ERROR_SUCCESS)
4415 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4416 if (rc == ERROR_SUCCESS)
4418 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4419 msiobj_release( &view->hdr );
4420 if (rc != ERROR_SUCCESS)
4423 return ERROR_SUCCESS;
4426 static void register_dll( const WCHAR *dll, BOOL unregister )
4430 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4433 HRESULT (WINAPI *func_ptr)( void );
4434 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4436 func_ptr = (void *)GetProcAddress( hmod, func );
4439 HRESULT hr = func_ptr();
4441 WARN("failed to register dll 0x%08x\n", hr);
4444 WARN("entry point %s not found\n", func);
4445 FreeLibrary( hmod );
4448 WARN("failed to load library %u\n", GetLastError());
4451 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4453 MSIPACKAGE *package = param;
4458 filename = MSI_RecordGetString(row,1);
4459 file = msi_get_loaded_file( package, filename );
4462 WARN("unable to find file %s\n", debugstr_w(filename));
4463 return ERROR_SUCCESS;
4465 file->Component->Action = msi_get_component_action( package, file->Component );
4466 if (file->Component->Action != INSTALLSTATE_LOCAL)
4468 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4469 return ERROR_SUCCESS;
4472 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4473 register_dll( file->TargetPath, FALSE );
4475 uirow = MSI_CreateRecord( 2 );
4476 MSI_RecordSetStringW( uirow, 1, filename );
4477 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4478 msi_ui_actiondata( package, szSelfRegModules, uirow );
4479 msiobj_release( &uirow->hdr );
4481 return ERROR_SUCCESS;
4484 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4486 static const WCHAR query[] = {
4487 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4488 '`','S','e','l','f','R','e','g','`',0};
4492 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4493 if (rc != ERROR_SUCCESS)
4494 return ERROR_SUCCESS;
4496 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4497 msiobj_release(&view->hdr);
4501 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4503 MSIPACKAGE *package = param;
4508 filename = MSI_RecordGetString( row, 1 );
4509 file = msi_get_loaded_file( package, filename );
4512 WARN("unable to find file %s\n", debugstr_w(filename));
4513 return ERROR_SUCCESS;
4515 file->Component->Action = msi_get_component_action( package, file->Component );
4516 if (file->Component->Action != INSTALLSTATE_ABSENT)
4518 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4519 return ERROR_SUCCESS;
4522 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4523 register_dll( file->TargetPath, TRUE );
4525 uirow = MSI_CreateRecord( 2 );
4526 MSI_RecordSetStringW( uirow, 1, filename );
4527 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4528 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4529 msiobj_release( &uirow->hdr );
4531 return ERROR_SUCCESS;
4534 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4536 static const WCHAR query[] = {
4537 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4538 '`','S','e','l','f','R','e','g','`',0};
4542 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4543 if (rc != ERROR_SUCCESS)
4544 return ERROR_SUCCESS;
4546 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4547 msiobj_release( &view->hdr );
4551 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4553 MSIFEATURE *feature;
4555 HKEY hkey = NULL, userdata = NULL;
4557 if (!msi_check_publish(package))
4558 return ERROR_SUCCESS;
4560 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4562 if (rc != ERROR_SUCCESS)
4565 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4567 if (rc != ERROR_SUCCESS)
4570 /* here the guids are base 85 encoded */
4571 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4577 BOOL absent = FALSE;
4580 if (feature->Action != INSTALLSTATE_LOCAL &&
4581 feature->Action != INSTALLSTATE_SOURCE &&
4582 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4585 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4589 if (feature->Feature_Parent)
4590 size += strlenW( feature->Feature_Parent )+2;
4592 data = msi_alloc(size * sizeof(WCHAR));
4595 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4597 MSICOMPONENT* component = cl->component;
4601 if (component->ComponentId)
4603 TRACE("From %s\n",debugstr_w(component->ComponentId));
4604 CLSIDFromString(component->ComponentId, &clsid);
4605 encode_base85_guid(&clsid,buf);
4606 TRACE("to %s\n",debugstr_w(buf));
4611 if (feature->Feature_Parent)
4613 static const WCHAR sep[] = {'\2',0};
4615 strcatW(data,feature->Feature_Parent);
4618 msi_reg_set_val_str( userdata, feature->Feature, data );
4622 if (feature->Feature_Parent)
4623 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4626 size += sizeof(WCHAR);
4627 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4628 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4632 size += 2*sizeof(WCHAR);
4633 data = msi_alloc(size);
4636 if (feature->Feature_Parent)
4637 strcpyW( &data[1], feature->Feature_Parent );
4638 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4644 uirow = MSI_CreateRecord( 1 );
4645 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4646 msi_ui_actiondata( package, szPublishFeatures, uirow );
4647 msiobj_release( &uirow->hdr );
4648 /* FIXME: call msi_ui_progress? */
4653 RegCloseKey(userdata);
4657 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4663 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4665 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4667 if (r == ERROR_SUCCESS)
4669 RegDeleteValueW(hkey, feature->Feature);
4673 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4675 if (r == ERROR_SUCCESS)
4677 RegDeleteValueW(hkey, feature->Feature);
4681 uirow = MSI_CreateRecord( 1 );
4682 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4683 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4684 msiobj_release( &uirow->hdr );
4686 return ERROR_SUCCESS;
4689 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4691 MSIFEATURE *feature;
4693 if (!msi_check_unpublish(package))
4694 return ERROR_SUCCESS;
4696 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4698 msi_unpublish_feature(package, feature);
4701 return ERROR_SUCCESS;
4704 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4708 WCHAR date[9], *val, *buffer;
4709 const WCHAR *prop, *key;
4711 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4712 static const WCHAR modpath_fmt[] =
4713 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4714 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4715 static const WCHAR szModifyPath[] =
4716 {'M','o','d','i','f','y','P','a','t','h',0};
4717 static const WCHAR szUninstallString[] =
4718 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4719 static const WCHAR szEstimatedSize[] =
4720 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4721 static const WCHAR szDisplayVersion[] =
4722 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4723 static const WCHAR szInstallSource[] =
4724 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4725 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4726 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4727 static const WCHAR szAuthorizedCDFPrefix[] =
4728 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4729 static const WCHAR szARPCONTACT[] =
4730 {'A','R','P','C','O','N','T','A','C','T',0};
4731 static const WCHAR szContact[] =
4732 {'C','o','n','t','a','c','t',0};
4733 static const WCHAR szARPCOMMENTS[] =
4734 {'A','R','P','C','O','M','M','E','N','T','S',0};
4735 static const WCHAR szComments[] =
4736 {'C','o','m','m','e','n','t','s',0};
4737 static const WCHAR szProductName[] =
4738 {'P','r','o','d','u','c','t','N','a','m','e',0};
4739 static const WCHAR szDisplayName[] =
4740 {'D','i','s','p','l','a','y','N','a','m','e',0};
4741 static const WCHAR szARPHELPLINK[] =
4742 {'A','R','P','H','E','L','P','L','I','N','K',0};
4743 static const WCHAR szHelpLink[] =
4744 {'H','e','l','p','L','i','n','k',0};
4745 static const WCHAR szARPHELPTELEPHONE[] =
4746 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4747 static const WCHAR szHelpTelephone[] =
4748 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4749 static const WCHAR szARPINSTALLLOCATION[] =
4750 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4751 static const WCHAR szInstallLocation[] =
4752 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4753 static const WCHAR szManufacturer[] =
4754 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4755 static const WCHAR szPublisher[] =
4756 {'P','u','b','l','i','s','h','e','r',0};
4757 static const WCHAR szARPREADME[] =
4758 {'A','R','P','R','E','A','D','M','E',0};
4759 static const WCHAR szReadme[] =
4760 {'R','e','a','d','M','e',0};
4761 static const WCHAR szARPSIZE[] =
4762 {'A','R','P','S','I','Z','E',0};
4763 static const WCHAR szSize[] =
4764 {'S','i','z','e',0};
4765 static const WCHAR szARPURLINFOABOUT[] =
4766 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4767 static const WCHAR szURLInfoAbout[] =
4768 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4769 static const WCHAR szARPURLUPDATEINFO[] =
4770 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4771 static const WCHAR szURLUpdateInfo[] =
4772 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4773 static const WCHAR szARPSYSTEMCOMPONENT[] =
4774 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4775 static const WCHAR szSystemComponent[] =
4776 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4778 static const WCHAR *propval[] = {
4779 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4780 szARPCONTACT, szContact,
4781 szARPCOMMENTS, szComments,
4782 szProductName, szDisplayName,
4783 szARPHELPLINK, szHelpLink,
4784 szARPHELPTELEPHONE, szHelpTelephone,
4785 szARPINSTALLLOCATION, szInstallLocation,
4786 szSourceDir, szInstallSource,
4787 szManufacturer, szPublisher,
4788 szARPREADME, szReadme,
4790 szARPURLINFOABOUT, szURLInfoAbout,
4791 szARPURLUPDATEINFO, szURLUpdateInfo,
4794 const WCHAR **p = propval;
4800 val = msi_dup_property(package->db, prop);
4801 msi_reg_set_val_str(hkey, key, val);
4805 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4806 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4808 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4810 size = deformat_string(package, modpath_fmt, &buffer);
4811 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4812 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4815 /* FIXME: Write real Estimated Size when we have it */
4816 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4818 GetLocalTime(&systime);
4819 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4820 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4822 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4823 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4825 buffer = msi_dup_property(package->db, szProductVersion);
4826 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4829 DWORD verdword = msi_version_str_to_dword(buffer);
4831 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4832 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4833 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4837 return ERROR_SUCCESS;
4840 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4842 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4844 LPWSTR upgrade_code;
4845 HKEY hkey, props, upgrade_key;
4848 /* FIXME: also need to publish if the product is in advertise mode */
4849 if (!msi_check_publish(package))
4850 return ERROR_SUCCESS;
4852 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4853 if (rc != ERROR_SUCCESS)
4856 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4857 if (rc != ERROR_SUCCESS)
4860 if (!msi_get_property_int( package->db, szInstalled, 0 ))
4862 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4863 if (!CopyFileW( package->PackagePath, package->localfile, FALSE ))
4865 rc = GetLastError();
4866 ERR("Unable to copy package %u\n", rc);
4870 msi_free( package->localfile );
4871 package->localfile = NULL;
4873 rc = msi_publish_install_properties(package, hkey);
4874 if (rc != ERROR_SUCCESS)
4877 rc = msi_publish_install_properties(package, props);
4878 if (rc != ERROR_SUCCESS)
4881 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4884 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4885 if (rc == ERROR_SUCCESS)
4887 squash_guid( package->ProductCode, squashed_pc );
4888 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4889 RegCloseKey( upgrade_key );
4891 msi_free( upgrade_code );
4895 uirow = MSI_CreateRecord( 1 );
4896 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4897 msi_ui_actiondata( package, szRegisterProduct, uirow );
4898 msiobj_release( &uirow->hdr );
4901 return ERROR_SUCCESS;
4904 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4906 return execute_script(package,INSTALL_SCRIPT);
4909 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4911 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4912 WCHAR *upgrade, **features;
4913 BOOL full_uninstall = TRUE;
4914 MSIFEATURE *feature;
4915 MSIPATCHINFO *patch;
4918 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4920 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4922 features = msi_split_string( remove, ',' );
4923 for (i = 0; features && features[i]; i++)
4925 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4929 if (!full_uninstall)
4930 return ERROR_SUCCESS;
4932 MSIREG_DeleteProductKey(package->ProductCode);
4933 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4934 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4936 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4937 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4938 MSIREG_DeleteUserProductKey(package->ProductCode);
4939 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4941 upgrade = msi_dup_property(package->db, szUpgradeCode);
4944 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4945 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4949 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4951 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4952 /* FIXME: remove local patch package if this is the last product */
4955 TRACE("removing local package %s\n", debugstr_w(package->localfile));
4956 DeleteFileW( package->localfile );
4957 msi_free( package->localfile );
4958 package->localfile = NULL;
4960 return ERROR_SUCCESS;
4963 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4968 /* turn off scheduling */
4969 package->script->CurrentlyScripting= FALSE;
4971 /* first do the same as an InstallExecute */
4972 rc = ACTION_InstallExecute(package);
4973 if (rc != ERROR_SUCCESS)
4976 /* then handle Commit Actions */
4977 rc = execute_script(package,COMMIT_SCRIPT);
4978 if (rc != ERROR_SUCCESS)
4981 remove = msi_dup_property(package->db, szRemove);
4982 rc = msi_unpublish_product(package, remove);
4987 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4989 static const WCHAR RunOnce[] = {
4990 'S','o','f','t','w','a','r','e','\\',
4991 'M','i','c','r','o','s','o','f','t','\\',
4992 'W','i','n','d','o','w','s','\\',
4993 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4994 'R','u','n','O','n','c','e',0};
4995 static const WCHAR InstallRunOnce[] = {
4996 'S','o','f','t','w','a','r','e','\\',
4997 'M','i','c','r','o','s','o','f','t','\\',
4998 'W','i','n','d','o','w','s','\\',
4999 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5000 'I','n','s','t','a','l','l','e','r','\\',
5001 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5003 static const WCHAR msiexec_fmt[] = {
5005 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5006 '\"','%','s','\"',0};
5007 static const WCHAR install_fmt[] = {
5008 '/','I',' ','\"','%','s','\"',' ',
5009 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5010 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5011 WCHAR buffer[256], sysdir[MAX_PATH];
5013 WCHAR squished_pc[100];
5015 squash_guid(package->ProductCode,squished_pc);
5017 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5018 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5019 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5022 msi_reg_set_val_str( hkey, squished_pc, buffer );
5025 TRACE("Reboot command %s\n",debugstr_w(buffer));
5027 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5028 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5030 msi_reg_set_val_str( hkey, squished_pc, buffer );
5033 return ERROR_INSTALL_SUSPEND;
5036 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5038 static const WCHAR query[] =
5039 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5040 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5041 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5042 MSIRECORD *rec, *row;
5048 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5050 rec = MSI_CreateRecord( count + 2 );
5051 str = MSI_RecordGetString( row, 1 );
5052 MSI_RecordSetStringW( rec, 0, str );
5053 msiobj_release( &row->hdr );
5054 MSI_RecordSetInteger( rec, 1, error );
5056 va_start( va, count );
5057 for (i = 0; i < count; i++)
5059 str = va_arg( va, const WCHAR *);
5060 MSI_RecordSetStringW( rec, i + 2, str );
5064 MSI_FormatRecordW( package, rec, NULL, &size );
5066 data = msi_alloc( size * sizeof(WCHAR) );
5067 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5069 msiobj_release( &rec->hdr );
5073 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5079 * We are currently doing what should be done here in the top level Install
5080 * however for Administrative and uninstalls this step will be needed
5082 if (!package->PackagePath)
5083 return ERROR_SUCCESS;
5085 msi_set_sourcedir_props(package, TRUE);
5087 attrib = GetFileAttributesW(package->db->path);
5088 if (attrib == INVALID_FILE_ATTRIBUTES)
5094 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5095 package->Context, MSICODE_PRODUCT,
5096 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5097 if (rc == ERROR_MORE_DATA)
5099 prompt = msi_alloc(size * sizeof(WCHAR));
5100 MsiSourceListGetInfoW(package->ProductCode, NULL,
5101 package->Context, MSICODE_PRODUCT,
5102 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5105 prompt = strdupW(package->db->path);
5107 msg = msi_build_error_string(package, 1302, 1, prompt);
5108 while(attrib == INVALID_FILE_ATTRIBUTES)
5110 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5113 rc = ERROR_INSTALL_USEREXIT;
5116 attrib = GetFileAttributesW(package->db->path);
5122 return ERROR_SUCCESS;
5127 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5130 LPWSTR buffer, productid = NULL;
5131 UINT i, rc = ERROR_SUCCESS;
5134 static const WCHAR szPropKeys[][80] =
5136 {'P','r','o','d','u','c','t','I','D',0},
5137 {'U','S','E','R','N','A','M','E',0},
5138 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5142 static const WCHAR szRegKeys[][80] =
5144 {'P','r','o','d','u','c','t','I','D',0},
5145 {'R','e','g','O','w','n','e','r',0},
5146 {'R','e','g','C','o','m','p','a','n','y',0},
5150 if (msi_check_unpublish(package))
5152 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5156 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5160 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5162 if (rc != ERROR_SUCCESS)
5165 for( i = 0; szPropKeys[i][0]; i++ )
5167 buffer = msi_dup_property( package->db, szPropKeys[i] );
5168 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5173 uirow = MSI_CreateRecord( 1 );
5174 MSI_RecordSetStringW( uirow, 1, productid );
5175 msi_ui_actiondata( package, szRegisterUser, uirow );
5176 msiobj_release( &uirow->hdr );
5178 msi_free(productid);
5184 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5188 package->script->InWhatSequence |= SEQUENCE_EXEC;
5189 rc = ACTION_ProcessExecSequence(package,FALSE);
5193 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5195 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5196 WCHAR productid_85[21], component_85[21], *ret;
5200 /* > is used if there is a component GUID and < if not. */
5202 productid_85[0] = 0;
5203 component_85[0] = 0;
5204 CLSIDFromString( package->ProductCode, &clsid );
5206 encode_base85_guid( &clsid, productid_85 );
5209 CLSIDFromString( component->ComponentId, &clsid );
5210 encode_base85_guid( &clsid, component_85 );
5213 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5214 debugstr_w(component_85));
5216 sz = 20 + strlenW( feature ) + 20 + 3;
5217 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5218 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5222 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5224 MSIPACKAGE *package = param;
5225 LPCWSTR compgroupid, component, feature, qualifier, text;
5226 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5235 feature = MSI_RecordGetString(rec, 5);
5236 feat = msi_get_loaded_feature(package, feature);
5238 return ERROR_SUCCESS;
5240 feat->Action = msi_get_feature_action( package, feat );
5241 if (feat->Action != INSTALLSTATE_LOCAL &&
5242 feat->Action != INSTALLSTATE_SOURCE &&
5243 feat->Action != INSTALLSTATE_ADVERTISED)
5245 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5246 return ERROR_SUCCESS;
5249 component = MSI_RecordGetString(rec, 3);
5250 comp = msi_get_loaded_component(package, component);
5252 return ERROR_SUCCESS;
5254 compgroupid = MSI_RecordGetString(rec,1);
5255 qualifier = MSI_RecordGetString(rec,2);
5257 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5258 if (rc != ERROR_SUCCESS)
5261 advertise = msi_create_component_advertise_string( package, comp, feature );
5262 text = MSI_RecordGetString( rec, 4 );
5265 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5266 strcpyW( p, advertise );
5268 msi_free( advertise );
5271 existing = msi_reg_get_val_str( hkey, qualifier );
5273 sz = strlenW( advertise ) + 1;
5276 for (p = existing; *p; p += len)
5278 len = strlenW( p ) + 1;
5279 if (strcmpW( advertise, p )) sz += len;
5282 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5284 rc = ERROR_OUTOFMEMORY;
5290 for (p = existing; *p; p += len)
5292 len = strlenW( p ) + 1;
5293 if (strcmpW( advertise, p ))
5295 memcpy( q, p, len * sizeof(WCHAR) );
5300 strcpyW( q, advertise );
5301 q[strlenW( q ) + 1] = 0;
5303 msi_reg_set_val_multi_str( hkey, qualifier, output );
5308 msi_free( advertise );
5309 msi_free( existing );
5312 uirow = MSI_CreateRecord( 2 );
5313 MSI_RecordSetStringW( uirow, 1, compgroupid );
5314 MSI_RecordSetStringW( uirow, 2, qualifier);
5315 msi_ui_actiondata( package, szPublishComponents, uirow );
5316 msiobj_release( &uirow->hdr );
5317 /* FIXME: call ui_progress? */
5323 * At present I am ignorning the advertised components part of this and only
5324 * focusing on the qualified component sets
5326 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5328 static const WCHAR query[] = {
5329 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5330 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5334 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5335 if (rc != ERROR_SUCCESS)
5336 return ERROR_SUCCESS;
5338 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5339 msiobj_release(&view->hdr);
5343 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5345 static const WCHAR szInstallerComponents[] = {
5346 'S','o','f','t','w','a','r','e','\\',
5347 'M','i','c','r','o','s','o','f','t','\\',
5348 'I','n','s','t','a','l','l','e','r','\\',
5349 'C','o','m','p','o','n','e','n','t','s','\\',0};
5351 MSIPACKAGE *package = param;
5352 LPCWSTR compgroupid, component, feature, qualifier;
5356 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5359 feature = MSI_RecordGetString( rec, 5 );
5360 feat = msi_get_loaded_feature( package, feature );
5362 return ERROR_SUCCESS;
5364 feat->Action = msi_get_feature_action( package, feat );
5365 if (feat->Action != INSTALLSTATE_ABSENT)
5367 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5368 return ERROR_SUCCESS;
5371 component = MSI_RecordGetString( rec, 3 );
5372 comp = msi_get_loaded_component( package, component );
5374 return ERROR_SUCCESS;
5376 compgroupid = MSI_RecordGetString( rec, 1 );
5377 qualifier = MSI_RecordGetString( rec, 2 );
5379 squash_guid( compgroupid, squashed );
5380 strcpyW( keypath, szInstallerComponents );
5381 strcatW( keypath, squashed );
5383 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5384 if (res != ERROR_SUCCESS)
5386 WARN("Unable to delete component key %d\n", res);
5389 uirow = MSI_CreateRecord( 2 );
5390 MSI_RecordSetStringW( uirow, 1, compgroupid );
5391 MSI_RecordSetStringW( uirow, 2, qualifier );
5392 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5393 msiobj_release( &uirow->hdr );
5395 return ERROR_SUCCESS;
5398 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5400 static const WCHAR query[] = {
5401 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5402 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5406 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5407 if (rc != ERROR_SUCCESS)
5408 return ERROR_SUCCESS;
5410 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5411 msiobj_release( &view->hdr );
5415 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5417 static const WCHAR query[] =
5418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5419 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5420 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5421 MSIPACKAGE *package = param;
5422 MSICOMPONENT *component;
5425 SC_HANDLE hscm = NULL, service = NULL;
5427 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5428 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5429 DWORD serv_type, start_type, err_control;
5430 SERVICE_DESCRIPTIONW sd = {NULL};
5432 comp = MSI_RecordGetString( rec, 12 );
5433 component = msi_get_loaded_component( package, comp );
5436 WARN("service component not found\n");
5439 component->Action = msi_get_component_action( package, component );
5440 if (component->Action != INSTALLSTATE_LOCAL)
5442 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5445 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5448 ERR("Failed to open the SC Manager!\n");
5452 start_type = MSI_RecordGetInteger(rec, 5);
5453 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5456 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5457 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5458 serv_type = MSI_RecordGetInteger(rec, 4);
5459 err_control = MSI_RecordGetInteger(rec, 6);
5460 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5461 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5462 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5463 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5464 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5465 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5467 /* fetch the service path */
5468 row = MSI_QueryGetRecord(package->db, query, comp);
5471 ERR("Query failed\n");
5474 key = MSI_RecordGetString(row, 6);
5475 file = msi_get_loaded_file(package, key);
5476 msiobj_release(&row->hdr);
5479 ERR("Failed to load the service file\n");
5483 if (!args || !args[0]) image_path = file->TargetPath;
5486 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5487 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5488 return ERROR_OUTOFMEMORY;
5490 strcpyW(image_path, file->TargetPath);
5491 strcatW(image_path, szSpace);
5492 strcatW(image_path, args);
5494 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5495 start_type, err_control, image_path, load_order,
5496 NULL, depends, serv_name, pass);
5500 if (GetLastError() != ERROR_SERVICE_EXISTS)
5501 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5503 else if (sd.lpDescription)
5505 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5506 WARN("failed to set service description %u\n", GetLastError());
5509 if (image_path != file->TargetPath) msi_free(image_path);
5511 CloseServiceHandle(service);
5512 CloseServiceHandle(hscm);
5515 msi_free(sd.lpDescription);
5516 msi_free(load_order);
5517 msi_free(serv_name);
5522 return ERROR_SUCCESS;
5525 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5527 static const WCHAR query[] = {
5528 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5529 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5533 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5534 if (rc != ERROR_SUCCESS)
5535 return ERROR_SUCCESS;
5537 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5538 msiobj_release(&view->hdr);
5542 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5543 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5545 LPCWSTR *vector, *temp_vector;
5549 static const WCHAR separator[] = {'[','~',']',0};
5552 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5557 vector = msi_alloc(sizeof(LPWSTR));
5565 vector[*numargs - 1] = p;
5567 if ((q = strstrW(p, separator)))
5571 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5577 vector = temp_vector;
5586 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5588 MSIPACKAGE *package = param;
5591 SC_HANDLE scm = NULL, service = NULL;
5592 LPCWSTR component, *vector = NULL;
5593 LPWSTR name, args, display_name = NULL;
5594 DWORD event, numargs, len;
5595 UINT r = ERROR_FUNCTION_FAILED;
5597 component = MSI_RecordGetString(rec, 6);
5598 comp = msi_get_loaded_component(package, component);
5600 return ERROR_SUCCESS;
5602 comp->Action = msi_get_component_action( package, comp );
5603 if (comp->Action != INSTALLSTATE_LOCAL)
5605 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5606 return ERROR_SUCCESS;
5609 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5610 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5611 event = MSI_RecordGetInteger(rec, 3);
5613 if (!(event & msidbServiceControlEventStart))
5619 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5622 ERR("Failed to open the service control manager\n");
5627 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5628 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5630 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5631 GetServiceDisplayNameW( scm, name, display_name, &len );
5634 service = OpenServiceW(scm, name, SERVICE_START);
5637 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5641 vector = msi_service_args_to_vector(args, &numargs);
5643 if (!StartServiceW(service, numargs, vector) &&
5644 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5646 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5653 uirow = MSI_CreateRecord( 2 );
5654 MSI_RecordSetStringW( uirow, 1, display_name );
5655 MSI_RecordSetStringW( uirow, 2, name );
5656 msi_ui_actiondata( package, szStartServices, uirow );
5657 msiobj_release( &uirow->hdr );
5659 CloseServiceHandle(service);
5660 CloseServiceHandle(scm);
5665 msi_free(display_name);
5669 static UINT ACTION_StartServices( MSIPACKAGE *package )
5671 static const WCHAR query[] = {
5672 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5673 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5677 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5678 if (rc != ERROR_SUCCESS)
5679 return ERROR_SUCCESS;
5681 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5682 msiobj_release(&view->hdr);
5686 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5688 DWORD i, needed, count;
5689 ENUM_SERVICE_STATUSW *dependencies;
5693 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5694 0, &needed, &count))
5697 if (GetLastError() != ERROR_MORE_DATA)
5700 dependencies = msi_alloc(needed);
5704 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5705 needed, &needed, &count))
5708 for (i = 0; i < count; i++)
5710 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5711 SERVICE_STOP | SERVICE_QUERY_STATUS);
5715 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5722 msi_free(dependencies);
5726 static UINT stop_service( LPCWSTR name )
5728 SC_HANDLE scm = NULL, service = NULL;
5729 SERVICE_STATUS status;
5730 SERVICE_STATUS_PROCESS ssp;
5733 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5736 WARN("Failed to open the SCM: %d\n", GetLastError());
5740 service = OpenServiceW(scm, name,
5742 SERVICE_QUERY_STATUS |
5743 SERVICE_ENUMERATE_DEPENDENTS);
5746 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5750 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5751 sizeof(SERVICE_STATUS_PROCESS), &needed))
5753 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5757 if (ssp.dwCurrentState == SERVICE_STOPPED)
5760 stop_service_dependents(scm, service);
5762 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5763 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5766 CloseServiceHandle(service);
5767 CloseServiceHandle(scm);
5769 return ERROR_SUCCESS;
5772 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5774 MSIPACKAGE *package = param;
5778 LPWSTR name = NULL, display_name = NULL;
5782 event = MSI_RecordGetInteger( rec, 3 );
5783 if (!(event & msidbServiceControlEventStop))
5784 return ERROR_SUCCESS;
5786 component = MSI_RecordGetString( rec, 6 );
5787 comp = msi_get_loaded_component( package, component );
5789 return ERROR_SUCCESS;
5791 comp->Action = msi_get_component_action( package, comp );
5792 if (comp->Action != INSTALLSTATE_ABSENT)
5794 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5795 return ERROR_SUCCESS;
5798 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5801 ERR("Failed to open the service control manager\n");
5806 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5807 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5809 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5810 GetServiceDisplayNameW( scm, name, display_name, &len );
5812 CloseServiceHandle( scm );
5814 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5815 stop_service( name );
5818 uirow = MSI_CreateRecord( 2 );
5819 MSI_RecordSetStringW( uirow, 1, display_name );
5820 MSI_RecordSetStringW( uirow, 2, name );
5821 msi_ui_actiondata( package, szStopServices, uirow );
5822 msiobj_release( &uirow->hdr );
5825 msi_free( display_name );
5826 return ERROR_SUCCESS;
5829 static UINT ACTION_StopServices( MSIPACKAGE *package )
5831 static const WCHAR query[] = {
5832 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5833 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5837 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5838 if (rc != ERROR_SUCCESS)
5839 return ERROR_SUCCESS;
5841 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5842 msiobj_release(&view->hdr);
5846 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5848 MSIPACKAGE *package = param;
5852 LPWSTR name = NULL, display_name = NULL;
5854 SC_HANDLE scm = NULL, service = NULL;
5856 event = MSI_RecordGetInteger( rec, 3 );
5857 if (!(event & msidbServiceControlEventDelete))
5858 return ERROR_SUCCESS;
5860 component = MSI_RecordGetString(rec, 6);
5861 comp = msi_get_loaded_component(package, component);
5863 return ERROR_SUCCESS;
5865 comp->Action = msi_get_component_action( package, comp );
5866 if (comp->Action != INSTALLSTATE_ABSENT)
5868 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5869 return ERROR_SUCCESS;
5872 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5873 stop_service( name );
5875 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5878 WARN("Failed to open the SCM: %d\n", GetLastError());
5883 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5884 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5886 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5887 GetServiceDisplayNameW( scm, name, display_name, &len );
5890 service = OpenServiceW( scm, name, DELETE );
5893 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5897 if (!DeleteService( service ))
5898 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5901 uirow = MSI_CreateRecord( 2 );
5902 MSI_RecordSetStringW( uirow, 1, display_name );
5903 MSI_RecordSetStringW( uirow, 2, name );
5904 msi_ui_actiondata( package, szDeleteServices, uirow );
5905 msiobj_release( &uirow->hdr );
5907 CloseServiceHandle( service );
5908 CloseServiceHandle( scm );
5910 msi_free( display_name );
5912 return ERROR_SUCCESS;
5915 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5917 static const WCHAR query[] = {
5918 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5919 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5923 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5924 if (rc != ERROR_SUCCESS)
5925 return ERROR_SUCCESS;
5927 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5928 msiobj_release( &view->hdr );
5932 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5934 MSIPACKAGE *package = param;
5935 LPWSTR driver, driver_path, ptr;
5936 WCHAR outpath[MAX_PATH];
5937 MSIFILE *driver_file = NULL, *setup_file = NULL;
5940 LPCWSTR desc, file_key, component;
5942 UINT r = ERROR_SUCCESS;
5944 static const WCHAR driver_fmt[] = {
5945 'D','r','i','v','e','r','=','%','s',0};
5946 static const WCHAR setup_fmt[] = {
5947 'S','e','t','u','p','=','%','s',0};
5948 static const WCHAR usage_fmt[] = {
5949 'F','i','l','e','U','s','a','g','e','=','1',0};
5951 component = MSI_RecordGetString( rec, 2 );
5952 comp = msi_get_loaded_component( package, component );
5954 return ERROR_SUCCESS;
5956 comp->Action = msi_get_component_action( package, comp );
5957 if (comp->Action != INSTALLSTATE_LOCAL)
5959 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5960 return ERROR_SUCCESS;
5962 desc = MSI_RecordGetString(rec, 3);
5964 file_key = MSI_RecordGetString( rec, 4 );
5965 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
5967 file_key = MSI_RecordGetString( rec, 5 );
5968 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
5972 ERR("ODBC Driver entry not found!\n");
5973 return ERROR_FUNCTION_FAILED;
5976 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5978 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5979 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5981 driver = msi_alloc(len * sizeof(WCHAR));
5983 return ERROR_OUTOFMEMORY;
5986 lstrcpyW(ptr, desc);
5987 ptr += lstrlenW(ptr) + 1;
5989 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5994 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5998 lstrcpyW(ptr, usage_fmt);
5999 ptr += lstrlenW(ptr) + 1;
6002 driver_path = strdupW(driver_file->TargetPath);
6003 ptr = strrchrW(driver_path, '\\');
6004 if (ptr) *ptr = '\0';
6006 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6007 NULL, ODBC_INSTALL_COMPLETE, &usage))
6009 ERR("Failed to install SQL driver!\n");
6010 r = ERROR_FUNCTION_FAILED;
6013 uirow = MSI_CreateRecord( 5 );
6014 MSI_RecordSetStringW( uirow, 1, desc );
6015 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6016 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6017 msi_ui_actiondata( package, szInstallODBC, uirow );
6018 msiobj_release( &uirow->hdr );
6021 msi_free(driver_path);
6026 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6028 MSIPACKAGE *package = param;
6029 LPWSTR translator, translator_path, ptr;
6030 WCHAR outpath[MAX_PATH];
6031 MSIFILE *translator_file = NULL, *setup_file = NULL;
6034 LPCWSTR desc, file_key, component;
6036 UINT r = ERROR_SUCCESS;
6038 static const WCHAR translator_fmt[] = {
6039 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6040 static const WCHAR setup_fmt[] = {
6041 'S','e','t','u','p','=','%','s',0};
6043 component = MSI_RecordGetString( rec, 2 );
6044 comp = msi_get_loaded_component( package, component );
6046 return ERROR_SUCCESS;
6048 comp->Action = msi_get_component_action( package, comp );
6049 if (comp->Action != INSTALLSTATE_LOCAL)
6051 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6052 return ERROR_SUCCESS;
6054 desc = MSI_RecordGetString(rec, 3);
6056 file_key = MSI_RecordGetString( rec, 4 );
6057 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6059 file_key = MSI_RecordGetString( rec, 5 );
6060 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6062 if (!translator_file)
6064 ERR("ODBC Translator entry not found!\n");
6065 return ERROR_FUNCTION_FAILED;
6068 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6070 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6072 translator = msi_alloc(len * sizeof(WCHAR));
6074 return ERROR_OUTOFMEMORY;
6077 lstrcpyW(ptr, desc);
6078 ptr += lstrlenW(ptr) + 1;
6080 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6085 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6090 translator_path = strdupW(translator_file->TargetPath);
6091 ptr = strrchrW(translator_path, '\\');
6092 if (ptr) *ptr = '\0';
6094 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6095 NULL, ODBC_INSTALL_COMPLETE, &usage))
6097 ERR("Failed to install SQL translator!\n");
6098 r = ERROR_FUNCTION_FAILED;
6101 uirow = MSI_CreateRecord( 5 );
6102 MSI_RecordSetStringW( uirow, 1, desc );
6103 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6104 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6105 msi_ui_actiondata( package, szInstallODBC, uirow );
6106 msiobj_release( &uirow->hdr );
6108 msi_free(translator);
6109 msi_free(translator_path);
6114 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6116 MSIPACKAGE *package = param;
6119 LPCWSTR desc, driver, component;
6120 WORD request = ODBC_ADD_SYS_DSN;
6123 UINT r = ERROR_SUCCESS;
6126 static const WCHAR attrs_fmt[] = {
6127 'D','S','N','=','%','s',0 };
6129 component = MSI_RecordGetString( rec, 2 );
6130 comp = msi_get_loaded_component( package, component );
6132 return ERROR_SUCCESS;
6134 comp->Action = msi_get_component_action( package, comp );
6135 if (comp->Action != INSTALLSTATE_LOCAL)
6137 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6138 return ERROR_SUCCESS;
6141 desc = MSI_RecordGetString(rec, 3);
6142 driver = MSI_RecordGetString(rec, 4);
6143 registration = MSI_RecordGetInteger(rec, 5);
6145 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6146 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6148 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6149 attrs = msi_alloc(len * sizeof(WCHAR));
6151 return ERROR_OUTOFMEMORY;
6153 len = sprintfW(attrs, attrs_fmt, desc);
6156 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6158 ERR("Failed to install SQL data source!\n");
6159 r = ERROR_FUNCTION_FAILED;
6162 uirow = MSI_CreateRecord( 5 );
6163 MSI_RecordSetStringW( uirow, 1, desc );
6164 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6165 MSI_RecordSetInteger( uirow, 3, request );
6166 msi_ui_actiondata( package, szInstallODBC, uirow );
6167 msiobj_release( &uirow->hdr );
6174 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6176 static const WCHAR driver_query[] = {
6177 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6178 'O','D','B','C','D','r','i','v','e','r',0};
6179 static const WCHAR translator_query[] = {
6180 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6181 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6182 static const WCHAR source_query[] = {
6183 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6184 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6188 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6189 if (rc == ERROR_SUCCESS)
6191 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6192 msiobj_release(&view->hdr);
6193 if (rc != ERROR_SUCCESS)
6196 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6197 if (rc == ERROR_SUCCESS)
6199 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6200 msiobj_release(&view->hdr);
6201 if (rc != ERROR_SUCCESS)
6204 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6205 if (rc == ERROR_SUCCESS)
6207 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6208 msiobj_release(&view->hdr);
6209 if (rc != ERROR_SUCCESS)
6212 return ERROR_SUCCESS;
6215 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6217 MSIPACKAGE *package = param;
6221 LPCWSTR desc, component;
6223 component = MSI_RecordGetString( rec, 2 );
6224 comp = msi_get_loaded_component( package, component );
6226 return ERROR_SUCCESS;
6228 comp->Action = msi_get_component_action( package, comp );
6229 if (comp->Action != INSTALLSTATE_ABSENT)
6231 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6232 return ERROR_SUCCESS;
6235 desc = MSI_RecordGetString( rec, 3 );
6236 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6238 WARN("Failed to remove ODBC driver\n");
6242 FIXME("Usage count reached 0\n");
6245 uirow = MSI_CreateRecord( 2 );
6246 MSI_RecordSetStringW( uirow, 1, desc );
6247 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6248 msi_ui_actiondata( package, szRemoveODBC, uirow );
6249 msiobj_release( &uirow->hdr );
6251 return ERROR_SUCCESS;
6254 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6256 MSIPACKAGE *package = param;
6260 LPCWSTR desc, component;
6262 component = MSI_RecordGetString( rec, 2 );
6263 comp = msi_get_loaded_component( package, component );
6265 return ERROR_SUCCESS;
6267 comp->Action = msi_get_component_action( package, comp );
6268 if (comp->Action != INSTALLSTATE_ABSENT)
6270 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6271 return ERROR_SUCCESS;
6274 desc = MSI_RecordGetString( rec, 3 );
6275 if (!SQLRemoveTranslatorW( desc, &usage ))
6277 WARN("Failed to remove ODBC translator\n");
6281 FIXME("Usage count reached 0\n");
6284 uirow = MSI_CreateRecord( 2 );
6285 MSI_RecordSetStringW( uirow, 1, desc );
6286 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6287 msi_ui_actiondata( package, szRemoveODBC, uirow );
6288 msiobj_release( &uirow->hdr );
6290 return ERROR_SUCCESS;
6293 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6295 MSIPACKAGE *package = param;
6299 LPCWSTR desc, driver, component;
6300 WORD request = ODBC_REMOVE_SYS_DSN;
6304 static const WCHAR attrs_fmt[] = {
6305 'D','S','N','=','%','s',0 };
6307 component = MSI_RecordGetString( rec, 2 );
6308 comp = msi_get_loaded_component( package, component );
6310 return ERROR_SUCCESS;
6312 comp->Action = msi_get_component_action( package, comp );
6313 if (comp->Action != INSTALLSTATE_ABSENT)
6315 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6316 return ERROR_SUCCESS;
6319 desc = MSI_RecordGetString( rec, 3 );
6320 driver = MSI_RecordGetString( rec, 4 );
6321 registration = MSI_RecordGetInteger( rec, 5 );
6323 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6324 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6326 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6327 attrs = msi_alloc( len * sizeof(WCHAR) );
6329 return ERROR_OUTOFMEMORY;
6331 FIXME("Use ODBCSourceAttribute table\n");
6333 len = sprintfW( attrs, attrs_fmt, desc );
6336 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6338 WARN("Failed to remove ODBC data source\n");
6342 uirow = MSI_CreateRecord( 3 );
6343 MSI_RecordSetStringW( uirow, 1, desc );
6344 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6345 MSI_RecordSetInteger( uirow, 3, request );
6346 msi_ui_actiondata( package, szRemoveODBC, uirow );
6347 msiobj_release( &uirow->hdr );
6349 return ERROR_SUCCESS;
6352 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6354 static const WCHAR driver_query[] = {
6355 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6356 'O','D','B','C','D','r','i','v','e','r',0};
6357 static const WCHAR translator_query[] = {
6358 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6359 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6360 static const WCHAR source_query[] = {
6361 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6362 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6366 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6367 if (rc == ERROR_SUCCESS)
6369 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6370 msiobj_release( &view->hdr );
6371 if (rc != ERROR_SUCCESS)
6374 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6375 if (rc == ERROR_SUCCESS)
6377 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6378 msiobj_release( &view->hdr );
6379 if (rc != ERROR_SUCCESS)
6382 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6383 if (rc == ERROR_SUCCESS)
6385 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6386 msiobj_release( &view->hdr );
6387 if (rc != ERROR_SUCCESS)
6390 return ERROR_SUCCESS;
6393 #define ENV_ACT_SETALWAYS 0x1
6394 #define ENV_ACT_SETABSENT 0x2
6395 #define ENV_ACT_REMOVE 0x4
6396 #define ENV_ACT_REMOVEMATCH 0x8
6398 #define ENV_MOD_MACHINE 0x20000000
6399 #define ENV_MOD_APPEND 0x40000000
6400 #define ENV_MOD_PREFIX 0x80000000
6401 #define ENV_MOD_MASK 0xC0000000
6403 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6405 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6407 LPCWSTR cptr = *name;
6409 static const WCHAR prefix[] = {'[','~',']',0};
6410 static const int prefix_len = 3;
6416 *flags |= ENV_ACT_SETALWAYS;
6417 else if (*cptr == '+')
6418 *flags |= ENV_ACT_SETABSENT;
6419 else if (*cptr == '-')
6420 *flags |= ENV_ACT_REMOVE;
6421 else if (*cptr == '!')
6422 *flags |= ENV_ACT_REMOVEMATCH;
6423 else if (*cptr == '*')
6424 *flags |= ENV_MOD_MACHINE;
6434 ERR("Missing environment variable\n");
6435 return ERROR_FUNCTION_FAILED;
6440 LPCWSTR ptr = *value;
6441 if (!strncmpW(ptr, prefix, prefix_len))
6443 if (ptr[prefix_len] == szSemiColon[0])
6445 *flags |= ENV_MOD_APPEND;
6446 *value += lstrlenW(prefix);
6453 else if (lstrlenW(*value) >= prefix_len)
6455 ptr += lstrlenW(ptr) - prefix_len;
6456 if (!strcmpW( ptr, prefix ))
6458 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6460 *flags |= ENV_MOD_PREFIX;
6461 /* the "[~]" will be removed by deformat_string */;
6471 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6472 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6473 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6474 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6476 ERR("Invalid flags: %08x\n", *flags);
6477 return ERROR_FUNCTION_FAILED;
6481 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6483 return ERROR_SUCCESS;
6486 static UINT open_env_key( DWORD flags, HKEY *key )
6488 static const WCHAR user_env[] =
6489 {'E','n','v','i','r','o','n','m','e','n','t',0};
6490 static const WCHAR machine_env[] =
6491 {'S','y','s','t','e','m','\\',
6492 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6493 'C','o','n','t','r','o','l','\\',
6494 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6495 'E','n','v','i','r','o','n','m','e','n','t',0};
6500 if (flags & ENV_MOD_MACHINE)
6503 root = HKEY_LOCAL_MACHINE;
6508 root = HKEY_CURRENT_USER;
6511 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6512 if (res != ERROR_SUCCESS)
6514 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6515 return ERROR_FUNCTION_FAILED;
6518 return ERROR_SUCCESS;
6521 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6523 MSIPACKAGE *package = param;
6524 LPCWSTR name, value, component;
6525 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6526 DWORD flags, type, size;
6533 component = MSI_RecordGetString(rec, 4);
6534 comp = msi_get_loaded_component(package, component);
6536 return ERROR_SUCCESS;
6538 comp->Action = msi_get_component_action( package, comp );
6539 if (comp->Action != INSTALLSTATE_LOCAL)
6541 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6542 return ERROR_SUCCESS;
6544 name = MSI_RecordGetString(rec, 2);
6545 value = MSI_RecordGetString(rec, 3);
6547 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6549 res = env_parse_flags(&name, &value, &flags);
6550 if (res != ERROR_SUCCESS || !value)
6553 if (value && !deformat_string(package, value, &deformatted))
6555 res = ERROR_OUTOFMEMORY;
6559 value = deformatted;
6561 res = open_env_key( flags, &env );
6562 if (res != ERROR_SUCCESS)
6565 if (flags & ENV_MOD_MACHINE)
6566 action |= 0x20000000;
6570 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6571 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6572 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6575 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6579 /* Nothing to do. */
6582 res = ERROR_SUCCESS;
6586 /* If we are appending but the string was empty, strip ; */
6587 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6589 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6590 newval = strdupW(value);
6593 res = ERROR_OUTOFMEMORY;
6601 /* Contrary to MSDN, +-variable to [~];path works */
6602 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6604 res = ERROR_SUCCESS;
6608 data = msi_alloc(size);
6612 return ERROR_OUTOFMEMORY;
6615 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6616 if (res != ERROR_SUCCESS)
6619 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6622 res = RegDeleteValueW(env, name);
6623 if (res != ERROR_SUCCESS)
6624 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6628 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6629 if (flags & ENV_MOD_MASK)
6633 if (flags & ENV_MOD_APPEND) multiplier++;
6634 if (flags & ENV_MOD_PREFIX) multiplier++;
6635 mod_size = lstrlenW(value) * multiplier;
6636 size += mod_size * sizeof(WCHAR);
6639 newval = msi_alloc(size);
6643 res = ERROR_OUTOFMEMORY;
6647 if (flags & ENV_MOD_PREFIX)
6649 lstrcpyW(newval, value);
6650 ptr = newval + lstrlenW(value);
6651 action |= 0x80000000;
6654 lstrcpyW(ptr, data);
6656 if (flags & ENV_MOD_APPEND)
6658 lstrcatW(newval, value);
6659 action |= 0x40000000;
6662 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6663 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6666 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6670 uirow = MSI_CreateRecord( 3 );
6671 MSI_RecordSetStringW( uirow, 1, name );
6672 MSI_RecordSetStringW( uirow, 2, newval );
6673 MSI_RecordSetInteger( uirow, 3, action );
6674 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6675 msiobj_release( &uirow->hdr );
6677 if (env) RegCloseKey(env);
6678 msi_free(deformatted);
6684 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6686 static const WCHAR query[] = {
6687 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6688 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6692 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6693 if (rc != ERROR_SUCCESS)
6694 return ERROR_SUCCESS;
6696 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6697 msiobj_release(&view->hdr);
6701 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6703 MSIPACKAGE *package = param;
6704 LPCWSTR name, value, component;
6705 LPWSTR deformatted = NULL;
6714 component = MSI_RecordGetString( rec, 4 );
6715 comp = msi_get_loaded_component( package, component );
6717 return ERROR_SUCCESS;
6719 comp->Action = msi_get_component_action( package, comp );
6720 if (comp->Action != INSTALLSTATE_ABSENT)
6722 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6723 return ERROR_SUCCESS;
6725 name = MSI_RecordGetString( rec, 2 );
6726 value = MSI_RecordGetString( rec, 3 );
6728 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6730 r = env_parse_flags( &name, &value, &flags );
6731 if (r != ERROR_SUCCESS)
6734 if (!(flags & ENV_ACT_REMOVE))
6736 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6737 return ERROR_SUCCESS;
6740 if (value && !deformat_string( package, value, &deformatted ))
6741 return ERROR_OUTOFMEMORY;
6743 value = deformatted;
6745 r = open_env_key( flags, &env );
6746 if (r != ERROR_SUCCESS)
6752 if (flags & ENV_MOD_MACHINE)
6753 action |= 0x20000000;
6755 TRACE("Removing %s\n", debugstr_w(name));
6757 res = RegDeleteValueW( env, name );
6758 if (res != ERROR_SUCCESS)
6760 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6765 uirow = MSI_CreateRecord( 3 );
6766 MSI_RecordSetStringW( uirow, 1, name );
6767 MSI_RecordSetStringW( uirow, 2, value );
6768 MSI_RecordSetInteger( uirow, 3, action );
6769 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6770 msiobj_release( &uirow->hdr );
6772 if (env) RegCloseKey( env );
6773 msi_free( deformatted );
6777 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6779 static const WCHAR query[] = {
6780 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6781 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6785 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6786 if (rc != ERROR_SUCCESS)
6787 return ERROR_SUCCESS;
6789 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6790 msiobj_release( &view->hdr );
6794 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6796 LPWSTR key, template, id;
6797 UINT r = ERROR_SUCCESS;
6799 id = msi_dup_property( package->db, szProductID );
6803 return ERROR_SUCCESS;
6805 template = msi_dup_property( package->db, szPIDTemplate );
6806 key = msi_dup_property( package->db, szPIDKEY );
6808 if (key && template)
6810 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6811 r = msi_set_property( package->db, szProductID, key );
6813 msi_free( template );
6818 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6821 package->need_reboot = 1;
6822 return ERROR_SUCCESS;
6825 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6827 static const WCHAR szAvailableFreeReg[] =
6828 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6830 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6832 TRACE("%p %d kilobytes\n", package, space);
6834 uirow = MSI_CreateRecord( 1 );
6835 MSI_RecordSetInteger( uirow, 1, space );
6836 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6837 msiobj_release( &uirow->hdr );
6839 return ERROR_SUCCESS;
6842 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6844 TRACE("%p\n", package);
6846 msi_set_property( package->db, szRollbackDisabled, szOne );
6847 return ERROR_SUCCESS;
6850 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6852 FIXME("%p\n", package);
6853 return ERROR_SUCCESS;
6856 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6858 static const WCHAR driver_query[] = {
6859 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6860 'O','D','B','C','D','r','i','v','e','r',0};
6861 static const WCHAR translator_query[] = {
6862 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6863 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6867 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6868 if (r == ERROR_SUCCESS)
6871 r = MSI_IterateRecords( view, &count, NULL, package );
6872 msiobj_release( &view->hdr );
6873 if (r != ERROR_SUCCESS)
6875 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6877 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6878 if (r == ERROR_SUCCESS)
6881 r = MSI_IterateRecords( view, &count, NULL, package );
6882 msiobj_release( &view->hdr );
6883 if (r != ERROR_SUCCESS)
6885 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6887 return ERROR_SUCCESS;
6890 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6892 MSIPACKAGE *package = param;
6893 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6896 if ((value = msi_dup_property( package->db, property )))
6898 FIXME("remove %s\n", debugstr_w(value));
6901 return ERROR_SUCCESS;
6904 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6906 static const WCHAR query[] = {
6907 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6908 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6912 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6913 if (r == ERROR_SUCCESS)
6915 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6916 msiobj_release( &view->hdr );
6917 if (r != ERROR_SUCCESS)
6920 return ERROR_SUCCESS;
6923 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6925 MSIPACKAGE *package = param;
6926 int attributes = MSI_RecordGetInteger( rec, 5 );
6928 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6930 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6931 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6932 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6933 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6937 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6939 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6940 if (r != ERROR_SUCCESS)
6941 return ERROR_SUCCESS;
6945 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6946 if (r != ERROR_SUCCESS)
6947 return ERROR_SUCCESS;
6949 RegCloseKey( hkey );
6951 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6952 debugstr_w(upgrade_code), debugstr_w(version_min),
6953 debugstr_w(version_max), debugstr_w(language));
6955 return ERROR_SUCCESS;
6958 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6960 static const WCHAR query[] = {
6961 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6962 'U','p','g','r','a','d','e',0};
6966 if (msi_get_property_int( package->db, szInstalled, 0 ))
6968 TRACE("product is installed, skipping action\n");
6969 return ERROR_SUCCESS;
6971 if (msi_get_property_int( package->db, szPreselected, 0 ))
6973 TRACE("Preselected property is set, not migrating feature states\n");
6974 return ERROR_SUCCESS;
6976 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6977 if (r == ERROR_SUCCESS)
6979 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
6980 msiobj_release( &view->hdr );
6981 if (r != ERROR_SUCCESS)
6984 return ERROR_SUCCESS;
6987 static void bind_image( const char *filename, const char *path )
6989 if (!BindImageEx( 0, filename, path, NULL, NULL ))
6991 WARN("failed to bind image %u\n", GetLastError());
6995 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
6999 MSIPACKAGE *package = param;
7000 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7001 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7002 char *filenameA, *pathA;
7003 WCHAR *pathW, **path_list;
7005 if (!(file = msi_get_loaded_file( package, key )))
7007 WARN("file %s not found\n", debugstr_w(key));
7008 return ERROR_SUCCESS;
7010 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7011 path_list = msi_split_string( paths, ';' );
7012 if (!path_list) bind_image( filenameA, NULL );
7015 for (i = 0; path_list[i] && path_list[i][0]; i++)
7017 deformat_string( package, path_list[i], &pathW );
7018 if ((pathA = strdupWtoA( pathW )))
7020 bind_image( filenameA, pathA );
7026 msi_free( path_list );
7027 msi_free( filenameA );
7028 return ERROR_SUCCESS;
7031 static UINT ACTION_BindImage( MSIPACKAGE *package )
7033 static const WCHAR query[] = {
7034 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7035 'B','i','n','d','I','m','a','g','e',0};
7039 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7040 if (r == ERROR_SUCCESS)
7042 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7043 msiobj_release( &view->hdr );
7044 if (r != ERROR_SUCCESS)
7047 return ERROR_SUCCESS;
7050 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7052 static const WCHAR query[] = {
7053 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7058 r = MSI_OpenQuery( package->db, &view, query, table );
7059 if (r == ERROR_SUCCESS)
7061 r = MSI_IterateRecords(view, &count, NULL, package);
7062 msiobj_release(&view->hdr);
7063 if (r != ERROR_SUCCESS)
7066 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7067 return ERROR_SUCCESS;
7070 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7072 static const WCHAR table[] = {
7073 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7074 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7077 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7079 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7080 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7083 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7085 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7086 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7089 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7091 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7092 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7095 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7097 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7098 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7103 const WCHAR *action;
7104 UINT (*handler)(MSIPACKAGE *);
7105 const WCHAR *action_rollback;
7109 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7110 { szAppSearch, ACTION_AppSearch, NULL },
7111 { szBindImage, ACTION_BindImage, NULL },
7112 { szCCPSearch, ACTION_CCPSearch, NULL },
7113 { szCostFinalize, ACTION_CostFinalize, NULL },
7114 { szCostInitialize, ACTION_CostInitialize, NULL },
7115 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7116 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7117 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7118 { szDisableRollback, ACTION_DisableRollback, NULL },
7119 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7120 { szExecuteAction, ACTION_ExecuteAction, NULL },
7121 { szFileCost, ACTION_FileCost, NULL },
7122 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7123 { szForceReboot, ACTION_ForceReboot, NULL },
7124 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7125 { szInstallExecute, ACTION_InstallExecute, NULL },
7126 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7127 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7128 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7129 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7130 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7131 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7132 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7133 { szInstallValidate, ACTION_InstallValidate, NULL },
7134 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7135 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7136 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7137 { szMoveFiles, ACTION_MoveFiles, NULL },
7138 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7139 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7140 { szPatchFiles, ACTION_PatchFiles, NULL },
7141 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7142 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7143 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7144 { szPublishProduct, ACTION_PublishProduct, NULL },
7145 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7146 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7147 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7148 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7149 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7150 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7151 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7152 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7153 { szRegisterUser, ACTION_RegisterUser, NULL },
7154 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7155 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7156 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7157 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7158 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7159 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7160 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7161 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7162 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7163 { szResolveSource, ACTION_ResolveSource, NULL },
7164 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7165 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7166 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7167 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7168 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7169 { szStartServices, ACTION_StartServices, szStopServices },
7170 { szStopServices, ACTION_StopServices, szStartServices },
7171 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7172 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7173 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7174 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7175 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7176 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7177 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7178 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7179 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7180 { szValidateProductID, ACTION_ValidateProductID, NULL },
7181 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7182 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7183 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7184 { NULL, NULL, NULL }
7187 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7193 while (StandardActions[i].action != NULL)
7195 if (!strcmpW( StandardActions[i].action, action ))
7197 ui_actionstart( package, action );
7198 if (StandardActions[i].handler)
7200 ui_actioninfo( package, action, TRUE, 0 );
7201 *rc = StandardActions[i].handler( package );
7202 ui_actioninfo( package, action, FALSE, *rc );
7204 if (StandardActions[i].action_rollback && !package->need_rollback)
7206 TRACE("scheduling rollback action\n");
7207 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7212 FIXME("unhandled standard action %s\n", debugstr_w(action));
7213 *rc = ERROR_SUCCESS;
7223 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7225 UINT rc = ERROR_SUCCESS;
7228 TRACE("Performing action (%s)\n", debugstr_w(action));
7230 handled = ACTION_HandleStandardAction(package, action, &rc);
7233 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7237 WARN("unhandled msi action %s\n", debugstr_w(action));
7238 rc = ERROR_FUNCTION_NOT_CALLED;
7244 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7246 UINT rc = ERROR_SUCCESS;
7247 BOOL handled = FALSE;
7249 TRACE("Performing action (%s)\n", debugstr_w(action));
7251 handled = ACTION_HandleStandardAction(package, action, &rc);
7254 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7256 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7261 WARN("unhandled msi action %s\n", debugstr_w(action));
7262 rc = ERROR_FUNCTION_NOT_CALLED;
7268 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7270 UINT rc = ERROR_SUCCESS;
7273 static const WCHAR query[] =
7274 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7275 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7276 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7277 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7278 static const WCHAR ui_query[] =
7279 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7280 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7281 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7282 ' ', '=',' ','%','i',0};
7284 if (needs_ui_sequence(package))
7285 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7287 row = MSI_QueryGetRecord(package->db, query, seq);
7291 LPCWSTR action, cond;
7293 TRACE("Running the actions\n");
7295 /* check conditions */
7296 cond = MSI_RecordGetString(row, 2);
7298 /* this is a hack to skip errors in the condition code */
7299 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7301 msiobj_release(&row->hdr);
7302 return ERROR_SUCCESS;
7305 action = MSI_RecordGetString(row, 1);
7308 ERR("failed to fetch action\n");
7309 msiobj_release(&row->hdr);
7310 return ERROR_FUNCTION_FAILED;
7313 if (needs_ui_sequence(package))
7314 rc = ACTION_PerformUIAction(package, action, -1);
7316 rc = ACTION_PerformAction(package, action, -1);
7318 msiobj_release(&row->hdr);
7324 /****************************************************
7325 * TOP level entry points
7326 *****************************************************/
7328 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7329 LPCWSTR szCommandLine )
7333 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7334 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7335 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7337 msi_set_property( package->db, szAction, szInstall );
7339 package->script->InWhatSequence = SEQUENCE_INSTALL;
7346 dir = strdupW(szPackagePath);
7347 p = strrchrW(dir, '\\');
7351 file = szPackagePath + (p - dir);
7356 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7357 GetCurrentDirectoryW(MAX_PATH, dir);
7358 lstrcatW(dir, szBackSlash);
7359 file = szPackagePath;
7362 msi_free( package->PackagePath );
7363 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7364 if (!package->PackagePath)
7367 return ERROR_OUTOFMEMORY;
7370 lstrcpyW(package->PackagePath, dir);
7371 lstrcatW(package->PackagePath, file);
7374 msi_set_sourcedir_props(package, FALSE);
7377 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7378 if (rc != ERROR_SUCCESS)
7381 msi_apply_transforms( package );
7382 msi_apply_patches( package );
7384 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7386 TRACE("setting reinstall property\n");
7387 msi_set_property( package->db, szReinstall, szAll );
7390 /* properties may have been added by a transform */
7391 msi_clone_properties( package );
7393 msi_parse_command_line( package, szCommandLine, FALSE );
7394 msi_adjust_privilege_properties( package );
7395 msi_set_context( package );
7397 if (msi_get_property_int( package->db, szInstalled, 0 ))
7400 DeleteFileW( package->localfile );
7401 msi_free( package->localfile );
7402 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
7403 package->localfile = msi_reg_get_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW );
7404 RegCloseKey( hkey );
7406 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7408 TRACE("disabling rollback\n");
7409 msi_set_property( package->db, szRollbackDisabled, szOne );
7412 if (needs_ui_sequence( package))
7414 package->script->InWhatSequence |= SEQUENCE_UI;
7415 rc = ACTION_ProcessUISequence(package);
7416 ui_exists = ui_sequence_exists(package);
7417 if (rc == ERROR_SUCCESS || !ui_exists)
7419 package->script->InWhatSequence |= SEQUENCE_EXEC;
7420 rc = ACTION_ProcessExecSequence(package, ui_exists);
7424 rc = ACTION_ProcessExecSequence(package, FALSE);
7426 package->script->CurrentlyScripting = FALSE;
7428 /* process the ending type action */
7429 if (rc == ERROR_SUCCESS)
7430 ACTION_PerformActionSequence(package, -1);
7431 else if (rc == ERROR_INSTALL_USEREXIT)
7432 ACTION_PerformActionSequence(package, -2);
7433 else if (rc == ERROR_INSTALL_SUSPEND)
7434 ACTION_PerformActionSequence(package, -4);
7437 ACTION_PerformActionSequence(package, -3);
7438 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7440 package->need_rollback = TRUE;
7444 /* finish up running custom actions */
7445 ACTION_FinishCustomActions(package);
7447 if (package->need_rollback)
7449 WARN("installation failed, running rollback script\n");
7450 execute_script( package, ROLLBACK_SCRIPT );
7453 if (rc == ERROR_SUCCESS && package->need_reboot)
7454 return ERROR_SUCCESS_REBOOT_REQUIRED;