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)
491 UINT r = msi_locate_product( package->ProductCode, &package->Context );
492 if (r != ERROR_SUCCESS)
494 int num = msi_get_property_int( package->db, szAllUsers, 0 );
495 if (num == 1 || num == 2)
496 package->Context = MSIINSTALLCONTEXT_MACHINE;
498 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
500 return ERROR_SUCCESS;
503 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
506 LPCWSTR cond, action;
507 MSIPACKAGE *package = param;
509 action = MSI_RecordGetString(row,1);
512 ERR("Error is retrieving action name\n");
513 return ERROR_FUNCTION_FAILED;
516 /* check conditions */
517 cond = MSI_RecordGetString(row,2);
519 /* this is a hack to skip errors in the condition code */
520 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
522 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
523 return ERROR_SUCCESS;
526 if (needs_ui_sequence(package))
527 rc = ACTION_PerformUIAction(package, action, -1);
529 rc = ACTION_PerformAction(package, action, -1);
531 msi_dialog_check_messages( NULL );
533 if (package->CurrentInstallState != ERROR_SUCCESS)
534 rc = package->CurrentInstallState;
536 if (rc == ERROR_FUNCTION_NOT_CALLED)
539 if (rc != ERROR_SUCCESS)
540 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
545 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
547 static const WCHAR query[] = {
548 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
549 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
550 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
551 '`','S','e','q','u','e','n','c','e','`',0};
555 TRACE("%p %s\n", package, debugstr_w(table));
557 r = MSI_OpenQuery( package->db, &view, query, table );
558 if (r == ERROR_SUCCESS)
560 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
561 msiobj_release(&view->hdr);
566 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
568 static const WCHAR query[] = {
569 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
570 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
571 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
572 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
573 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
574 static const WCHAR query_validate[] = {
575 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
576 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
577 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
578 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
579 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
584 if (package->script->ExecuteSequenceRun)
586 TRACE("Execute Sequence already Run\n");
587 return ERROR_SUCCESS;
590 package->script->ExecuteSequenceRun = TRUE;
592 /* get the sequence number */
595 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
596 if (!row) return ERROR_FUNCTION_FAILED;
597 seq = MSI_RecordGetInteger(row,1);
598 msiobj_release(&row->hdr);
600 rc = MSI_OpenQuery(package->db, &view, query, seq);
601 if (rc == ERROR_SUCCESS)
603 TRACE("Running the actions\n");
605 msi_set_property(package->db, szSourceDir, NULL);
606 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
607 msiobj_release(&view->hdr);
612 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
614 static const WCHAR query[] = {
615 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
616 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
617 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
618 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
622 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
623 if (rc == ERROR_SUCCESS)
625 TRACE("Running the actions\n");
626 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
627 msiobj_release(&view->hdr);
632 /********************************************************
633 * ACTION helper functions and functions that perform the actions
634 *******************************************************/
635 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
636 UINT* rc, UINT script, BOOL force )
641 arc = ACTION_CustomAction(package, action, script, force);
643 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
651 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
655 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
657 if (!strcmpW( Component, comp->Component )) return comp;
662 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
666 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
668 if (!strcmpW( Feature, feature->Feature )) return feature;
673 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
677 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
679 if (!strcmpW( key, file->File )) return file;
684 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
688 /* FIXME: There might be more than one patch */
689 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
691 if (!strcmpW( key, patch->File->File )) return patch;
696 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
700 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
702 if (!strcmpW( dir, folder->Directory )) return folder;
708 * Recursively create all directories in the path.
709 * shamelessly stolen from setupapi/queue.c
711 BOOL msi_create_full_path( const WCHAR *path )
717 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
718 strcpyW( new_path, path );
720 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
721 new_path[len - 1] = 0;
723 while (!CreateDirectoryW( new_path, NULL ))
726 DWORD last_error = GetLastError();
727 if (last_error == ERROR_ALREADY_EXISTS) break;
728 if (last_error != ERROR_PATH_NOT_FOUND)
733 if (!(slash = strrchrW( new_path, '\\' )))
738 len = slash - new_path;
740 if (!msi_create_full_path( new_path ))
745 new_path[len] = '\\';
747 msi_free( new_path );
751 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
755 row = MSI_CreateRecord( 4 );
756 MSI_RecordSetInteger( row, 1, a );
757 MSI_RecordSetInteger( row, 2, b );
758 MSI_RecordSetInteger( row, 3, c );
759 MSI_RecordSetInteger( row, 4, d );
760 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
761 msiobj_release( &row->hdr );
763 msi_dialog_check_messages( NULL );
766 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
768 static const WCHAR query[] =
769 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
770 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
771 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
776 if (!package->LastAction || strcmpW( package->LastAction, action ))
778 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
780 if (MSI_RecordIsNull( row, 3 ))
782 msiobj_release( &row->hdr );
785 /* update the cached action format */
786 msi_free( package->ActionFormat );
787 package->ActionFormat = msi_dup_record_field( row, 3 );
788 msi_free( package->LastAction );
789 package->LastAction = strdupW( action );
790 msiobj_release( &row->hdr );
793 MSI_RecordSetStringW( record, 0, package->ActionFormat );
794 MSI_FormatRecordW( package, record, message, &size );
795 row = MSI_CreateRecord( 1 );
796 MSI_RecordSetStringW( row, 1, message );
797 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
798 msiobj_release( &row->hdr );
801 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
805 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
806 return INSTALLSTATE_UNKNOWN;
808 if (package->need_rollback) return comp->Installed;
809 return comp->ActionRequest;
812 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
814 if (package->need_rollback) return feature->Installed;
815 return feature->ActionRequest;
818 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
820 MSIPACKAGE *package = param;
821 LPCWSTR dir, component, full_path;
826 component = MSI_RecordGetString(row, 2);
828 return ERROR_SUCCESS;
830 comp = msi_get_loaded_component(package, component);
832 return ERROR_SUCCESS;
834 comp->Action = msi_get_component_action( package, comp );
835 if (comp->Action != INSTALLSTATE_LOCAL)
837 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
838 return ERROR_SUCCESS;
841 dir = MSI_RecordGetString(row,1);
844 ERR("Unable to get folder id\n");
845 return ERROR_SUCCESS;
848 uirow = MSI_CreateRecord(1);
849 MSI_RecordSetStringW(uirow, 1, dir);
850 msi_ui_actiondata(package, szCreateFolders, uirow);
851 msiobj_release(&uirow->hdr);
853 full_path = msi_get_target_folder( package, dir );
856 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
857 return ERROR_SUCCESS;
859 TRACE("folder is %s\n", debugstr_w(full_path));
861 folder = msi_get_loaded_folder( package, dir );
862 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
863 folder->State = FOLDER_STATE_CREATED;
864 return ERROR_SUCCESS;
867 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
869 static const WCHAR query[] = {
870 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
871 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
875 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
876 if (rc != ERROR_SUCCESS)
877 return ERROR_SUCCESS;
879 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
880 msiobj_release(&view->hdr);
884 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
886 MSIPACKAGE *package = param;
887 LPCWSTR dir, component, full_path;
892 component = MSI_RecordGetString(row, 2);
894 return ERROR_SUCCESS;
896 comp = msi_get_loaded_component(package, component);
898 return ERROR_SUCCESS;
900 comp->Action = msi_get_component_action( package, comp );
901 if (comp->Action != INSTALLSTATE_ABSENT)
903 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
904 return ERROR_SUCCESS;
907 dir = MSI_RecordGetString( row, 1 );
910 ERR("Unable to get folder id\n");
911 return ERROR_SUCCESS;
914 full_path = msi_get_target_folder( package, dir );
917 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
918 return ERROR_SUCCESS;
920 TRACE("folder is %s\n", debugstr_w(full_path));
922 uirow = MSI_CreateRecord( 1 );
923 MSI_RecordSetStringW( uirow, 1, dir );
924 msi_ui_actiondata( package, szRemoveFolders, uirow );
925 msiobj_release( &uirow->hdr );
927 RemoveDirectoryW( full_path );
928 folder = msi_get_loaded_folder( package, dir );
929 folder->State = FOLDER_STATE_REMOVED;
930 return ERROR_SUCCESS;
933 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
935 static const WCHAR query[] = {
936 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
937 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
941 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
942 if (rc != ERROR_SUCCESS)
943 return ERROR_SUCCESS;
945 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
946 msiobj_release( &view->hdr );
950 static UINT load_component( MSIRECORD *row, LPVOID param )
952 MSIPACKAGE *package = param;
955 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
957 return ERROR_FUNCTION_FAILED;
959 list_add_tail( &package->components, &comp->entry );
961 /* fill in the data */
962 comp->Component = msi_dup_record_field( row, 1 );
964 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
966 comp->ComponentId = msi_dup_record_field( row, 2 );
967 comp->Directory = msi_dup_record_field( row, 3 );
968 comp->Attributes = MSI_RecordGetInteger(row,4);
969 comp->Condition = msi_dup_record_field( row, 5 );
970 comp->KeyPath = msi_dup_record_field( row, 6 );
972 comp->Installed = INSTALLSTATE_UNKNOWN;
973 comp->Action = INSTALLSTATE_UNKNOWN;
974 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
976 comp->assembly = msi_load_assembly( package, comp );
977 return ERROR_SUCCESS;
980 UINT msi_load_all_components( MSIPACKAGE *package )
982 static const WCHAR query[] = {
983 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
984 '`','C','o','m','p','o','n','e','n','t','`',0};
988 if (!list_empty(&package->components))
989 return ERROR_SUCCESS;
991 r = MSI_DatabaseOpenViewW( package->db, query, &view );
992 if (r != ERROR_SUCCESS)
995 if (!msi_init_assembly_caches( package ))
997 ERR("can't initialize assembly caches\n");
998 msiobj_release( &view->hdr );
999 return ERROR_FUNCTION_FAILED;
1002 r = MSI_IterateRecords(view, NULL, load_component, package);
1003 msiobj_release(&view->hdr);
1004 msi_destroy_assembly_caches( package );
1009 MSIPACKAGE *package;
1010 MSIFEATURE *feature;
1013 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1017 cl = msi_alloc( sizeof (*cl) );
1019 return ERROR_NOT_ENOUGH_MEMORY;
1020 cl->component = comp;
1021 list_add_tail( &feature->Components, &cl->entry );
1023 return ERROR_SUCCESS;
1026 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1030 fl = msi_alloc( sizeof(*fl) );
1032 return ERROR_NOT_ENOUGH_MEMORY;
1033 fl->feature = child;
1034 list_add_tail( &parent->Children, &fl->entry );
1036 return ERROR_SUCCESS;
1039 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1041 _ilfs* ilfs = param;
1045 component = MSI_RecordGetString(row,1);
1047 /* check to see if the component is already loaded */
1048 comp = msi_get_loaded_component( ilfs->package, component );
1051 WARN("ignoring unknown component %s\n", debugstr_w(component));
1052 return ERROR_SUCCESS;
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 );
3522 /* some installers use a separate root */
3523 MSIFOLDER *folder = msi_get_loaded_folder( package, directory );
3524 while (folder->Parent && strcmpW( folder->Parent, folder->Directory ))
3526 folder = msi_get_loaded_folder( package, folder->Parent );
3528 msi_resolve_target_folder( package, folder->Directory, TRUE );
3529 link_folder = msi_get_target_folder( package, directory );
3531 /* may be needed because of a bug somewhere else */
3532 msi_create_full_path( link_folder );
3534 filename = msi_dup_record_field( row, 3 );
3535 msi_reduce_to_long_filename( filename );
3537 extension = strchrW( filename, '.' );
3538 if (!extension || strcmpiW( extension, szlnk ))
3540 int len = strlenW( filename );
3541 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3542 memcpy( filename + len, szlnk, sizeof(szlnk) );
3544 link_file = msi_build_directory_name( 2, link_folder, filename );
3545 msi_free( filename );
3550 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3552 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3553 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3554 WCHAR *folder, *dest, *path;
3556 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3557 folder = msi_dup_property( package->db, szWindowsFolder );
3560 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3561 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3562 msi_free( appdata );
3564 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3565 msi_create_full_path( dest );
3566 path = msi_build_directory_name( 2, dest, icon_name );
3572 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3574 MSIPACKAGE *package = param;
3575 LPWSTR link_file, deformated, path;
3576 LPCWSTR component, target;
3578 IShellLinkW *sl = NULL;
3579 IPersistFile *pf = NULL;
3582 component = MSI_RecordGetString(row, 4);
3583 comp = msi_get_loaded_component(package, component);
3585 return ERROR_SUCCESS;
3587 comp->Action = msi_get_component_action( package, comp );
3588 if (comp->Action != INSTALLSTATE_LOCAL)
3590 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3591 return ERROR_SUCCESS;
3593 msi_ui_actiondata( package, szCreateShortcuts, row );
3595 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3596 &IID_IShellLinkW, (LPVOID *) &sl );
3600 ERR("CLSID_ShellLink not available\n");
3604 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3607 ERR("QueryInterface(IID_IPersistFile) failed\n");
3611 target = MSI_RecordGetString(row, 5);
3612 if (strchrW(target, '['))
3614 deformat_string(package, target, &deformated);
3615 IShellLinkW_SetPath(sl,deformated);
3616 msi_free(deformated);
3620 FIXME("poorly handled shortcut format, advertised shortcut\n");
3621 IShellLinkW_SetPath(sl,comp->FullKeypath);
3624 if (!MSI_RecordIsNull(row,6))
3626 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3627 deformat_string(package, arguments, &deformated);
3628 IShellLinkW_SetArguments(sl,deformated);
3629 msi_free(deformated);
3632 if (!MSI_RecordIsNull(row,7))
3634 LPCWSTR description = MSI_RecordGetString(row, 7);
3635 IShellLinkW_SetDescription(sl, description);
3638 if (!MSI_RecordIsNull(row,8))
3639 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3641 if (!MSI_RecordIsNull(row,9))
3644 LPCWSTR icon = MSI_RecordGetString(row, 9);
3646 path = msi_build_icon_path(package, icon);
3647 index = MSI_RecordGetInteger(row,10);
3649 /* no value means 0 */
3650 if (index == MSI_NULL_INTEGER)
3653 IShellLinkW_SetIconLocation(sl, path, index);
3657 if (!MSI_RecordIsNull(row,11))
3658 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3660 if (!MSI_RecordIsNull(row,12))
3662 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3663 full_path = msi_get_target_folder( package, wkdir );
3664 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3666 link_file = get_link_file(package, row);
3668 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3669 IPersistFile_Save(pf, link_file, FALSE);
3670 msi_free(link_file);
3674 IPersistFile_Release( pf );
3676 IShellLinkW_Release( sl );
3678 return ERROR_SUCCESS;
3681 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3683 static const WCHAR query[] = {
3684 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3685 '`','S','h','o','r','t','c','u','t','`',0};
3690 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3691 if (rc != ERROR_SUCCESS)
3692 return ERROR_SUCCESS;
3694 res = CoInitialize( NULL );
3696 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3697 msiobj_release(&view->hdr);
3699 if (SUCCEEDED(res)) CoUninitialize();
3703 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3705 MSIPACKAGE *package = param;
3710 component = MSI_RecordGetString( row, 4 );
3711 comp = msi_get_loaded_component( package, component );
3713 return ERROR_SUCCESS;
3715 comp->Action = msi_get_component_action( package, comp );
3716 if (comp->Action != INSTALLSTATE_ABSENT)
3718 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3719 return ERROR_SUCCESS;
3721 msi_ui_actiondata( package, szRemoveShortcuts, row );
3723 link_file = get_link_file( package, row );
3725 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3726 if (!DeleteFileW( link_file ))
3728 WARN("Failed to remove shortcut file %u\n", GetLastError());
3730 msi_free( link_file );
3732 return ERROR_SUCCESS;
3735 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3737 static const WCHAR query[] = {
3738 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3739 '`','S','h','o','r','t','c','u','t','`',0};
3743 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3744 if (rc != ERROR_SUCCESS)
3745 return ERROR_SUCCESS;
3747 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3748 msiobj_release( &view->hdr );
3752 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3754 MSIPACKAGE* package = param;
3762 FileName = MSI_RecordGetString(row,1);
3765 ERR("Unable to get FileName\n");
3766 return ERROR_SUCCESS;
3769 FilePath = msi_build_icon_path(package, FileName);
3771 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3773 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3774 FILE_ATTRIBUTE_NORMAL, NULL);
3776 if (the_file == INVALID_HANDLE_VALUE)
3778 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3780 return ERROR_SUCCESS;
3787 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3788 if (rc != ERROR_SUCCESS)
3790 ERR("Failed to get stream\n");
3791 CloseHandle(the_file);
3792 DeleteFileW(FilePath);
3795 WriteFile(the_file,buffer,sz,&write,NULL);
3796 } while (sz == 1024);
3799 CloseHandle(the_file);
3801 return ERROR_SUCCESS;
3804 static UINT msi_publish_icons(MSIPACKAGE *package)
3806 static const WCHAR query[]= {
3807 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3808 '`','I','c','o','n','`',0};
3812 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3813 if (r == ERROR_SUCCESS)
3815 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3816 msiobj_release(&view->hdr);
3817 if (r != ERROR_SUCCESS)
3820 return ERROR_SUCCESS;
3823 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3829 MSISOURCELISTINFO *info;
3831 r = RegCreateKeyW(hkey, szSourceList, &source);
3832 if (r != ERROR_SUCCESS)
3835 RegCloseKey(source);
3837 buffer = strrchrW(package->PackagePath, '\\') + 1;
3838 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3839 package->Context, MSICODE_PRODUCT,
3840 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3841 if (r != ERROR_SUCCESS)
3844 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3845 package->Context, MSICODE_PRODUCT,
3846 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3847 if (r != ERROR_SUCCESS)
3850 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3851 package->Context, MSICODE_PRODUCT,
3852 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3853 if (r != ERROR_SUCCESS)
3856 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3858 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3859 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3860 info->options, info->value);
3862 MsiSourceListSetInfoW(package->ProductCode, NULL,
3863 info->context, info->options,
3864 info->property, info->value);
3867 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3869 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3870 disk->context, disk->options,
3871 disk->disk_id, disk->volume_label, disk->disk_prompt);
3874 return ERROR_SUCCESS;
3877 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3879 MSIHANDLE hdb, suminfo;
3880 WCHAR guids[MAX_PATH];
3881 WCHAR packcode[SQUISH_GUID_SIZE];
3888 static const WCHAR szARPProductIcon[] =
3889 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3890 static const WCHAR szAssignment[] =
3891 {'A','s','s','i','g','n','m','e','n','t',0};
3892 static const WCHAR szAdvertiseFlags[] =
3893 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3894 static const WCHAR szClients[] =
3895 {'C','l','i','e','n','t','s',0};
3896 static const WCHAR szColon[] = {':',0};
3898 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3899 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3902 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3903 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3906 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3908 buffer = msi_dup_property(package->db, szARPProductIcon);
3911 LPWSTR path = msi_build_icon_path(package, buffer);
3912 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3917 buffer = msi_dup_property(package->db, szProductVersion);
3920 DWORD verdword = msi_version_str_to_dword(buffer);
3921 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3925 msi_reg_set_val_dword(hkey, szAssignment, 0);
3926 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3927 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3928 msi_reg_set_val_str(hkey, szClients, szColon);
3930 hdb = alloc_msihandle(&package->db->hdr);
3932 return ERROR_NOT_ENOUGH_MEMORY;
3934 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3935 MsiCloseHandle(hdb);
3936 if (r != ERROR_SUCCESS)
3940 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3941 NULL, guids, &size);
3942 if (r != ERROR_SUCCESS)
3945 ptr = strchrW(guids, ';');
3947 squash_guid(guids, packcode);
3948 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3951 MsiCloseHandle(suminfo);
3952 return ERROR_SUCCESS;
3955 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3960 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3962 upgrade = msi_dup_property(package->db, szUpgradeCode);
3964 return ERROR_SUCCESS;
3966 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3967 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3969 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3971 if (r != ERROR_SUCCESS)
3973 WARN("failed to open upgrade code key\n");
3975 return ERROR_SUCCESS;
3977 squash_guid(package->ProductCode, squashed_pc);
3978 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3981 return ERROR_SUCCESS;
3984 static BOOL msi_check_publish(MSIPACKAGE *package)
3986 MSIFEATURE *feature;
3988 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3990 feature->Action = msi_get_feature_action( package, feature );
3991 if (feature->Action == INSTALLSTATE_LOCAL)
3998 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4000 MSIFEATURE *feature;
4002 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4004 feature->Action = msi_get_feature_action( package, feature );
4005 if (feature->Action != INSTALLSTATE_ABSENT)
4012 static UINT msi_publish_patches( MSIPACKAGE *package )
4014 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4015 WCHAR patch_squashed[GUID_SIZE];
4016 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4018 MSIPATCHINFO *patch;
4020 WCHAR *p, *all_patches = NULL;
4023 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4024 if (r != ERROR_SUCCESS)
4025 return ERROR_FUNCTION_FAILED;
4027 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4028 if (res != ERROR_SUCCESS)
4030 r = ERROR_FUNCTION_FAILED;
4034 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4035 if (r != ERROR_SUCCESS)
4038 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4040 squash_guid( patch->patchcode, patch_squashed );
4041 len += strlenW( patch_squashed ) + 1;
4044 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4048 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4052 squash_guid( patch->patchcode, p );
4053 p += strlenW( p ) + 1;
4055 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4056 (const BYTE *)patch->transforms,
4057 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4058 if (res != ERROR_SUCCESS)
4061 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4062 if (r != ERROR_SUCCESS)
4065 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4066 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4067 RegCloseKey( patch_key );
4068 if (res != ERROR_SUCCESS)
4071 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4073 res = GetLastError();
4074 ERR("Unable to copy patch package %d\n", res);
4077 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4078 if (res != ERROR_SUCCESS)
4081 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4082 RegCloseKey( patch_key );
4083 if (res != ERROR_SUCCESS)
4087 all_patches[len] = 0;
4088 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4089 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4090 if (res != ERROR_SUCCESS)
4093 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4094 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4095 if (res != ERROR_SUCCESS)
4096 r = ERROR_FUNCTION_FAILED;
4099 RegCloseKey( product_patches_key );
4100 RegCloseKey( patches_key );
4101 RegCloseKey( product_key );
4102 msi_free( all_patches );
4106 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4109 HKEY hukey = NULL, hudkey = NULL;
4112 if (!list_empty(&package->patches))
4114 rc = msi_publish_patches(package);
4115 if (rc != ERROR_SUCCESS)
4119 /* FIXME: also need to publish if the product is in advertise mode */
4120 if (!msi_check_publish(package))
4121 return ERROR_SUCCESS;
4123 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4125 if (rc != ERROR_SUCCESS)
4128 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4129 NULL, &hudkey, TRUE);
4130 if (rc != ERROR_SUCCESS)
4133 rc = msi_publish_upgrade_code(package);
4134 if (rc != ERROR_SUCCESS)
4137 rc = msi_publish_product_properties(package, hukey);
4138 if (rc != ERROR_SUCCESS)
4141 rc = msi_publish_sourcelist(package, hukey);
4142 if (rc != ERROR_SUCCESS)
4145 rc = msi_publish_icons(package);
4148 uirow = MSI_CreateRecord( 1 );
4149 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4150 msi_ui_actiondata( package, szPublishProduct, uirow );
4151 msiobj_release( &uirow->hdr );
4154 RegCloseKey(hudkey);
4158 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4160 WCHAR *filename, *ptr, *folder, *ret;
4161 const WCHAR *dirprop;
4163 filename = msi_dup_record_field( row, 2 );
4164 if (filename && (ptr = strchrW( filename, '|' )))
4169 dirprop = MSI_RecordGetString( row, 3 );
4172 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4173 if (!folder) folder = msi_dup_property( package->db, dirprop );
4176 folder = msi_dup_property( package->db, szWindowsFolder );
4180 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4181 msi_free( filename );
4185 ret = msi_build_directory_name( 2, folder, ptr );
4187 msi_free( filename );
4192 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4194 MSIPACKAGE *package = param;
4195 LPCWSTR component, section, key, value, identifier;
4196 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4201 component = MSI_RecordGetString(row, 8);
4202 comp = msi_get_loaded_component(package,component);
4204 return ERROR_SUCCESS;
4206 comp->Action = msi_get_component_action( package, comp );
4207 if (comp->Action != INSTALLSTATE_LOCAL)
4209 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4210 return ERROR_SUCCESS;
4213 identifier = MSI_RecordGetString(row,1);
4214 section = MSI_RecordGetString(row,4);
4215 key = MSI_RecordGetString(row,5);
4216 value = MSI_RecordGetString(row,6);
4217 action = MSI_RecordGetInteger(row,7);
4219 deformat_string(package,section,&deformated_section);
4220 deformat_string(package,key,&deformated_key);
4221 deformat_string(package,value,&deformated_value);
4223 fullname = get_ini_file_name(package, row);
4227 TRACE("Adding value %s to section %s in %s\n",
4228 debugstr_w(deformated_key), debugstr_w(deformated_section),
4229 debugstr_w(fullname));
4230 WritePrivateProfileStringW(deformated_section, deformated_key,
4231 deformated_value, fullname);
4233 else if (action == 1)
4236 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4237 returned, 10, fullname);
4238 if (returned[0] == 0)
4240 TRACE("Adding value %s to section %s in %s\n",
4241 debugstr_w(deformated_key), debugstr_w(deformated_section),
4242 debugstr_w(fullname));
4244 WritePrivateProfileStringW(deformated_section, deformated_key,
4245 deformated_value, fullname);
4248 else if (action == 3)
4249 FIXME("Append to existing section not yet implemented\n");
4251 uirow = MSI_CreateRecord(4);
4252 MSI_RecordSetStringW(uirow,1,identifier);
4253 MSI_RecordSetStringW(uirow,2,deformated_section);
4254 MSI_RecordSetStringW(uirow,3,deformated_key);
4255 MSI_RecordSetStringW(uirow,4,deformated_value);
4256 msi_ui_actiondata( package, szWriteIniValues, uirow );
4257 msiobj_release( &uirow->hdr );
4260 msi_free(deformated_key);
4261 msi_free(deformated_value);
4262 msi_free(deformated_section);
4263 return ERROR_SUCCESS;
4266 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4268 static const WCHAR query[] = {
4269 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4270 '`','I','n','i','F','i','l','e','`',0};
4274 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4275 if (rc != ERROR_SUCCESS)
4276 return ERROR_SUCCESS;
4278 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4279 msiobj_release(&view->hdr);
4283 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4285 MSIPACKAGE *package = param;
4286 LPCWSTR component, section, key, value, identifier;
4287 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4292 component = MSI_RecordGetString( row, 8 );
4293 comp = msi_get_loaded_component( package, component );
4295 return ERROR_SUCCESS;
4297 comp->Action = msi_get_component_action( package, comp );
4298 if (comp->Action != INSTALLSTATE_ABSENT)
4300 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4301 return ERROR_SUCCESS;
4304 identifier = MSI_RecordGetString( row, 1 );
4305 section = MSI_RecordGetString( row, 4 );
4306 key = MSI_RecordGetString( row, 5 );
4307 value = MSI_RecordGetString( row, 6 );
4308 action = MSI_RecordGetInteger( row, 7 );
4310 deformat_string( package, section, &deformated_section );
4311 deformat_string( package, key, &deformated_key );
4312 deformat_string( package, value, &deformated_value );
4314 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4316 filename = get_ini_file_name( package, row );
4318 TRACE("Removing key %s from section %s in %s\n",
4319 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4321 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4323 WARN("Unable to remove key %u\n", GetLastError());
4325 msi_free( filename );
4328 FIXME("Unsupported action %d\n", action);
4331 uirow = MSI_CreateRecord( 4 );
4332 MSI_RecordSetStringW( uirow, 1, identifier );
4333 MSI_RecordSetStringW( uirow, 2, deformated_section );
4334 MSI_RecordSetStringW( uirow, 3, deformated_key );
4335 MSI_RecordSetStringW( uirow, 4, deformated_value );
4336 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4337 msiobj_release( &uirow->hdr );
4339 msi_free( deformated_key );
4340 msi_free( deformated_value );
4341 msi_free( deformated_section );
4342 return ERROR_SUCCESS;
4345 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4347 MSIPACKAGE *package = param;
4348 LPCWSTR component, section, key, value, identifier;
4349 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4354 component = MSI_RecordGetString( row, 8 );
4355 comp = msi_get_loaded_component( package, component );
4357 return ERROR_SUCCESS;
4359 comp->Action = msi_get_component_action( package, comp );
4360 if (comp->Action != INSTALLSTATE_LOCAL)
4362 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4363 return ERROR_SUCCESS;
4366 identifier = MSI_RecordGetString( row, 1 );
4367 section = MSI_RecordGetString( row, 4 );
4368 key = MSI_RecordGetString( row, 5 );
4369 value = MSI_RecordGetString( row, 6 );
4370 action = MSI_RecordGetInteger( row, 7 );
4372 deformat_string( package, section, &deformated_section );
4373 deformat_string( package, key, &deformated_key );
4374 deformat_string( package, value, &deformated_value );
4376 if (action == msidbIniFileActionRemoveLine)
4378 filename = get_ini_file_name( package, row );
4380 TRACE("Removing key %s from section %s in %s\n",
4381 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4383 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4385 WARN("Unable to remove key %u\n", GetLastError());
4387 msi_free( filename );
4390 FIXME("Unsupported action %d\n", action);
4392 uirow = MSI_CreateRecord( 4 );
4393 MSI_RecordSetStringW( uirow, 1, identifier );
4394 MSI_RecordSetStringW( uirow, 2, deformated_section );
4395 MSI_RecordSetStringW( uirow, 3, deformated_key );
4396 MSI_RecordSetStringW( uirow, 4, deformated_value );
4397 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4398 msiobj_release( &uirow->hdr );
4400 msi_free( deformated_key );
4401 msi_free( deformated_value );
4402 msi_free( deformated_section );
4403 return ERROR_SUCCESS;
4406 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4408 static const WCHAR query[] = {
4409 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4410 '`','I','n','i','F','i','l','e','`',0};
4411 static const WCHAR remove_query[] = {
4412 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4413 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4417 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4418 if (rc == ERROR_SUCCESS)
4420 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4421 msiobj_release( &view->hdr );
4422 if (rc != ERROR_SUCCESS)
4425 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4426 if (rc == ERROR_SUCCESS)
4428 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4429 msiobj_release( &view->hdr );
4430 if (rc != ERROR_SUCCESS)
4433 return ERROR_SUCCESS;
4436 static void register_dll( const WCHAR *dll, BOOL unregister )
4440 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4443 HRESULT (WINAPI *func_ptr)( void );
4444 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4446 func_ptr = (void *)GetProcAddress( hmod, func );
4449 HRESULT hr = func_ptr();
4451 WARN("failed to register dll 0x%08x\n", hr);
4454 WARN("entry point %s not found\n", func);
4455 FreeLibrary( hmod );
4458 WARN("failed to load library %u\n", GetLastError());
4461 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4463 MSIPACKAGE *package = param;
4468 filename = MSI_RecordGetString(row,1);
4469 file = msi_get_loaded_file( package, filename );
4472 WARN("unable to find file %s\n", debugstr_w(filename));
4473 return ERROR_SUCCESS;
4475 file->Component->Action = msi_get_component_action( package, file->Component );
4476 if (file->Component->Action != INSTALLSTATE_LOCAL)
4478 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4479 return ERROR_SUCCESS;
4482 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4483 register_dll( file->TargetPath, FALSE );
4485 uirow = MSI_CreateRecord( 2 );
4486 MSI_RecordSetStringW( uirow, 1, filename );
4487 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4488 msi_ui_actiondata( package, szSelfRegModules, uirow );
4489 msiobj_release( &uirow->hdr );
4491 return ERROR_SUCCESS;
4494 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4496 static const WCHAR query[] = {
4497 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4498 '`','S','e','l','f','R','e','g','`',0};
4502 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4503 if (rc != ERROR_SUCCESS)
4504 return ERROR_SUCCESS;
4506 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4507 msiobj_release(&view->hdr);
4511 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4513 MSIPACKAGE *package = param;
4518 filename = MSI_RecordGetString( row, 1 );
4519 file = msi_get_loaded_file( package, filename );
4522 WARN("unable to find file %s\n", debugstr_w(filename));
4523 return ERROR_SUCCESS;
4525 file->Component->Action = msi_get_component_action( package, file->Component );
4526 if (file->Component->Action != INSTALLSTATE_ABSENT)
4528 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4529 return ERROR_SUCCESS;
4532 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4533 register_dll( file->TargetPath, TRUE );
4535 uirow = MSI_CreateRecord( 2 );
4536 MSI_RecordSetStringW( uirow, 1, filename );
4537 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4538 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4539 msiobj_release( &uirow->hdr );
4541 return ERROR_SUCCESS;
4544 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4546 static const WCHAR query[] = {
4547 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4548 '`','S','e','l','f','R','e','g','`',0};
4552 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4553 if (rc != ERROR_SUCCESS)
4554 return ERROR_SUCCESS;
4556 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4557 msiobj_release( &view->hdr );
4561 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4563 MSIFEATURE *feature;
4565 HKEY hkey = NULL, userdata = NULL;
4567 if (!msi_check_publish(package))
4568 return ERROR_SUCCESS;
4570 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4572 if (rc != ERROR_SUCCESS)
4575 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4577 if (rc != ERROR_SUCCESS)
4580 /* here the guids are base 85 encoded */
4581 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4587 BOOL absent = FALSE;
4590 if (feature->Action != INSTALLSTATE_LOCAL &&
4591 feature->Action != INSTALLSTATE_SOURCE &&
4592 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4595 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4599 if (feature->Feature_Parent)
4600 size += strlenW( feature->Feature_Parent )+2;
4602 data = msi_alloc(size * sizeof(WCHAR));
4605 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4607 MSICOMPONENT* component = cl->component;
4611 if (component->ComponentId)
4613 TRACE("From %s\n",debugstr_w(component->ComponentId));
4614 CLSIDFromString(component->ComponentId, &clsid);
4615 encode_base85_guid(&clsid,buf);
4616 TRACE("to %s\n",debugstr_w(buf));
4621 if (feature->Feature_Parent)
4623 static const WCHAR sep[] = {'\2',0};
4625 strcatW(data,feature->Feature_Parent);
4628 msi_reg_set_val_str( userdata, feature->Feature, data );
4632 if (feature->Feature_Parent)
4633 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4636 size += sizeof(WCHAR);
4637 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4638 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4642 size += 2*sizeof(WCHAR);
4643 data = msi_alloc(size);
4646 if (feature->Feature_Parent)
4647 strcpyW( &data[1], feature->Feature_Parent );
4648 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4654 uirow = MSI_CreateRecord( 1 );
4655 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4656 msi_ui_actiondata( package, szPublishFeatures, uirow );
4657 msiobj_release( &uirow->hdr );
4658 /* FIXME: call msi_ui_progress? */
4663 RegCloseKey(userdata);
4667 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4673 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4675 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4677 if (r == ERROR_SUCCESS)
4679 RegDeleteValueW(hkey, feature->Feature);
4683 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4685 if (r == ERROR_SUCCESS)
4687 RegDeleteValueW(hkey, feature->Feature);
4691 uirow = MSI_CreateRecord( 1 );
4692 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4693 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4694 msiobj_release( &uirow->hdr );
4696 return ERROR_SUCCESS;
4699 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4701 MSIFEATURE *feature;
4703 if (!msi_check_unpublish(package))
4704 return ERROR_SUCCESS;
4706 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4708 msi_unpublish_feature(package, feature);
4711 return ERROR_SUCCESS;
4714 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4718 WCHAR date[9], *val, *buffer;
4719 const WCHAR *prop, *key;
4721 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4722 static const WCHAR modpath_fmt[] =
4723 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4724 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4725 static const WCHAR szModifyPath[] =
4726 {'M','o','d','i','f','y','P','a','t','h',0};
4727 static const WCHAR szUninstallString[] =
4728 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4729 static const WCHAR szEstimatedSize[] =
4730 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4731 static const WCHAR szDisplayVersion[] =
4732 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4733 static const WCHAR szInstallSource[] =
4734 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4735 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4736 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4737 static const WCHAR szAuthorizedCDFPrefix[] =
4738 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4739 static const WCHAR szARPCONTACT[] =
4740 {'A','R','P','C','O','N','T','A','C','T',0};
4741 static const WCHAR szContact[] =
4742 {'C','o','n','t','a','c','t',0};
4743 static const WCHAR szARPCOMMENTS[] =
4744 {'A','R','P','C','O','M','M','E','N','T','S',0};
4745 static const WCHAR szComments[] =
4746 {'C','o','m','m','e','n','t','s',0};
4747 static const WCHAR szProductName[] =
4748 {'P','r','o','d','u','c','t','N','a','m','e',0};
4749 static const WCHAR szDisplayName[] =
4750 {'D','i','s','p','l','a','y','N','a','m','e',0};
4751 static const WCHAR szARPHELPLINK[] =
4752 {'A','R','P','H','E','L','P','L','I','N','K',0};
4753 static const WCHAR szHelpLink[] =
4754 {'H','e','l','p','L','i','n','k',0};
4755 static const WCHAR szARPHELPTELEPHONE[] =
4756 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4757 static const WCHAR szHelpTelephone[] =
4758 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4759 static const WCHAR szARPINSTALLLOCATION[] =
4760 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4761 static const WCHAR szInstallLocation[] =
4762 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4763 static const WCHAR szManufacturer[] =
4764 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4765 static const WCHAR szPublisher[] =
4766 {'P','u','b','l','i','s','h','e','r',0};
4767 static const WCHAR szARPREADME[] =
4768 {'A','R','P','R','E','A','D','M','E',0};
4769 static const WCHAR szReadme[] =
4770 {'R','e','a','d','M','e',0};
4771 static const WCHAR szARPSIZE[] =
4772 {'A','R','P','S','I','Z','E',0};
4773 static const WCHAR szSize[] =
4774 {'S','i','z','e',0};
4775 static const WCHAR szARPURLINFOABOUT[] =
4776 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4777 static const WCHAR szURLInfoAbout[] =
4778 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4779 static const WCHAR szARPURLUPDATEINFO[] =
4780 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4781 static const WCHAR szURLUpdateInfo[] =
4782 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4783 static const WCHAR szARPSYSTEMCOMPONENT[] =
4784 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4785 static const WCHAR szSystemComponent[] =
4786 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4788 static const WCHAR *propval[] = {
4789 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4790 szARPCONTACT, szContact,
4791 szARPCOMMENTS, szComments,
4792 szProductName, szDisplayName,
4793 szARPHELPLINK, szHelpLink,
4794 szARPHELPTELEPHONE, szHelpTelephone,
4795 szARPINSTALLLOCATION, szInstallLocation,
4796 szSourceDir, szInstallSource,
4797 szManufacturer, szPublisher,
4798 szARPREADME, szReadme,
4800 szARPURLINFOABOUT, szURLInfoAbout,
4801 szARPURLUPDATEINFO, szURLUpdateInfo,
4804 const WCHAR **p = propval;
4810 val = msi_dup_property(package->db, prop);
4811 msi_reg_set_val_str(hkey, key, val);
4815 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4816 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4818 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4820 size = deformat_string(package, modpath_fmt, &buffer);
4821 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4822 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4825 /* FIXME: Write real Estimated Size when we have it */
4826 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4828 GetLocalTime(&systime);
4829 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4830 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4832 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4833 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4835 buffer = msi_dup_property(package->db, szProductVersion);
4836 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4839 DWORD verdword = msi_version_str_to_dword(buffer);
4841 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4842 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4843 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4847 return ERROR_SUCCESS;
4850 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4852 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4854 LPWSTR upgrade_code;
4855 HKEY hkey, props, upgrade_key;
4858 /* FIXME: also need to publish if the product is in advertise mode */
4859 if (!msi_check_publish(package))
4860 return ERROR_SUCCESS;
4862 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4863 if (rc != ERROR_SUCCESS)
4866 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4867 if (rc != ERROR_SUCCESS)
4870 rc = msi_publish_install_properties(package, hkey);
4871 if (rc != ERROR_SUCCESS)
4874 rc = msi_publish_install_properties(package, props);
4875 if (rc != ERROR_SUCCESS)
4878 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4881 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4882 if (rc == ERROR_SUCCESS)
4884 squash_guid( package->ProductCode, squashed_pc );
4885 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4886 RegCloseKey( upgrade_key );
4888 msi_free( upgrade_code );
4890 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4891 package->delete_on_close = FALSE;
4894 uirow = MSI_CreateRecord( 1 );
4895 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4896 msi_ui_actiondata( package, szRegisterProduct, uirow );
4897 msiobj_release( &uirow->hdr );
4900 return ERROR_SUCCESS;
4903 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4905 return execute_script(package,INSTALL_SCRIPT);
4908 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4910 MSIPACKAGE *package = param;
4911 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4912 WCHAR *p, *icon_path;
4914 if (!icon) return ERROR_SUCCESS;
4915 if ((icon_path = msi_build_icon_path( package, icon )))
4917 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4918 DeleteFileW( icon_path );
4919 if ((p = strrchrW( icon_path, '\\' )))
4922 RemoveDirectoryW( icon_path );
4924 msi_free( icon_path );
4926 return ERROR_SUCCESS;
4929 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4931 static const WCHAR query[]= {
4932 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4936 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4937 if (r == ERROR_SUCCESS)
4939 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4940 msiobj_release( &view->hdr );
4941 if (r != ERROR_SUCCESS)
4944 return ERROR_SUCCESS;
4947 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4949 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4950 WCHAR *upgrade, **features;
4951 BOOL full_uninstall = TRUE;
4952 MSIFEATURE *feature;
4953 MSIPATCHINFO *patch;
4956 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4958 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4960 features = msi_split_string( remove, ',' );
4961 for (i = 0; features && features[i]; i++)
4963 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4967 if (!full_uninstall)
4968 return ERROR_SUCCESS;
4970 MSIREG_DeleteProductKey(package->ProductCode);
4971 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4972 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4974 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4975 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4976 MSIREG_DeleteUserProductKey(package->ProductCode);
4977 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4979 upgrade = msi_dup_property(package->db, szUpgradeCode);
4982 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4983 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4987 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4989 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4990 if (!strcmpW( package->ProductCode, patch->products ))
4992 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
4993 patch->delete_on_close = TRUE;
4995 /* FIXME: remove local patch package if this is the last product */
4997 TRACE("removing local package %s\n", debugstr_w(package->localfile));
4998 package->delete_on_close = TRUE;
5000 msi_unpublish_icons( package );
5001 return ERROR_SUCCESS;
5004 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5009 /* turn off scheduling */
5010 package->script->CurrentlyScripting= FALSE;
5012 /* first do the same as an InstallExecute */
5013 rc = ACTION_InstallExecute(package);
5014 if (rc != ERROR_SUCCESS)
5017 /* then handle Commit Actions */
5018 rc = execute_script(package,COMMIT_SCRIPT);
5019 if (rc != ERROR_SUCCESS)
5022 remove = msi_dup_property(package->db, szRemove);
5023 rc = msi_unpublish_product(package, remove);
5028 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5030 static const WCHAR RunOnce[] = {
5031 'S','o','f','t','w','a','r','e','\\',
5032 'M','i','c','r','o','s','o','f','t','\\',
5033 'W','i','n','d','o','w','s','\\',
5034 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5035 'R','u','n','O','n','c','e',0};
5036 static const WCHAR InstallRunOnce[] = {
5037 'S','o','f','t','w','a','r','e','\\',
5038 'M','i','c','r','o','s','o','f','t','\\',
5039 'W','i','n','d','o','w','s','\\',
5040 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5041 'I','n','s','t','a','l','l','e','r','\\',
5042 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5044 static const WCHAR msiexec_fmt[] = {
5046 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5047 '\"','%','s','\"',0};
5048 static const WCHAR install_fmt[] = {
5049 '/','I',' ','\"','%','s','\"',' ',
5050 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5051 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5052 WCHAR buffer[256], sysdir[MAX_PATH];
5054 WCHAR squished_pc[100];
5056 squash_guid(package->ProductCode,squished_pc);
5058 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5059 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5060 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5063 msi_reg_set_val_str( hkey, squished_pc, buffer );
5066 TRACE("Reboot command %s\n",debugstr_w(buffer));
5068 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5069 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5071 msi_reg_set_val_str( hkey, squished_pc, buffer );
5074 return ERROR_INSTALL_SUSPEND;
5077 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5079 static const WCHAR query[] =
5080 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5081 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5082 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5083 MSIRECORD *rec, *row;
5089 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5091 rec = MSI_CreateRecord( count + 2 );
5092 str = MSI_RecordGetString( row, 1 );
5093 MSI_RecordSetStringW( rec, 0, str );
5094 msiobj_release( &row->hdr );
5095 MSI_RecordSetInteger( rec, 1, error );
5097 va_start( va, count );
5098 for (i = 0; i < count; i++)
5100 str = va_arg( va, const WCHAR *);
5101 MSI_RecordSetStringW( rec, i + 2, str );
5105 MSI_FormatRecordW( package, rec, NULL, &size );
5107 data = msi_alloc( size * sizeof(WCHAR) );
5108 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5110 msiobj_release( &rec->hdr );
5114 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5120 * We are currently doing what should be done here in the top level Install
5121 * however for Administrative and uninstalls this step will be needed
5123 if (!package->PackagePath)
5124 return ERROR_SUCCESS;
5126 msi_set_sourcedir_props(package, TRUE);
5128 attrib = GetFileAttributesW(package->db->path);
5129 if (attrib == INVALID_FILE_ATTRIBUTES)
5134 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5135 package->Context, MSICODE_PRODUCT,
5136 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5137 if (rc == ERROR_MORE_DATA)
5139 prompt = msi_alloc(size * sizeof(WCHAR));
5140 MsiSourceListGetInfoW(package->ProductCode, NULL,
5141 package->Context, MSICODE_PRODUCT,
5142 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5145 prompt = strdupW(package->db->path);
5147 msg = msi_build_error_string(package, 1302, 1, prompt);
5149 while(attrib == INVALID_FILE_ATTRIBUTES)
5151 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5155 return ERROR_INSTALL_USEREXIT;
5157 attrib = GetFileAttributesW(package->db->path);
5163 return ERROR_SUCCESS;
5168 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5171 LPWSTR buffer, productid = NULL;
5172 UINT i, rc = ERROR_SUCCESS;
5175 static const WCHAR szPropKeys[][80] =
5177 {'P','r','o','d','u','c','t','I','D',0},
5178 {'U','S','E','R','N','A','M','E',0},
5179 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5183 static const WCHAR szRegKeys[][80] =
5185 {'P','r','o','d','u','c','t','I','D',0},
5186 {'R','e','g','O','w','n','e','r',0},
5187 {'R','e','g','C','o','m','p','a','n','y',0},
5191 if (msi_check_unpublish(package))
5193 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5197 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5201 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5203 if (rc != ERROR_SUCCESS)
5206 for( i = 0; szPropKeys[i][0]; i++ )
5208 buffer = msi_dup_property( package->db, szPropKeys[i] );
5209 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5214 uirow = MSI_CreateRecord( 1 );
5215 MSI_RecordSetStringW( uirow, 1, productid );
5216 msi_ui_actiondata( package, szRegisterUser, uirow );
5217 msiobj_release( &uirow->hdr );
5219 msi_free(productid);
5225 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5229 package->script->InWhatSequence |= SEQUENCE_EXEC;
5230 rc = ACTION_ProcessExecSequence(package,FALSE);
5234 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5236 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5237 WCHAR productid_85[21], component_85[21], *ret;
5241 /* > is used if there is a component GUID and < if not. */
5243 productid_85[0] = 0;
5244 component_85[0] = 0;
5245 CLSIDFromString( package->ProductCode, &clsid );
5247 encode_base85_guid( &clsid, productid_85 );
5250 CLSIDFromString( component->ComponentId, &clsid );
5251 encode_base85_guid( &clsid, component_85 );
5254 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5255 debugstr_w(component_85));
5257 sz = 20 + strlenW( feature ) + 20 + 3;
5258 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5259 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5263 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5265 MSIPACKAGE *package = param;
5266 LPCWSTR compgroupid, component, feature, qualifier, text;
5267 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5276 feature = MSI_RecordGetString(rec, 5);
5277 feat = msi_get_loaded_feature(package, feature);
5279 return ERROR_SUCCESS;
5281 feat->Action = msi_get_feature_action( package, feat );
5282 if (feat->Action != INSTALLSTATE_LOCAL &&
5283 feat->Action != INSTALLSTATE_SOURCE &&
5284 feat->Action != INSTALLSTATE_ADVERTISED)
5286 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5287 return ERROR_SUCCESS;
5290 component = MSI_RecordGetString(rec, 3);
5291 comp = msi_get_loaded_component(package, component);
5293 return ERROR_SUCCESS;
5295 compgroupid = MSI_RecordGetString(rec,1);
5296 qualifier = MSI_RecordGetString(rec,2);
5298 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5299 if (rc != ERROR_SUCCESS)
5302 advertise = msi_create_component_advertise_string( package, comp, feature );
5303 text = MSI_RecordGetString( rec, 4 );
5306 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5307 strcpyW( p, advertise );
5309 msi_free( advertise );
5312 existing = msi_reg_get_val_str( hkey, qualifier );
5314 sz = strlenW( advertise ) + 1;
5317 for (p = existing; *p; p += len)
5319 len = strlenW( p ) + 1;
5320 if (strcmpW( advertise, p )) sz += len;
5323 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5325 rc = ERROR_OUTOFMEMORY;
5331 for (p = existing; *p; p += len)
5333 len = strlenW( p ) + 1;
5334 if (strcmpW( advertise, p ))
5336 memcpy( q, p, len * sizeof(WCHAR) );
5341 strcpyW( q, advertise );
5342 q[strlenW( q ) + 1] = 0;
5344 msi_reg_set_val_multi_str( hkey, qualifier, output );
5349 msi_free( advertise );
5350 msi_free( existing );
5353 uirow = MSI_CreateRecord( 2 );
5354 MSI_RecordSetStringW( uirow, 1, compgroupid );
5355 MSI_RecordSetStringW( uirow, 2, qualifier);
5356 msi_ui_actiondata( package, szPublishComponents, uirow );
5357 msiobj_release( &uirow->hdr );
5358 /* FIXME: call ui_progress? */
5364 * At present I am ignorning the advertised components part of this and only
5365 * focusing on the qualified component sets
5367 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5369 static const WCHAR query[] = {
5370 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5371 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5375 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5376 if (rc != ERROR_SUCCESS)
5377 return ERROR_SUCCESS;
5379 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5380 msiobj_release(&view->hdr);
5384 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5386 static const WCHAR szInstallerComponents[] = {
5387 'S','o','f','t','w','a','r','e','\\',
5388 'M','i','c','r','o','s','o','f','t','\\',
5389 'I','n','s','t','a','l','l','e','r','\\',
5390 'C','o','m','p','o','n','e','n','t','s','\\',0};
5392 MSIPACKAGE *package = param;
5393 LPCWSTR compgroupid, component, feature, qualifier;
5397 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5400 feature = MSI_RecordGetString( rec, 5 );
5401 feat = msi_get_loaded_feature( package, feature );
5403 return ERROR_SUCCESS;
5405 feat->Action = msi_get_feature_action( package, feat );
5406 if (feat->Action != INSTALLSTATE_ABSENT)
5408 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5409 return ERROR_SUCCESS;
5412 component = MSI_RecordGetString( rec, 3 );
5413 comp = msi_get_loaded_component( package, component );
5415 return ERROR_SUCCESS;
5417 compgroupid = MSI_RecordGetString( rec, 1 );
5418 qualifier = MSI_RecordGetString( rec, 2 );
5420 squash_guid( compgroupid, squashed );
5421 strcpyW( keypath, szInstallerComponents );
5422 strcatW( keypath, squashed );
5424 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5425 if (res != ERROR_SUCCESS)
5427 WARN("Unable to delete component key %d\n", res);
5430 uirow = MSI_CreateRecord( 2 );
5431 MSI_RecordSetStringW( uirow, 1, compgroupid );
5432 MSI_RecordSetStringW( uirow, 2, qualifier );
5433 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5434 msiobj_release( &uirow->hdr );
5436 return ERROR_SUCCESS;
5439 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5441 static const WCHAR query[] = {
5442 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5443 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5447 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5448 if (rc != ERROR_SUCCESS)
5449 return ERROR_SUCCESS;
5451 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5452 msiobj_release( &view->hdr );
5456 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5458 static const WCHAR query[] =
5459 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5460 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5461 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5462 MSIPACKAGE *package = param;
5463 MSICOMPONENT *component;
5466 SC_HANDLE hscm = NULL, service = NULL;
5468 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5469 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5470 DWORD serv_type, start_type, err_control;
5471 SERVICE_DESCRIPTIONW sd = {NULL};
5473 comp = MSI_RecordGetString( rec, 12 );
5474 component = msi_get_loaded_component( package, comp );
5477 WARN("service component not found\n");
5480 component->Action = msi_get_component_action( package, component );
5481 if (component->Action != INSTALLSTATE_LOCAL)
5483 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5486 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5489 ERR("Failed to open the SC Manager!\n");
5493 start_type = MSI_RecordGetInteger(rec, 5);
5494 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5497 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5498 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5499 serv_type = MSI_RecordGetInteger(rec, 4);
5500 err_control = MSI_RecordGetInteger(rec, 6);
5501 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5502 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5503 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5504 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5505 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5506 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5508 /* fetch the service path */
5509 row = MSI_QueryGetRecord(package->db, query, comp);
5512 ERR("Query failed\n");
5515 key = MSI_RecordGetString(row, 6);
5516 file = msi_get_loaded_file(package, key);
5517 msiobj_release(&row->hdr);
5520 ERR("Failed to load the service file\n");
5524 if (!args || !args[0]) image_path = file->TargetPath;
5527 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5528 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5529 return ERROR_OUTOFMEMORY;
5531 strcpyW(image_path, file->TargetPath);
5532 strcatW(image_path, szSpace);
5533 strcatW(image_path, args);
5535 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5536 start_type, err_control, image_path, load_order,
5537 NULL, depends, serv_name, pass);
5541 if (GetLastError() != ERROR_SERVICE_EXISTS)
5542 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5544 else if (sd.lpDescription)
5546 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5547 WARN("failed to set service description %u\n", GetLastError());
5550 if (image_path != file->TargetPath) msi_free(image_path);
5552 CloseServiceHandle(service);
5553 CloseServiceHandle(hscm);
5556 msi_free(sd.lpDescription);
5557 msi_free(load_order);
5558 msi_free(serv_name);
5563 return ERROR_SUCCESS;
5566 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5568 static const WCHAR query[] = {
5569 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5570 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5574 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5575 if (rc != ERROR_SUCCESS)
5576 return ERROR_SUCCESS;
5578 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5579 msiobj_release(&view->hdr);
5583 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5584 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5586 LPCWSTR *vector, *temp_vector;
5590 static const WCHAR separator[] = {'[','~',']',0};
5593 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5598 vector = msi_alloc(sizeof(LPWSTR));
5606 vector[*numargs - 1] = p;
5608 if ((q = strstrW(p, separator)))
5612 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5618 vector = temp_vector;
5627 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5629 MSIPACKAGE *package = param;
5632 SC_HANDLE scm = NULL, service = NULL;
5633 LPCWSTR component, *vector = NULL;
5634 LPWSTR name, args, display_name = NULL;
5635 DWORD event, numargs, len;
5636 UINT r = ERROR_FUNCTION_FAILED;
5638 component = MSI_RecordGetString(rec, 6);
5639 comp = msi_get_loaded_component(package, component);
5641 return ERROR_SUCCESS;
5643 comp->Action = msi_get_component_action( package, comp );
5644 if (comp->Action != INSTALLSTATE_LOCAL)
5646 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5647 return ERROR_SUCCESS;
5650 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5651 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5652 event = MSI_RecordGetInteger(rec, 3);
5654 if (!(event & msidbServiceControlEventStart))
5660 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5663 ERR("Failed to open the service control manager\n");
5668 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5669 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5671 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5672 GetServiceDisplayNameW( scm, name, display_name, &len );
5675 service = OpenServiceW(scm, name, SERVICE_START);
5678 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5682 vector = msi_service_args_to_vector(args, &numargs);
5684 if (!StartServiceW(service, numargs, vector) &&
5685 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5687 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5694 uirow = MSI_CreateRecord( 2 );
5695 MSI_RecordSetStringW( uirow, 1, display_name );
5696 MSI_RecordSetStringW( uirow, 2, name );
5697 msi_ui_actiondata( package, szStartServices, uirow );
5698 msiobj_release( &uirow->hdr );
5700 CloseServiceHandle(service);
5701 CloseServiceHandle(scm);
5706 msi_free(display_name);
5710 static UINT ACTION_StartServices( MSIPACKAGE *package )
5712 static const WCHAR query[] = {
5713 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5714 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5718 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5719 if (rc != ERROR_SUCCESS)
5720 return ERROR_SUCCESS;
5722 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5723 msiobj_release(&view->hdr);
5727 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5729 DWORD i, needed, count;
5730 ENUM_SERVICE_STATUSW *dependencies;
5734 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5735 0, &needed, &count))
5738 if (GetLastError() != ERROR_MORE_DATA)
5741 dependencies = msi_alloc(needed);
5745 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5746 needed, &needed, &count))
5749 for (i = 0; i < count; i++)
5751 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5752 SERVICE_STOP | SERVICE_QUERY_STATUS);
5756 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5763 msi_free(dependencies);
5767 static UINT stop_service( LPCWSTR name )
5769 SC_HANDLE scm = NULL, service = NULL;
5770 SERVICE_STATUS status;
5771 SERVICE_STATUS_PROCESS ssp;
5774 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5777 WARN("Failed to open the SCM: %d\n", GetLastError());
5781 service = OpenServiceW(scm, name,
5783 SERVICE_QUERY_STATUS |
5784 SERVICE_ENUMERATE_DEPENDENTS);
5787 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5791 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5792 sizeof(SERVICE_STATUS_PROCESS), &needed))
5794 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5798 if (ssp.dwCurrentState == SERVICE_STOPPED)
5801 stop_service_dependents(scm, service);
5803 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5804 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5807 CloseServiceHandle(service);
5808 CloseServiceHandle(scm);
5810 return ERROR_SUCCESS;
5813 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5815 MSIPACKAGE *package = param;
5819 LPWSTR name = NULL, display_name = NULL;
5823 event = MSI_RecordGetInteger( rec, 3 );
5824 if (!(event & msidbServiceControlEventStop))
5825 return ERROR_SUCCESS;
5827 component = MSI_RecordGetString( rec, 6 );
5828 comp = msi_get_loaded_component( package, component );
5830 return ERROR_SUCCESS;
5832 comp->Action = msi_get_component_action( package, comp );
5833 if (comp->Action != INSTALLSTATE_ABSENT)
5835 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5836 return ERROR_SUCCESS;
5839 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5842 ERR("Failed to open the service control manager\n");
5847 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5848 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5850 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5851 GetServiceDisplayNameW( scm, name, display_name, &len );
5853 CloseServiceHandle( scm );
5855 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5856 stop_service( name );
5859 uirow = MSI_CreateRecord( 2 );
5860 MSI_RecordSetStringW( uirow, 1, display_name );
5861 MSI_RecordSetStringW( uirow, 2, name );
5862 msi_ui_actiondata( package, szStopServices, uirow );
5863 msiobj_release( &uirow->hdr );
5866 msi_free( display_name );
5867 return ERROR_SUCCESS;
5870 static UINT ACTION_StopServices( MSIPACKAGE *package )
5872 static const WCHAR query[] = {
5873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5874 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5878 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5879 if (rc != ERROR_SUCCESS)
5880 return ERROR_SUCCESS;
5882 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5883 msiobj_release(&view->hdr);
5887 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5889 MSIPACKAGE *package = param;
5893 LPWSTR name = NULL, display_name = NULL;
5895 SC_HANDLE scm = NULL, service = NULL;
5897 event = MSI_RecordGetInteger( rec, 3 );
5898 if (!(event & msidbServiceControlEventDelete))
5899 return ERROR_SUCCESS;
5901 component = MSI_RecordGetString(rec, 6);
5902 comp = msi_get_loaded_component(package, component);
5904 return ERROR_SUCCESS;
5906 comp->Action = msi_get_component_action( package, comp );
5907 if (comp->Action != INSTALLSTATE_ABSENT)
5909 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5910 return ERROR_SUCCESS;
5913 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5914 stop_service( name );
5916 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5919 WARN("Failed to open the SCM: %d\n", GetLastError());
5924 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5925 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5927 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5928 GetServiceDisplayNameW( scm, name, display_name, &len );
5931 service = OpenServiceW( scm, name, DELETE );
5934 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5938 if (!DeleteService( service ))
5939 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5942 uirow = MSI_CreateRecord( 2 );
5943 MSI_RecordSetStringW( uirow, 1, display_name );
5944 MSI_RecordSetStringW( uirow, 2, name );
5945 msi_ui_actiondata( package, szDeleteServices, uirow );
5946 msiobj_release( &uirow->hdr );
5948 CloseServiceHandle( service );
5949 CloseServiceHandle( scm );
5951 msi_free( display_name );
5953 return ERROR_SUCCESS;
5956 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5958 static const WCHAR query[] = {
5959 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5960 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5964 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5965 if (rc != ERROR_SUCCESS)
5966 return ERROR_SUCCESS;
5968 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5969 msiobj_release( &view->hdr );
5973 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5975 MSIPACKAGE *package = param;
5976 LPWSTR driver, driver_path, ptr;
5977 WCHAR outpath[MAX_PATH];
5978 MSIFILE *driver_file = NULL, *setup_file = NULL;
5981 LPCWSTR desc, file_key, component;
5983 UINT r = ERROR_SUCCESS;
5985 static const WCHAR driver_fmt[] = {
5986 'D','r','i','v','e','r','=','%','s',0};
5987 static const WCHAR setup_fmt[] = {
5988 'S','e','t','u','p','=','%','s',0};
5989 static const WCHAR usage_fmt[] = {
5990 'F','i','l','e','U','s','a','g','e','=','1',0};
5992 component = MSI_RecordGetString( rec, 2 );
5993 comp = msi_get_loaded_component( package, component );
5995 return ERROR_SUCCESS;
5997 comp->Action = msi_get_component_action( package, comp );
5998 if (comp->Action != INSTALLSTATE_LOCAL)
6000 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6001 return ERROR_SUCCESS;
6003 desc = MSI_RecordGetString(rec, 3);
6005 file_key = MSI_RecordGetString( rec, 4 );
6006 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6008 file_key = MSI_RecordGetString( rec, 5 );
6009 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6013 ERR("ODBC Driver entry not found!\n");
6014 return ERROR_FUNCTION_FAILED;
6017 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6019 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6020 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6022 driver = msi_alloc(len * sizeof(WCHAR));
6024 return ERROR_OUTOFMEMORY;
6027 lstrcpyW(ptr, desc);
6028 ptr += lstrlenW(ptr) + 1;
6030 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6035 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6039 lstrcpyW(ptr, usage_fmt);
6040 ptr += lstrlenW(ptr) + 1;
6043 driver_path = strdupW(driver_file->TargetPath);
6044 ptr = strrchrW(driver_path, '\\');
6045 if (ptr) *ptr = '\0';
6047 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6048 NULL, ODBC_INSTALL_COMPLETE, &usage))
6050 ERR("Failed to install SQL driver!\n");
6051 r = ERROR_FUNCTION_FAILED;
6054 uirow = MSI_CreateRecord( 5 );
6055 MSI_RecordSetStringW( uirow, 1, desc );
6056 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6057 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6058 msi_ui_actiondata( package, szInstallODBC, uirow );
6059 msiobj_release( &uirow->hdr );
6062 msi_free(driver_path);
6067 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6069 MSIPACKAGE *package = param;
6070 LPWSTR translator, translator_path, ptr;
6071 WCHAR outpath[MAX_PATH];
6072 MSIFILE *translator_file = NULL, *setup_file = NULL;
6075 LPCWSTR desc, file_key, component;
6077 UINT r = ERROR_SUCCESS;
6079 static const WCHAR translator_fmt[] = {
6080 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6081 static const WCHAR setup_fmt[] = {
6082 'S','e','t','u','p','=','%','s',0};
6084 component = MSI_RecordGetString( rec, 2 );
6085 comp = msi_get_loaded_component( package, component );
6087 return ERROR_SUCCESS;
6089 comp->Action = msi_get_component_action( package, comp );
6090 if (comp->Action != INSTALLSTATE_LOCAL)
6092 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6093 return ERROR_SUCCESS;
6095 desc = MSI_RecordGetString(rec, 3);
6097 file_key = MSI_RecordGetString( rec, 4 );
6098 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6100 file_key = MSI_RecordGetString( rec, 5 );
6101 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6103 if (!translator_file)
6105 ERR("ODBC Translator entry not found!\n");
6106 return ERROR_FUNCTION_FAILED;
6109 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6111 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6113 translator = msi_alloc(len * sizeof(WCHAR));
6115 return ERROR_OUTOFMEMORY;
6118 lstrcpyW(ptr, desc);
6119 ptr += lstrlenW(ptr) + 1;
6121 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6126 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6131 translator_path = strdupW(translator_file->TargetPath);
6132 ptr = strrchrW(translator_path, '\\');
6133 if (ptr) *ptr = '\0';
6135 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6136 NULL, ODBC_INSTALL_COMPLETE, &usage))
6138 ERR("Failed to install SQL translator!\n");
6139 r = ERROR_FUNCTION_FAILED;
6142 uirow = MSI_CreateRecord( 5 );
6143 MSI_RecordSetStringW( uirow, 1, desc );
6144 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6145 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6146 msi_ui_actiondata( package, szInstallODBC, uirow );
6147 msiobj_release( &uirow->hdr );
6149 msi_free(translator);
6150 msi_free(translator_path);
6155 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6157 MSIPACKAGE *package = param;
6160 LPCWSTR desc, driver, component;
6161 WORD request = ODBC_ADD_SYS_DSN;
6164 UINT r = ERROR_SUCCESS;
6167 static const WCHAR attrs_fmt[] = {
6168 'D','S','N','=','%','s',0 };
6170 component = MSI_RecordGetString( rec, 2 );
6171 comp = msi_get_loaded_component( package, component );
6173 return ERROR_SUCCESS;
6175 comp->Action = msi_get_component_action( package, comp );
6176 if (comp->Action != INSTALLSTATE_LOCAL)
6178 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6179 return ERROR_SUCCESS;
6182 desc = MSI_RecordGetString(rec, 3);
6183 driver = MSI_RecordGetString(rec, 4);
6184 registration = MSI_RecordGetInteger(rec, 5);
6186 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6187 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6189 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6190 attrs = msi_alloc(len * sizeof(WCHAR));
6192 return ERROR_OUTOFMEMORY;
6194 len = sprintfW(attrs, attrs_fmt, desc);
6197 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6199 ERR("Failed to install SQL data source!\n");
6200 r = ERROR_FUNCTION_FAILED;
6203 uirow = MSI_CreateRecord( 5 );
6204 MSI_RecordSetStringW( uirow, 1, desc );
6205 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6206 MSI_RecordSetInteger( uirow, 3, request );
6207 msi_ui_actiondata( package, szInstallODBC, uirow );
6208 msiobj_release( &uirow->hdr );
6215 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6217 static const WCHAR driver_query[] = {
6218 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6219 'O','D','B','C','D','r','i','v','e','r',0};
6220 static const WCHAR translator_query[] = {
6221 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6222 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6223 static const WCHAR source_query[] = {
6224 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6225 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6229 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6230 if (rc == ERROR_SUCCESS)
6232 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6233 msiobj_release(&view->hdr);
6234 if (rc != ERROR_SUCCESS)
6237 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6238 if (rc == ERROR_SUCCESS)
6240 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6241 msiobj_release(&view->hdr);
6242 if (rc != ERROR_SUCCESS)
6245 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6246 if (rc == ERROR_SUCCESS)
6248 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6249 msiobj_release(&view->hdr);
6250 if (rc != ERROR_SUCCESS)
6253 return ERROR_SUCCESS;
6256 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6258 MSIPACKAGE *package = param;
6262 LPCWSTR desc, component;
6264 component = MSI_RecordGetString( rec, 2 );
6265 comp = msi_get_loaded_component( package, component );
6267 return ERROR_SUCCESS;
6269 comp->Action = msi_get_component_action( package, comp );
6270 if (comp->Action != INSTALLSTATE_ABSENT)
6272 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6273 return ERROR_SUCCESS;
6276 desc = MSI_RecordGetString( rec, 3 );
6277 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6279 WARN("Failed to remove ODBC driver\n");
6283 FIXME("Usage count reached 0\n");
6286 uirow = MSI_CreateRecord( 2 );
6287 MSI_RecordSetStringW( uirow, 1, desc );
6288 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6289 msi_ui_actiondata( package, szRemoveODBC, uirow );
6290 msiobj_release( &uirow->hdr );
6292 return ERROR_SUCCESS;
6295 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6297 MSIPACKAGE *package = param;
6301 LPCWSTR desc, component;
6303 component = MSI_RecordGetString( rec, 2 );
6304 comp = msi_get_loaded_component( package, component );
6306 return ERROR_SUCCESS;
6308 comp->Action = msi_get_component_action( package, comp );
6309 if (comp->Action != INSTALLSTATE_ABSENT)
6311 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6312 return ERROR_SUCCESS;
6315 desc = MSI_RecordGetString( rec, 3 );
6316 if (!SQLRemoveTranslatorW( desc, &usage ))
6318 WARN("Failed to remove ODBC translator\n");
6322 FIXME("Usage count reached 0\n");
6325 uirow = MSI_CreateRecord( 2 );
6326 MSI_RecordSetStringW( uirow, 1, desc );
6327 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6328 msi_ui_actiondata( package, szRemoveODBC, uirow );
6329 msiobj_release( &uirow->hdr );
6331 return ERROR_SUCCESS;
6334 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6336 MSIPACKAGE *package = param;
6340 LPCWSTR desc, driver, component;
6341 WORD request = ODBC_REMOVE_SYS_DSN;
6345 static const WCHAR attrs_fmt[] = {
6346 'D','S','N','=','%','s',0 };
6348 component = MSI_RecordGetString( rec, 2 );
6349 comp = msi_get_loaded_component( package, component );
6351 return ERROR_SUCCESS;
6353 comp->Action = msi_get_component_action( package, comp );
6354 if (comp->Action != INSTALLSTATE_ABSENT)
6356 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6357 return ERROR_SUCCESS;
6360 desc = MSI_RecordGetString( rec, 3 );
6361 driver = MSI_RecordGetString( rec, 4 );
6362 registration = MSI_RecordGetInteger( rec, 5 );
6364 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6365 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6367 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6368 attrs = msi_alloc( len * sizeof(WCHAR) );
6370 return ERROR_OUTOFMEMORY;
6372 FIXME("Use ODBCSourceAttribute table\n");
6374 len = sprintfW( attrs, attrs_fmt, desc );
6377 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6379 WARN("Failed to remove ODBC data source\n");
6383 uirow = MSI_CreateRecord( 3 );
6384 MSI_RecordSetStringW( uirow, 1, desc );
6385 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6386 MSI_RecordSetInteger( uirow, 3, request );
6387 msi_ui_actiondata( package, szRemoveODBC, uirow );
6388 msiobj_release( &uirow->hdr );
6390 return ERROR_SUCCESS;
6393 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6395 static const WCHAR driver_query[] = {
6396 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6397 'O','D','B','C','D','r','i','v','e','r',0};
6398 static const WCHAR translator_query[] = {
6399 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6400 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6401 static const WCHAR source_query[] = {
6402 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6403 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6407 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6408 if (rc == ERROR_SUCCESS)
6410 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6411 msiobj_release( &view->hdr );
6412 if (rc != ERROR_SUCCESS)
6415 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6416 if (rc == ERROR_SUCCESS)
6418 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6419 msiobj_release( &view->hdr );
6420 if (rc != ERROR_SUCCESS)
6423 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6424 if (rc == ERROR_SUCCESS)
6426 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6427 msiobj_release( &view->hdr );
6428 if (rc != ERROR_SUCCESS)
6431 return ERROR_SUCCESS;
6434 #define ENV_ACT_SETALWAYS 0x1
6435 #define ENV_ACT_SETABSENT 0x2
6436 #define ENV_ACT_REMOVE 0x4
6437 #define ENV_ACT_REMOVEMATCH 0x8
6439 #define ENV_MOD_MACHINE 0x20000000
6440 #define ENV_MOD_APPEND 0x40000000
6441 #define ENV_MOD_PREFIX 0x80000000
6442 #define ENV_MOD_MASK 0xC0000000
6444 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6446 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6448 LPCWSTR cptr = *name;
6450 static const WCHAR prefix[] = {'[','~',']',0};
6451 static const int prefix_len = 3;
6457 *flags |= ENV_ACT_SETALWAYS;
6458 else if (*cptr == '+')
6459 *flags |= ENV_ACT_SETABSENT;
6460 else if (*cptr == '-')
6461 *flags |= ENV_ACT_REMOVE;
6462 else if (*cptr == '!')
6463 *flags |= ENV_ACT_REMOVEMATCH;
6464 else if (*cptr == '*')
6465 *flags |= ENV_MOD_MACHINE;
6475 ERR("Missing environment variable\n");
6476 return ERROR_FUNCTION_FAILED;
6481 LPCWSTR ptr = *value;
6482 if (!strncmpW(ptr, prefix, prefix_len))
6484 if (ptr[prefix_len] == szSemiColon[0])
6486 *flags |= ENV_MOD_APPEND;
6487 *value += lstrlenW(prefix);
6494 else if (lstrlenW(*value) >= prefix_len)
6496 ptr += lstrlenW(ptr) - prefix_len;
6497 if (!strcmpW( ptr, prefix ))
6499 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6501 *flags |= ENV_MOD_PREFIX;
6502 /* the "[~]" will be removed by deformat_string */;
6512 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6513 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6514 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6515 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6517 ERR("Invalid flags: %08x\n", *flags);
6518 return ERROR_FUNCTION_FAILED;
6522 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6524 return ERROR_SUCCESS;
6527 static UINT open_env_key( DWORD flags, HKEY *key )
6529 static const WCHAR user_env[] =
6530 {'E','n','v','i','r','o','n','m','e','n','t',0};
6531 static const WCHAR machine_env[] =
6532 {'S','y','s','t','e','m','\\',
6533 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6534 'C','o','n','t','r','o','l','\\',
6535 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6536 'E','n','v','i','r','o','n','m','e','n','t',0};
6541 if (flags & ENV_MOD_MACHINE)
6544 root = HKEY_LOCAL_MACHINE;
6549 root = HKEY_CURRENT_USER;
6552 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6553 if (res != ERROR_SUCCESS)
6555 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6556 return ERROR_FUNCTION_FAILED;
6559 return ERROR_SUCCESS;
6562 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6564 MSIPACKAGE *package = param;
6565 LPCWSTR name, value, component;
6566 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6567 DWORD flags, type, size;
6574 component = MSI_RecordGetString(rec, 4);
6575 comp = msi_get_loaded_component(package, component);
6577 return ERROR_SUCCESS;
6579 comp->Action = msi_get_component_action( package, comp );
6580 if (comp->Action != INSTALLSTATE_LOCAL)
6582 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6583 return ERROR_SUCCESS;
6585 name = MSI_RecordGetString(rec, 2);
6586 value = MSI_RecordGetString(rec, 3);
6588 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6590 res = env_parse_flags(&name, &value, &flags);
6591 if (res != ERROR_SUCCESS || !value)
6594 if (value && !deformat_string(package, value, &deformatted))
6596 res = ERROR_OUTOFMEMORY;
6600 value = deformatted;
6602 res = open_env_key( flags, &env );
6603 if (res != ERROR_SUCCESS)
6606 if (flags & ENV_MOD_MACHINE)
6607 action |= 0x20000000;
6611 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6612 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6613 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6616 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6620 /* Nothing to do. */
6623 res = ERROR_SUCCESS;
6627 /* If we are appending but the string was empty, strip ; */
6628 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6630 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6631 newval = strdupW(value);
6634 res = ERROR_OUTOFMEMORY;
6642 /* Contrary to MSDN, +-variable to [~];path works */
6643 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6645 res = ERROR_SUCCESS;
6649 data = msi_alloc(size);
6653 return ERROR_OUTOFMEMORY;
6656 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6657 if (res != ERROR_SUCCESS)
6660 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6663 res = RegDeleteValueW(env, name);
6664 if (res != ERROR_SUCCESS)
6665 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6669 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6670 if (flags & ENV_MOD_MASK)
6674 if (flags & ENV_MOD_APPEND) multiplier++;
6675 if (flags & ENV_MOD_PREFIX) multiplier++;
6676 mod_size = lstrlenW(value) * multiplier;
6677 size += mod_size * sizeof(WCHAR);
6680 newval = msi_alloc(size);
6684 res = ERROR_OUTOFMEMORY;
6688 if (flags & ENV_MOD_PREFIX)
6690 lstrcpyW(newval, value);
6691 ptr = newval + lstrlenW(value);
6692 action |= 0x80000000;
6695 lstrcpyW(ptr, data);
6697 if (flags & ENV_MOD_APPEND)
6699 lstrcatW(newval, value);
6700 action |= 0x40000000;
6703 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6704 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6707 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6711 uirow = MSI_CreateRecord( 3 );
6712 MSI_RecordSetStringW( uirow, 1, name );
6713 MSI_RecordSetStringW( uirow, 2, newval );
6714 MSI_RecordSetInteger( uirow, 3, action );
6715 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6716 msiobj_release( &uirow->hdr );
6718 if (env) RegCloseKey(env);
6719 msi_free(deformatted);
6725 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6727 static const WCHAR query[] = {
6728 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6729 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6733 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6734 if (rc != ERROR_SUCCESS)
6735 return ERROR_SUCCESS;
6737 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6738 msiobj_release(&view->hdr);
6742 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6744 MSIPACKAGE *package = param;
6745 LPCWSTR name, value, component;
6746 LPWSTR deformatted = NULL;
6755 component = MSI_RecordGetString( rec, 4 );
6756 comp = msi_get_loaded_component( package, component );
6758 return ERROR_SUCCESS;
6760 comp->Action = msi_get_component_action( package, comp );
6761 if (comp->Action != INSTALLSTATE_ABSENT)
6763 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6764 return ERROR_SUCCESS;
6766 name = MSI_RecordGetString( rec, 2 );
6767 value = MSI_RecordGetString( rec, 3 );
6769 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6771 r = env_parse_flags( &name, &value, &flags );
6772 if (r != ERROR_SUCCESS)
6775 if (!(flags & ENV_ACT_REMOVE))
6777 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6778 return ERROR_SUCCESS;
6781 if (value && !deformat_string( package, value, &deformatted ))
6782 return ERROR_OUTOFMEMORY;
6784 value = deformatted;
6786 r = open_env_key( flags, &env );
6787 if (r != ERROR_SUCCESS)
6793 if (flags & ENV_MOD_MACHINE)
6794 action |= 0x20000000;
6796 TRACE("Removing %s\n", debugstr_w(name));
6798 res = RegDeleteValueW( env, name );
6799 if (res != ERROR_SUCCESS)
6801 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6806 uirow = MSI_CreateRecord( 3 );
6807 MSI_RecordSetStringW( uirow, 1, name );
6808 MSI_RecordSetStringW( uirow, 2, value );
6809 MSI_RecordSetInteger( uirow, 3, action );
6810 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6811 msiobj_release( &uirow->hdr );
6813 if (env) RegCloseKey( env );
6814 msi_free( deformatted );
6818 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6820 static const WCHAR query[] = {
6821 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6822 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6826 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6827 if (rc != ERROR_SUCCESS)
6828 return ERROR_SUCCESS;
6830 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6831 msiobj_release( &view->hdr );
6835 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6837 LPWSTR key, template, id;
6838 UINT r = ERROR_SUCCESS;
6840 id = msi_dup_property( package->db, szProductID );
6844 return ERROR_SUCCESS;
6846 template = msi_dup_property( package->db, szPIDTemplate );
6847 key = msi_dup_property( package->db, szPIDKEY );
6849 if (key && template)
6851 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6852 r = msi_set_property( package->db, szProductID, key );
6854 msi_free( template );
6859 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6862 package->need_reboot = 1;
6863 return ERROR_SUCCESS;
6866 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6868 static const WCHAR szAvailableFreeReg[] =
6869 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6871 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6873 TRACE("%p %d kilobytes\n", package, space);
6875 uirow = MSI_CreateRecord( 1 );
6876 MSI_RecordSetInteger( uirow, 1, space );
6877 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6878 msiobj_release( &uirow->hdr );
6880 return ERROR_SUCCESS;
6883 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6885 TRACE("%p\n", package);
6887 msi_set_property( package->db, szRollbackDisabled, szOne );
6888 return ERROR_SUCCESS;
6891 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6893 FIXME("%p\n", package);
6894 return ERROR_SUCCESS;
6897 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6899 static const WCHAR driver_query[] = {
6900 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6901 'O','D','B','C','D','r','i','v','e','r',0};
6902 static const WCHAR translator_query[] = {
6903 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6904 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6908 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6909 if (r == ERROR_SUCCESS)
6912 r = MSI_IterateRecords( view, &count, NULL, package );
6913 msiobj_release( &view->hdr );
6914 if (r != ERROR_SUCCESS)
6916 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6918 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6919 if (r == ERROR_SUCCESS)
6922 r = MSI_IterateRecords( view, &count, NULL, package );
6923 msiobj_release( &view->hdr );
6924 if (r != ERROR_SUCCESS)
6926 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6928 return ERROR_SUCCESS;
6931 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6933 MSIPACKAGE *package = param;
6934 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6937 if ((value = msi_dup_property( package->db, property )))
6939 FIXME("remove %s\n", debugstr_w(value));
6942 return ERROR_SUCCESS;
6945 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6947 static const WCHAR query[] = {
6948 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6949 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6953 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6954 if (r == ERROR_SUCCESS)
6956 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6957 msiobj_release( &view->hdr );
6958 if (r != ERROR_SUCCESS)
6961 return ERROR_SUCCESS;
6964 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6966 MSIPACKAGE *package = param;
6967 int attributes = MSI_RecordGetInteger( rec, 5 );
6969 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6971 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6972 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6973 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6974 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6978 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6980 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6981 if (r != ERROR_SUCCESS)
6982 return ERROR_SUCCESS;
6986 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6987 if (r != ERROR_SUCCESS)
6988 return ERROR_SUCCESS;
6990 RegCloseKey( hkey );
6992 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6993 debugstr_w(upgrade_code), debugstr_w(version_min),
6994 debugstr_w(version_max), debugstr_w(language));
6996 return ERROR_SUCCESS;
6999 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7001 static const WCHAR query[] = {
7002 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7003 'U','p','g','r','a','d','e',0};
7007 if (msi_get_property_int( package->db, szInstalled, 0 ))
7009 TRACE("product is installed, skipping action\n");
7010 return ERROR_SUCCESS;
7012 if (msi_get_property_int( package->db, szPreselected, 0 ))
7014 TRACE("Preselected property is set, not migrating feature states\n");
7015 return ERROR_SUCCESS;
7017 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7018 if (r == ERROR_SUCCESS)
7020 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7021 msiobj_release( &view->hdr );
7022 if (r != ERROR_SUCCESS)
7025 return ERROR_SUCCESS;
7028 static void bind_image( const char *filename, const char *path )
7030 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7032 WARN("failed to bind image %u\n", GetLastError());
7036 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7040 MSIPACKAGE *package = param;
7041 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7042 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7043 char *filenameA, *pathA;
7044 WCHAR *pathW, **path_list;
7046 if (!(file = msi_get_loaded_file( package, key )))
7048 WARN("file %s not found\n", debugstr_w(key));
7049 return ERROR_SUCCESS;
7051 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7052 path_list = msi_split_string( paths, ';' );
7053 if (!path_list) bind_image( filenameA, NULL );
7056 for (i = 0; path_list[i] && path_list[i][0]; i++)
7058 deformat_string( package, path_list[i], &pathW );
7059 if ((pathA = strdupWtoA( pathW )))
7061 bind_image( filenameA, pathA );
7067 msi_free( path_list );
7068 msi_free( filenameA );
7069 return ERROR_SUCCESS;
7072 static UINT ACTION_BindImage( MSIPACKAGE *package )
7074 static const WCHAR query[] = {
7075 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7076 'B','i','n','d','I','m','a','g','e',0};
7080 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7081 if (r == ERROR_SUCCESS)
7083 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7084 msiobj_release( &view->hdr );
7085 if (r != ERROR_SUCCESS)
7088 return ERROR_SUCCESS;
7091 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7093 static const WCHAR query[] = {
7094 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7099 r = MSI_OpenQuery( package->db, &view, query, table );
7100 if (r == ERROR_SUCCESS)
7102 r = MSI_IterateRecords(view, &count, NULL, package);
7103 msiobj_release(&view->hdr);
7104 if (r != ERROR_SUCCESS)
7107 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7108 return ERROR_SUCCESS;
7111 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7113 static const WCHAR table[] = {
7114 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7115 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7118 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7120 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7121 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7124 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7126 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7127 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7130 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7132 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7133 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7136 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7138 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7139 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7144 const WCHAR *action;
7145 UINT (*handler)(MSIPACKAGE *);
7146 const WCHAR *action_rollback;
7150 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7151 { szAppSearch, ACTION_AppSearch, NULL },
7152 { szBindImage, ACTION_BindImage, NULL },
7153 { szCCPSearch, ACTION_CCPSearch, NULL },
7154 { szCostFinalize, ACTION_CostFinalize, NULL },
7155 { szCostInitialize, ACTION_CostInitialize, NULL },
7156 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7157 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7158 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7159 { szDisableRollback, ACTION_DisableRollback, NULL },
7160 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7161 { szExecuteAction, ACTION_ExecuteAction, NULL },
7162 { szFileCost, ACTION_FileCost, NULL },
7163 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7164 { szForceReboot, ACTION_ForceReboot, NULL },
7165 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7166 { szInstallExecute, ACTION_InstallExecute, NULL },
7167 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7168 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7169 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7170 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7171 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7172 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7173 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7174 { szInstallValidate, ACTION_InstallValidate, NULL },
7175 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7176 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7177 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7178 { szMoveFiles, ACTION_MoveFiles, NULL },
7179 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7180 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7181 { szPatchFiles, ACTION_PatchFiles, NULL },
7182 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7183 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7184 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7185 { szPublishProduct, ACTION_PublishProduct, NULL },
7186 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7187 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7188 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7189 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7190 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7191 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7192 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7193 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7194 { szRegisterUser, ACTION_RegisterUser, NULL },
7195 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7196 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7197 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7198 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7199 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7200 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7201 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7202 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7203 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7204 { szResolveSource, ACTION_ResolveSource, NULL },
7205 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7206 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7207 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7208 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7209 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7210 { szStartServices, ACTION_StartServices, szStopServices },
7211 { szStopServices, ACTION_StopServices, szStartServices },
7212 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7213 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7214 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7215 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7216 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7217 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7218 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7219 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7220 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7221 { szValidateProductID, ACTION_ValidateProductID, NULL },
7222 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7223 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7224 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7225 { NULL, NULL, NULL }
7228 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7234 while (StandardActions[i].action != NULL)
7236 if (!strcmpW( StandardActions[i].action, action ))
7238 ui_actionstart( package, action );
7239 if (StandardActions[i].handler)
7241 ui_actioninfo( package, action, TRUE, 0 );
7242 *rc = StandardActions[i].handler( package );
7243 ui_actioninfo( package, action, FALSE, *rc );
7245 if (StandardActions[i].action_rollback && !package->need_rollback)
7247 TRACE("scheduling rollback action\n");
7248 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7253 FIXME("unhandled standard action %s\n", debugstr_w(action));
7254 *rc = ERROR_SUCCESS;
7264 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7266 UINT rc = ERROR_SUCCESS;
7269 TRACE("Performing action (%s)\n", debugstr_w(action));
7271 handled = ACTION_HandleStandardAction(package, action, &rc);
7274 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7278 WARN("unhandled msi action %s\n", debugstr_w(action));
7279 rc = ERROR_FUNCTION_NOT_CALLED;
7285 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7287 UINT rc = ERROR_SUCCESS;
7288 BOOL handled = FALSE;
7290 TRACE("Performing action (%s)\n", debugstr_w(action));
7292 handled = ACTION_HandleStandardAction(package, action, &rc);
7295 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7297 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7302 WARN("unhandled msi action %s\n", debugstr_w(action));
7303 rc = ERROR_FUNCTION_NOT_CALLED;
7309 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7311 UINT rc = ERROR_SUCCESS;
7314 static const WCHAR query[] =
7315 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7316 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7317 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7318 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7319 static const WCHAR ui_query[] =
7320 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7321 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7322 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7323 ' ', '=',' ','%','i',0};
7325 if (needs_ui_sequence(package))
7326 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7328 row = MSI_QueryGetRecord(package->db, query, seq);
7332 LPCWSTR action, cond;
7334 TRACE("Running the actions\n");
7336 /* check conditions */
7337 cond = MSI_RecordGetString(row, 2);
7339 /* this is a hack to skip errors in the condition code */
7340 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7342 msiobj_release(&row->hdr);
7343 return ERROR_SUCCESS;
7346 action = MSI_RecordGetString(row, 1);
7349 ERR("failed to fetch action\n");
7350 msiobj_release(&row->hdr);
7351 return ERROR_FUNCTION_FAILED;
7354 if (needs_ui_sequence(package))
7355 rc = ACTION_PerformUIAction(package, action, -1);
7357 rc = ACTION_PerformAction(package, action, -1);
7359 msiobj_release(&row->hdr);
7365 /****************************************************
7366 * TOP level entry points
7367 *****************************************************/
7369 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7370 LPCWSTR szCommandLine )
7374 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7375 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7376 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7378 msi_set_property( package->db, szAction, szInstall );
7380 package->script->InWhatSequence = SEQUENCE_INSTALL;
7387 dir = strdupW(szPackagePath);
7388 p = strrchrW(dir, '\\');
7392 file = szPackagePath + (p - dir);
7397 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7398 GetCurrentDirectoryW(MAX_PATH, dir);
7399 lstrcatW(dir, szBackSlash);
7400 file = szPackagePath;
7403 msi_free( package->PackagePath );
7404 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7405 if (!package->PackagePath)
7408 return ERROR_OUTOFMEMORY;
7411 lstrcpyW(package->PackagePath, dir);
7412 lstrcatW(package->PackagePath, file);
7415 msi_set_sourcedir_props(package, FALSE);
7418 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7419 if (rc != ERROR_SUCCESS)
7422 msi_apply_transforms( package );
7423 msi_apply_patches( package );
7425 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7427 TRACE("setting reinstall property\n");
7428 msi_set_property( package->db, szReinstall, szAll );
7431 /* properties may have been added by a transform */
7432 msi_clone_properties( package );
7434 msi_parse_command_line( package, szCommandLine, FALSE );
7435 msi_adjust_privilege_properties( package );
7436 msi_set_context( package );
7438 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7440 TRACE("disabling rollback\n");
7441 msi_set_property( package->db, szRollbackDisabled, szOne );
7444 if (needs_ui_sequence( package))
7446 package->script->InWhatSequence |= SEQUENCE_UI;
7447 rc = ACTION_ProcessUISequence(package);
7448 ui_exists = ui_sequence_exists(package);
7449 if (rc == ERROR_SUCCESS || !ui_exists)
7451 package->script->InWhatSequence |= SEQUENCE_EXEC;
7452 rc = ACTION_ProcessExecSequence(package, ui_exists);
7456 rc = ACTION_ProcessExecSequence(package, FALSE);
7458 package->script->CurrentlyScripting = FALSE;
7460 /* process the ending type action */
7461 if (rc == ERROR_SUCCESS)
7462 ACTION_PerformActionSequence(package, -1);
7463 else if (rc == ERROR_INSTALL_USEREXIT)
7464 ACTION_PerformActionSequence(package, -2);
7465 else if (rc == ERROR_INSTALL_SUSPEND)
7466 ACTION_PerformActionSequence(package, -4);
7469 ACTION_PerformActionSequence(package, -3);
7470 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7472 package->need_rollback = TRUE;
7476 /* finish up running custom actions */
7477 ACTION_FinishCustomActions(package);
7479 if (package->need_rollback)
7481 WARN("installation failed, running rollback script\n");
7482 execute_script( package, ROLLBACK_SCRIPT );
7485 if (rc == ERROR_SUCCESS && package->need_reboot)
7486 return ERROR_SUCCESS_REBOOT_REQUIRED;