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 = msi_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( 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( 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, '['))
3615 WCHAR *format_string, *p;
3617 if (!(p = strchrW( target, ']' ))) goto err;
3618 len = p - target + 1;
3619 format_string = msi_alloc( (len + 1) * sizeof(WCHAR) );
3620 memcpy( format_string, target, len * sizeof(WCHAR) );
3621 format_string[len] = 0;
3622 deformat_string( package, format_string, &deformated );
3623 msi_free( format_string );
3625 path = msi_alloc( (strlenW( deformated ) + strlenW( p + 1 ) + 2) * sizeof(WCHAR) );
3626 strcpyW( path, deformated );
3627 PathAddBackslashW( path );
3628 strcatW( path, p + 1 );
3629 TRACE("target path is %s\n", debugstr_w(path));
3631 IShellLinkW_SetPath( sl, path );
3632 msi_free( deformated );
3637 FIXME("poorly handled shortcut format, advertised shortcut\n");
3638 IShellLinkW_SetPath(sl,comp->FullKeypath);
3641 if (!MSI_RecordIsNull(row,6))
3643 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3644 deformat_string(package, arguments, &deformated);
3645 IShellLinkW_SetArguments(sl,deformated);
3646 msi_free(deformated);
3649 if (!MSI_RecordIsNull(row,7))
3651 LPCWSTR description = MSI_RecordGetString(row, 7);
3652 IShellLinkW_SetDescription(sl, description);
3655 if (!MSI_RecordIsNull(row,8))
3656 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3658 if (!MSI_RecordIsNull(row,9))
3661 LPCWSTR icon = MSI_RecordGetString(row, 9);
3663 path = msi_build_icon_path(package, icon);
3664 index = MSI_RecordGetInteger(row,10);
3666 /* no value means 0 */
3667 if (index == MSI_NULL_INTEGER)
3670 IShellLinkW_SetIconLocation(sl, path, index);
3674 if (!MSI_RecordIsNull(row,11))
3675 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3677 if (!MSI_RecordIsNull(row,12))
3679 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3680 full_path = msi_get_target_folder( package, wkdir );
3681 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3683 link_file = get_link_file(package, row);
3685 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3686 IPersistFile_Save(pf, link_file, FALSE);
3687 msi_free(link_file);
3691 IPersistFile_Release( pf );
3693 IShellLinkW_Release( sl );
3695 return ERROR_SUCCESS;
3698 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3700 static const WCHAR query[] = {
3701 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3702 '`','S','h','o','r','t','c','u','t','`',0};
3707 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3708 if (rc != ERROR_SUCCESS)
3709 return ERROR_SUCCESS;
3711 res = CoInitialize( NULL );
3713 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3714 msiobj_release(&view->hdr);
3716 if (SUCCEEDED(res)) CoUninitialize();
3720 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3722 MSIPACKAGE *package = param;
3727 component = MSI_RecordGetString( row, 4 );
3728 comp = msi_get_loaded_component( package, component );
3730 return ERROR_SUCCESS;
3732 comp->Action = msi_get_component_action( package, comp );
3733 if (comp->Action != INSTALLSTATE_ABSENT)
3735 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3736 return ERROR_SUCCESS;
3738 msi_ui_actiondata( package, szRemoveShortcuts, row );
3740 link_file = get_link_file( package, row );
3742 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3743 if (!DeleteFileW( link_file ))
3745 WARN("Failed to remove shortcut file %u\n", GetLastError());
3747 msi_free( link_file );
3749 return ERROR_SUCCESS;
3752 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3754 static const WCHAR query[] = {
3755 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3756 '`','S','h','o','r','t','c','u','t','`',0};
3760 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3761 if (rc != ERROR_SUCCESS)
3762 return ERROR_SUCCESS;
3764 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3765 msiobj_release( &view->hdr );
3769 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3771 MSIPACKAGE* package = param;
3779 FileName = MSI_RecordGetString(row,1);
3782 ERR("Unable to get FileName\n");
3783 return ERROR_SUCCESS;
3786 FilePath = msi_build_icon_path(package, FileName);
3788 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3790 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3791 FILE_ATTRIBUTE_NORMAL, NULL);
3793 if (the_file == INVALID_HANDLE_VALUE)
3795 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3797 return ERROR_SUCCESS;
3804 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3805 if (rc != ERROR_SUCCESS)
3807 ERR("Failed to get stream\n");
3808 CloseHandle(the_file);
3809 DeleteFileW(FilePath);
3812 WriteFile(the_file,buffer,sz,&write,NULL);
3813 } while (sz == 1024);
3816 CloseHandle(the_file);
3818 return ERROR_SUCCESS;
3821 static UINT msi_publish_icons(MSIPACKAGE *package)
3823 static const WCHAR query[]= {
3824 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3825 '`','I','c','o','n','`',0};
3829 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3830 if (r == ERROR_SUCCESS)
3832 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3833 msiobj_release(&view->hdr);
3834 if (r != ERROR_SUCCESS)
3837 return ERROR_SUCCESS;
3840 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3846 MSISOURCELISTINFO *info;
3848 r = RegCreateKeyW(hkey, szSourceList, &source);
3849 if (r != ERROR_SUCCESS)
3852 RegCloseKey(source);
3854 buffer = strrchrW(package->PackagePath, '\\') + 1;
3855 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3856 package->Context, MSICODE_PRODUCT,
3857 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3858 if (r != ERROR_SUCCESS)
3861 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3862 package->Context, MSICODE_PRODUCT,
3863 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3864 if (r != ERROR_SUCCESS)
3867 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3868 package->Context, MSICODE_PRODUCT,
3869 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3870 if (r != ERROR_SUCCESS)
3873 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3875 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3876 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3877 info->options, info->value);
3879 MsiSourceListSetInfoW(package->ProductCode, NULL,
3880 info->context, info->options,
3881 info->property, info->value);
3884 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3886 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3887 disk->context, disk->options,
3888 disk->disk_id, disk->volume_label, disk->disk_prompt);
3891 return ERROR_SUCCESS;
3894 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3896 MSIHANDLE hdb, suminfo;
3897 WCHAR guids[MAX_PATH];
3898 WCHAR packcode[SQUISH_GUID_SIZE];
3905 static const WCHAR szARPProductIcon[] =
3906 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3907 static const WCHAR szAssignment[] =
3908 {'A','s','s','i','g','n','m','e','n','t',0};
3909 static const WCHAR szAdvertiseFlags[] =
3910 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3911 static const WCHAR szClients[] =
3912 {'C','l','i','e','n','t','s',0};
3913 static const WCHAR szColon[] = {':',0};
3915 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3916 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3919 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3923 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3925 buffer = msi_dup_property(package->db, szARPProductIcon);
3928 LPWSTR path = msi_build_icon_path(package, buffer);
3929 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3934 buffer = msi_dup_property(package->db, szProductVersion);
3937 DWORD verdword = msi_version_str_to_dword(buffer);
3938 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3942 msi_reg_set_val_dword(hkey, szAssignment, 0);
3943 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3944 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3945 msi_reg_set_val_str(hkey, szClients, szColon);
3947 hdb = alloc_msihandle(&package->db->hdr);
3949 return ERROR_NOT_ENOUGH_MEMORY;
3951 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3952 MsiCloseHandle(hdb);
3953 if (r != ERROR_SUCCESS)
3957 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3958 NULL, guids, &size);
3959 if (r != ERROR_SUCCESS)
3962 ptr = strchrW(guids, ';');
3964 squash_guid(guids, packcode);
3965 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3968 MsiCloseHandle(suminfo);
3969 return ERROR_SUCCESS;
3972 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3977 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3979 upgrade = msi_dup_property(package->db, szUpgradeCode);
3981 return ERROR_SUCCESS;
3983 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3984 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3986 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3988 if (r != ERROR_SUCCESS)
3990 WARN("failed to open upgrade code key\n");
3992 return ERROR_SUCCESS;
3994 squash_guid(package->ProductCode, squashed_pc);
3995 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3998 return ERROR_SUCCESS;
4001 static BOOL msi_check_publish(MSIPACKAGE *package)
4003 MSIFEATURE *feature;
4005 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4007 feature->Action = msi_get_feature_action( package, feature );
4008 if (feature->Action == INSTALLSTATE_LOCAL)
4015 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4017 MSIFEATURE *feature;
4019 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4021 feature->Action = msi_get_feature_action( package, feature );
4022 if (feature->Action != INSTALLSTATE_ABSENT)
4029 static UINT msi_publish_patches( MSIPACKAGE *package )
4031 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4032 WCHAR patch_squashed[GUID_SIZE];
4033 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4035 MSIPATCHINFO *patch;
4037 WCHAR *p, *all_patches = NULL;
4040 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4041 if (r != ERROR_SUCCESS)
4042 return ERROR_FUNCTION_FAILED;
4044 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4045 if (res != ERROR_SUCCESS)
4047 r = ERROR_FUNCTION_FAILED;
4051 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4052 if (r != ERROR_SUCCESS)
4055 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4057 squash_guid( patch->patchcode, patch_squashed );
4058 len += strlenW( patch_squashed ) + 1;
4061 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4065 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4069 squash_guid( patch->patchcode, p );
4070 p += strlenW( p ) + 1;
4072 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4073 (const BYTE *)patch->transforms,
4074 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4075 if (res != ERROR_SUCCESS)
4078 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4079 if (r != ERROR_SUCCESS)
4082 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4083 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4084 RegCloseKey( patch_key );
4085 if (res != ERROR_SUCCESS)
4088 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4090 res = GetLastError();
4091 ERR("Unable to copy patch package %d\n", res);
4094 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4095 if (res != ERROR_SUCCESS)
4098 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4099 RegCloseKey( patch_key );
4100 if (res != ERROR_SUCCESS)
4104 all_patches[len] = 0;
4105 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4106 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4107 if (res != ERROR_SUCCESS)
4110 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4111 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4112 if (res != ERROR_SUCCESS)
4113 r = ERROR_FUNCTION_FAILED;
4116 RegCloseKey( product_patches_key );
4117 RegCloseKey( patches_key );
4118 RegCloseKey( product_key );
4119 msi_free( all_patches );
4123 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4126 HKEY hukey = NULL, hudkey = NULL;
4129 if (!list_empty(&package->patches))
4131 rc = msi_publish_patches(package);
4132 if (rc != ERROR_SUCCESS)
4136 /* FIXME: also need to publish if the product is in advertise mode */
4137 if (!msi_check_publish(package))
4138 return ERROR_SUCCESS;
4140 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4142 if (rc != ERROR_SUCCESS)
4145 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4146 NULL, &hudkey, TRUE);
4147 if (rc != ERROR_SUCCESS)
4150 rc = msi_publish_upgrade_code(package);
4151 if (rc != ERROR_SUCCESS)
4154 rc = msi_publish_product_properties(package, hukey);
4155 if (rc != ERROR_SUCCESS)
4158 rc = msi_publish_sourcelist(package, hukey);
4159 if (rc != ERROR_SUCCESS)
4162 rc = msi_publish_icons(package);
4165 uirow = MSI_CreateRecord( 1 );
4166 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4167 msi_ui_actiondata( package, szPublishProduct, uirow );
4168 msiobj_release( &uirow->hdr );
4171 RegCloseKey(hudkey);
4175 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4177 WCHAR *filename, *ptr, *folder, *ret;
4178 const WCHAR *dirprop;
4180 filename = msi_dup_record_field( row, 2 );
4181 if (filename && (ptr = strchrW( filename, '|' )))
4186 dirprop = MSI_RecordGetString( row, 3 );
4189 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4190 if (!folder) folder = msi_dup_property( package->db, dirprop );
4193 folder = msi_dup_property( package->db, szWindowsFolder );
4197 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4198 msi_free( filename );
4202 ret = msi_build_directory_name( 2, folder, ptr );
4204 msi_free( filename );
4209 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4211 MSIPACKAGE *package = param;
4212 LPCWSTR component, section, key, value, identifier;
4213 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4218 component = MSI_RecordGetString(row, 8);
4219 comp = msi_get_loaded_component(package,component);
4221 return ERROR_SUCCESS;
4223 comp->Action = msi_get_component_action( package, comp );
4224 if (comp->Action != INSTALLSTATE_LOCAL)
4226 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4227 return ERROR_SUCCESS;
4230 identifier = MSI_RecordGetString(row,1);
4231 section = MSI_RecordGetString(row,4);
4232 key = MSI_RecordGetString(row,5);
4233 value = MSI_RecordGetString(row,6);
4234 action = MSI_RecordGetInteger(row,7);
4236 deformat_string(package,section,&deformated_section);
4237 deformat_string(package,key,&deformated_key);
4238 deformat_string(package,value,&deformated_value);
4240 fullname = get_ini_file_name(package, row);
4244 TRACE("Adding value %s to section %s in %s\n",
4245 debugstr_w(deformated_key), debugstr_w(deformated_section),
4246 debugstr_w(fullname));
4247 WritePrivateProfileStringW(deformated_section, deformated_key,
4248 deformated_value, fullname);
4250 else if (action == 1)
4253 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4254 returned, 10, fullname);
4255 if (returned[0] == 0)
4257 TRACE("Adding value %s to section %s in %s\n",
4258 debugstr_w(deformated_key), debugstr_w(deformated_section),
4259 debugstr_w(fullname));
4261 WritePrivateProfileStringW(deformated_section, deformated_key,
4262 deformated_value, fullname);
4265 else if (action == 3)
4266 FIXME("Append to existing section not yet implemented\n");
4268 uirow = MSI_CreateRecord(4);
4269 MSI_RecordSetStringW(uirow,1,identifier);
4270 MSI_RecordSetStringW(uirow,2,deformated_section);
4271 MSI_RecordSetStringW(uirow,3,deformated_key);
4272 MSI_RecordSetStringW(uirow,4,deformated_value);
4273 msi_ui_actiondata( package, szWriteIniValues, uirow );
4274 msiobj_release( &uirow->hdr );
4277 msi_free(deformated_key);
4278 msi_free(deformated_value);
4279 msi_free(deformated_section);
4280 return ERROR_SUCCESS;
4283 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4285 static const WCHAR query[] = {
4286 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4287 '`','I','n','i','F','i','l','e','`',0};
4291 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4292 if (rc != ERROR_SUCCESS)
4293 return ERROR_SUCCESS;
4295 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4296 msiobj_release(&view->hdr);
4300 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4302 MSIPACKAGE *package = param;
4303 LPCWSTR component, section, key, value, identifier;
4304 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4309 component = MSI_RecordGetString( row, 8 );
4310 comp = msi_get_loaded_component( package, component );
4312 return ERROR_SUCCESS;
4314 comp->Action = msi_get_component_action( package, comp );
4315 if (comp->Action != INSTALLSTATE_ABSENT)
4317 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4318 return ERROR_SUCCESS;
4321 identifier = MSI_RecordGetString( row, 1 );
4322 section = MSI_RecordGetString( row, 4 );
4323 key = MSI_RecordGetString( row, 5 );
4324 value = MSI_RecordGetString( row, 6 );
4325 action = MSI_RecordGetInteger( row, 7 );
4327 deformat_string( package, section, &deformated_section );
4328 deformat_string( package, key, &deformated_key );
4329 deformat_string( package, value, &deformated_value );
4331 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4333 filename = get_ini_file_name( package, row );
4335 TRACE("Removing key %s from section %s in %s\n",
4336 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4338 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4340 WARN("Unable to remove key %u\n", GetLastError());
4342 msi_free( filename );
4345 FIXME("Unsupported action %d\n", action);
4348 uirow = MSI_CreateRecord( 4 );
4349 MSI_RecordSetStringW( uirow, 1, identifier );
4350 MSI_RecordSetStringW( uirow, 2, deformated_section );
4351 MSI_RecordSetStringW( uirow, 3, deformated_key );
4352 MSI_RecordSetStringW( uirow, 4, deformated_value );
4353 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4354 msiobj_release( &uirow->hdr );
4356 msi_free( deformated_key );
4357 msi_free( deformated_value );
4358 msi_free( deformated_section );
4359 return ERROR_SUCCESS;
4362 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4364 MSIPACKAGE *package = param;
4365 LPCWSTR component, section, key, value, identifier;
4366 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4371 component = MSI_RecordGetString( row, 8 );
4372 comp = msi_get_loaded_component( package, component );
4374 return ERROR_SUCCESS;
4376 comp->Action = msi_get_component_action( package, comp );
4377 if (comp->Action != INSTALLSTATE_LOCAL)
4379 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4380 return ERROR_SUCCESS;
4383 identifier = MSI_RecordGetString( row, 1 );
4384 section = MSI_RecordGetString( row, 4 );
4385 key = MSI_RecordGetString( row, 5 );
4386 value = MSI_RecordGetString( row, 6 );
4387 action = MSI_RecordGetInteger( row, 7 );
4389 deformat_string( package, section, &deformated_section );
4390 deformat_string( package, key, &deformated_key );
4391 deformat_string( package, value, &deformated_value );
4393 if (action == msidbIniFileActionRemoveLine)
4395 filename = get_ini_file_name( package, row );
4397 TRACE("Removing key %s from section %s in %s\n",
4398 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4400 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4402 WARN("Unable to remove key %u\n", GetLastError());
4404 msi_free( filename );
4407 FIXME("Unsupported action %d\n", action);
4409 uirow = MSI_CreateRecord( 4 );
4410 MSI_RecordSetStringW( uirow, 1, identifier );
4411 MSI_RecordSetStringW( uirow, 2, deformated_section );
4412 MSI_RecordSetStringW( uirow, 3, deformated_key );
4413 MSI_RecordSetStringW( uirow, 4, deformated_value );
4414 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4415 msiobj_release( &uirow->hdr );
4417 msi_free( deformated_key );
4418 msi_free( deformated_value );
4419 msi_free( deformated_section );
4420 return ERROR_SUCCESS;
4423 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4425 static const WCHAR query[] = {
4426 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4427 '`','I','n','i','F','i','l','e','`',0};
4428 static const WCHAR remove_query[] = {
4429 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4430 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4434 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4435 if (rc == ERROR_SUCCESS)
4437 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4438 msiobj_release( &view->hdr );
4439 if (rc != ERROR_SUCCESS)
4442 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4443 if (rc == ERROR_SUCCESS)
4445 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4446 msiobj_release( &view->hdr );
4447 if (rc != ERROR_SUCCESS)
4450 return ERROR_SUCCESS;
4453 static void register_dll( const WCHAR *dll, BOOL unregister )
4457 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4460 HRESULT (WINAPI *func_ptr)( void );
4461 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4463 func_ptr = (void *)GetProcAddress( hmod, func );
4466 HRESULT hr = func_ptr();
4468 WARN("failed to register dll 0x%08x\n", hr);
4471 WARN("entry point %s not found\n", func);
4472 FreeLibrary( hmod );
4475 WARN("failed to load library %u\n", GetLastError());
4478 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4480 MSIPACKAGE *package = param;
4485 filename = MSI_RecordGetString(row,1);
4486 file = msi_get_loaded_file( package, filename );
4489 WARN("unable to find file %s\n", debugstr_w(filename));
4490 return ERROR_SUCCESS;
4492 file->Component->Action = msi_get_component_action( package, file->Component );
4493 if (file->Component->Action != INSTALLSTATE_LOCAL)
4495 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4496 return ERROR_SUCCESS;
4499 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4500 register_dll( file->TargetPath, FALSE );
4502 uirow = MSI_CreateRecord( 2 );
4503 MSI_RecordSetStringW( uirow, 1, filename );
4504 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4505 msi_ui_actiondata( package, szSelfRegModules, uirow );
4506 msiobj_release( &uirow->hdr );
4508 return ERROR_SUCCESS;
4511 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4513 static const WCHAR query[] = {
4514 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4515 '`','S','e','l','f','R','e','g','`',0};
4519 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4520 if (rc != ERROR_SUCCESS)
4521 return ERROR_SUCCESS;
4523 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4524 msiobj_release(&view->hdr);
4528 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4530 MSIPACKAGE *package = param;
4535 filename = MSI_RecordGetString( row, 1 );
4536 file = msi_get_loaded_file( package, filename );
4539 WARN("unable to find file %s\n", debugstr_w(filename));
4540 return ERROR_SUCCESS;
4542 file->Component->Action = msi_get_component_action( package, file->Component );
4543 if (file->Component->Action != INSTALLSTATE_ABSENT)
4545 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4546 return ERROR_SUCCESS;
4549 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4550 register_dll( file->TargetPath, TRUE );
4552 uirow = MSI_CreateRecord( 2 );
4553 MSI_RecordSetStringW( uirow, 1, filename );
4554 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4555 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4556 msiobj_release( &uirow->hdr );
4558 return ERROR_SUCCESS;
4561 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4563 static const WCHAR query[] = {
4564 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4565 '`','S','e','l','f','R','e','g','`',0};
4569 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4570 if (rc != ERROR_SUCCESS)
4571 return ERROR_SUCCESS;
4573 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4574 msiobj_release( &view->hdr );
4578 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4580 MSIFEATURE *feature;
4582 HKEY hkey = NULL, userdata = NULL;
4584 if (!msi_check_publish(package))
4585 return ERROR_SUCCESS;
4587 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4589 if (rc != ERROR_SUCCESS)
4592 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4594 if (rc != ERROR_SUCCESS)
4597 /* here the guids are base 85 encoded */
4598 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4604 BOOL absent = FALSE;
4607 if (feature->Action != INSTALLSTATE_LOCAL &&
4608 feature->Action != INSTALLSTATE_SOURCE &&
4609 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4612 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4616 if (feature->Feature_Parent)
4617 size += strlenW( feature->Feature_Parent )+2;
4619 data = msi_alloc(size * sizeof(WCHAR));
4622 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4624 MSICOMPONENT* component = cl->component;
4628 if (component->ComponentId)
4630 TRACE("From %s\n",debugstr_w(component->ComponentId));
4631 CLSIDFromString(component->ComponentId, &clsid);
4632 encode_base85_guid(&clsid,buf);
4633 TRACE("to %s\n",debugstr_w(buf));
4638 if (feature->Feature_Parent)
4640 static const WCHAR sep[] = {'\2',0};
4642 strcatW(data,feature->Feature_Parent);
4645 msi_reg_set_val_str( userdata, feature->Feature, data );
4649 if (feature->Feature_Parent)
4650 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4653 size += sizeof(WCHAR);
4654 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4655 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4659 size += 2*sizeof(WCHAR);
4660 data = msi_alloc(size);
4663 if (feature->Feature_Parent)
4664 strcpyW( &data[1], feature->Feature_Parent );
4665 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4671 uirow = MSI_CreateRecord( 1 );
4672 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4673 msi_ui_actiondata( package, szPublishFeatures, uirow );
4674 msiobj_release( &uirow->hdr );
4675 /* FIXME: call msi_ui_progress? */
4680 RegCloseKey(userdata);
4684 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4690 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4692 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4694 if (r == ERROR_SUCCESS)
4696 RegDeleteValueW(hkey, feature->Feature);
4700 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4702 if (r == ERROR_SUCCESS)
4704 RegDeleteValueW(hkey, feature->Feature);
4708 uirow = MSI_CreateRecord( 1 );
4709 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4710 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4711 msiobj_release( &uirow->hdr );
4713 return ERROR_SUCCESS;
4716 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4718 MSIFEATURE *feature;
4720 if (!msi_check_unpublish(package))
4721 return ERROR_SUCCESS;
4723 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4725 msi_unpublish_feature(package, feature);
4728 return ERROR_SUCCESS;
4731 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4735 WCHAR date[9], *val, *buffer;
4736 const WCHAR *prop, *key;
4738 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4739 static const WCHAR modpath_fmt[] =
4740 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4741 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4742 static const WCHAR szModifyPath[] =
4743 {'M','o','d','i','f','y','P','a','t','h',0};
4744 static const WCHAR szUninstallString[] =
4745 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4746 static const WCHAR szEstimatedSize[] =
4747 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4748 static const WCHAR szDisplayVersion[] =
4749 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4750 static const WCHAR szInstallSource[] =
4751 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4752 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4753 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4754 static const WCHAR szAuthorizedCDFPrefix[] =
4755 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4756 static const WCHAR szARPCONTACT[] =
4757 {'A','R','P','C','O','N','T','A','C','T',0};
4758 static const WCHAR szContact[] =
4759 {'C','o','n','t','a','c','t',0};
4760 static const WCHAR szARPCOMMENTS[] =
4761 {'A','R','P','C','O','M','M','E','N','T','S',0};
4762 static const WCHAR szComments[] =
4763 {'C','o','m','m','e','n','t','s',0};
4764 static const WCHAR szProductName[] =
4765 {'P','r','o','d','u','c','t','N','a','m','e',0};
4766 static const WCHAR szDisplayName[] =
4767 {'D','i','s','p','l','a','y','N','a','m','e',0};
4768 static const WCHAR szARPHELPLINK[] =
4769 {'A','R','P','H','E','L','P','L','I','N','K',0};
4770 static const WCHAR szHelpLink[] =
4771 {'H','e','l','p','L','i','n','k',0};
4772 static const WCHAR szARPHELPTELEPHONE[] =
4773 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4774 static const WCHAR szHelpTelephone[] =
4775 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4776 static const WCHAR szARPINSTALLLOCATION[] =
4777 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4778 static const WCHAR szInstallLocation[] =
4779 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4780 static const WCHAR szManufacturer[] =
4781 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4782 static const WCHAR szPublisher[] =
4783 {'P','u','b','l','i','s','h','e','r',0};
4784 static const WCHAR szARPREADME[] =
4785 {'A','R','P','R','E','A','D','M','E',0};
4786 static const WCHAR szReadme[] =
4787 {'R','e','a','d','M','e',0};
4788 static const WCHAR szARPSIZE[] =
4789 {'A','R','P','S','I','Z','E',0};
4790 static const WCHAR szSize[] =
4791 {'S','i','z','e',0};
4792 static const WCHAR szARPURLINFOABOUT[] =
4793 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4794 static const WCHAR szURLInfoAbout[] =
4795 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4796 static const WCHAR szARPURLUPDATEINFO[] =
4797 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4798 static const WCHAR szURLUpdateInfo[] =
4799 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4800 static const WCHAR szARPSYSTEMCOMPONENT[] =
4801 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4802 static const WCHAR szSystemComponent[] =
4803 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4805 static const WCHAR *propval[] = {
4806 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4807 szARPCONTACT, szContact,
4808 szARPCOMMENTS, szComments,
4809 szProductName, szDisplayName,
4810 szARPHELPLINK, szHelpLink,
4811 szARPHELPTELEPHONE, szHelpTelephone,
4812 szARPINSTALLLOCATION, szInstallLocation,
4813 szSourceDir, szInstallSource,
4814 szManufacturer, szPublisher,
4815 szARPREADME, szReadme,
4817 szARPURLINFOABOUT, szURLInfoAbout,
4818 szARPURLUPDATEINFO, szURLUpdateInfo,
4821 const WCHAR **p = propval;
4827 val = msi_dup_property(package->db, prop);
4828 msi_reg_set_val_str(hkey, key, val);
4832 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4833 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4835 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4837 size = deformat_string(package, modpath_fmt, &buffer);
4838 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4839 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4842 /* FIXME: Write real Estimated Size when we have it */
4843 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4845 GetLocalTime(&systime);
4846 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4847 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4849 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4850 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4852 buffer = msi_dup_property(package->db, szProductVersion);
4853 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4856 DWORD verdword = msi_version_str_to_dword(buffer);
4858 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4859 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4860 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4864 return ERROR_SUCCESS;
4867 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4869 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4871 LPWSTR upgrade_code;
4872 HKEY hkey, props, upgrade_key;
4875 /* FIXME: also need to publish if the product is in advertise mode */
4876 if (!msi_check_publish(package))
4877 return ERROR_SUCCESS;
4879 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4880 if (rc != ERROR_SUCCESS)
4883 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4884 if (rc != ERROR_SUCCESS)
4887 rc = msi_publish_install_properties(package, hkey);
4888 if (rc != ERROR_SUCCESS)
4891 rc = msi_publish_install_properties(package, props);
4892 if (rc != ERROR_SUCCESS)
4895 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4898 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4899 if (rc == ERROR_SUCCESS)
4901 squash_guid( package->ProductCode, squashed_pc );
4902 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4903 RegCloseKey( upgrade_key );
4905 msi_free( upgrade_code );
4907 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4908 package->delete_on_close = FALSE;
4911 uirow = MSI_CreateRecord( 1 );
4912 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4913 msi_ui_actiondata( package, szRegisterProduct, uirow );
4914 msiobj_release( &uirow->hdr );
4917 return ERROR_SUCCESS;
4920 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4922 return execute_script(package,INSTALL_SCRIPT);
4925 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4927 MSIPACKAGE *package = param;
4928 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4929 WCHAR *p, *icon_path;
4931 if (!icon) return ERROR_SUCCESS;
4932 if ((icon_path = msi_build_icon_path( package, icon )))
4934 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4935 DeleteFileW( icon_path );
4936 if ((p = strrchrW( icon_path, '\\' )))
4939 RemoveDirectoryW( icon_path );
4941 msi_free( icon_path );
4943 return ERROR_SUCCESS;
4946 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4948 static const WCHAR query[]= {
4949 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4953 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4954 if (r == ERROR_SUCCESS)
4956 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4957 msiobj_release( &view->hdr );
4958 if (r != ERROR_SUCCESS)
4961 return ERROR_SUCCESS;
4964 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4966 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4967 WCHAR *upgrade, **features;
4968 BOOL full_uninstall = TRUE;
4969 MSIFEATURE *feature;
4970 MSIPATCHINFO *patch;
4973 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4975 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4977 features = msi_split_string( remove, ',' );
4978 for (i = 0; features && features[i]; i++)
4980 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4984 if (!full_uninstall)
4985 return ERROR_SUCCESS;
4987 MSIREG_DeleteProductKey(package->ProductCode);
4988 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4989 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4991 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4992 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4993 MSIREG_DeleteUserProductKey(package->ProductCode);
4994 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4996 upgrade = msi_dup_property(package->db, szUpgradeCode);
4999 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5000 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5004 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5006 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5007 if (!strcmpW( package->ProductCode, patch->products ))
5009 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5010 patch->delete_on_close = TRUE;
5012 /* FIXME: remove local patch package if this is the last product */
5014 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5015 package->delete_on_close = TRUE;
5017 msi_unpublish_icons( package );
5018 return ERROR_SUCCESS;
5021 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5026 /* turn off scheduling */
5027 package->script->CurrentlyScripting= FALSE;
5029 /* first do the same as an InstallExecute */
5030 rc = ACTION_InstallExecute(package);
5031 if (rc != ERROR_SUCCESS)
5034 /* then handle Commit Actions */
5035 rc = execute_script(package,COMMIT_SCRIPT);
5036 if (rc != ERROR_SUCCESS)
5039 remove = msi_dup_property(package->db, szRemove);
5040 rc = msi_unpublish_product(package, remove);
5045 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5047 static const WCHAR RunOnce[] = {
5048 'S','o','f','t','w','a','r','e','\\',
5049 'M','i','c','r','o','s','o','f','t','\\',
5050 'W','i','n','d','o','w','s','\\',
5051 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5052 'R','u','n','O','n','c','e',0};
5053 static const WCHAR InstallRunOnce[] = {
5054 'S','o','f','t','w','a','r','e','\\',
5055 'M','i','c','r','o','s','o','f','t','\\',
5056 'W','i','n','d','o','w','s','\\',
5057 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5058 'I','n','s','t','a','l','l','e','r','\\',
5059 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5061 static const WCHAR msiexec_fmt[] = {
5063 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5064 '\"','%','s','\"',0};
5065 static const WCHAR install_fmt[] = {
5066 '/','I',' ','\"','%','s','\"',' ',
5067 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5068 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5069 WCHAR buffer[256], sysdir[MAX_PATH];
5071 WCHAR squished_pc[100];
5073 squash_guid(package->ProductCode,squished_pc);
5075 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5076 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5077 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5080 msi_reg_set_val_str( hkey, squished_pc, buffer );
5083 TRACE("Reboot command %s\n",debugstr_w(buffer));
5085 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5086 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5088 msi_reg_set_val_str( hkey, squished_pc, buffer );
5091 return ERROR_INSTALL_SUSPEND;
5094 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5096 static const WCHAR query[] =
5097 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5098 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5099 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5100 MSIRECORD *rec, *row;
5106 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5108 rec = MSI_CreateRecord( count + 2 );
5109 str = MSI_RecordGetString( row, 1 );
5110 MSI_RecordSetStringW( rec, 0, str );
5111 msiobj_release( &row->hdr );
5112 MSI_RecordSetInteger( rec, 1, error );
5114 va_start( va, count );
5115 for (i = 0; i < count; i++)
5117 str = va_arg( va, const WCHAR *);
5118 MSI_RecordSetStringW( rec, i + 2, str );
5122 MSI_FormatRecordW( package, rec, NULL, &size );
5124 data = msi_alloc( size * sizeof(WCHAR) );
5125 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5127 msiobj_release( &rec->hdr );
5131 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5137 * We are currently doing what should be done here in the top level Install
5138 * however for Administrative and uninstalls this step will be needed
5140 if (!package->PackagePath)
5141 return ERROR_SUCCESS;
5143 msi_set_sourcedir_props(package, TRUE);
5145 attrib = GetFileAttributesW(package->db->path);
5146 if (attrib == INVALID_FILE_ATTRIBUTES)
5151 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5152 package->Context, MSICODE_PRODUCT,
5153 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5154 if (rc == ERROR_MORE_DATA)
5156 prompt = msi_alloc(size * sizeof(WCHAR));
5157 MsiSourceListGetInfoW(package->ProductCode, NULL,
5158 package->Context, MSICODE_PRODUCT,
5159 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5162 prompt = strdupW(package->db->path);
5164 msg = msi_build_error_string(package, 1302, 1, prompt);
5166 while(attrib == INVALID_FILE_ATTRIBUTES)
5168 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5172 return ERROR_INSTALL_USEREXIT;
5174 attrib = GetFileAttributesW(package->db->path);
5180 return ERROR_SUCCESS;
5185 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5188 LPWSTR buffer, productid = NULL;
5189 UINT i, rc = ERROR_SUCCESS;
5192 static const WCHAR szPropKeys[][80] =
5194 {'P','r','o','d','u','c','t','I','D',0},
5195 {'U','S','E','R','N','A','M','E',0},
5196 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5200 static const WCHAR szRegKeys[][80] =
5202 {'P','r','o','d','u','c','t','I','D',0},
5203 {'R','e','g','O','w','n','e','r',0},
5204 {'R','e','g','C','o','m','p','a','n','y',0},
5208 if (msi_check_unpublish(package))
5210 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5214 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5218 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5220 if (rc != ERROR_SUCCESS)
5223 for( i = 0; szPropKeys[i][0]; i++ )
5225 buffer = msi_dup_property( package->db, szPropKeys[i] );
5226 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5231 uirow = MSI_CreateRecord( 1 );
5232 MSI_RecordSetStringW( uirow, 1, productid );
5233 msi_ui_actiondata( package, szRegisterUser, uirow );
5234 msiobj_release( &uirow->hdr );
5236 msi_free(productid);
5242 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5246 package->script->InWhatSequence |= SEQUENCE_EXEC;
5247 rc = ACTION_ProcessExecSequence(package,FALSE);
5251 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5253 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5254 WCHAR productid_85[21], component_85[21], *ret;
5258 /* > is used if there is a component GUID and < if not. */
5260 productid_85[0] = 0;
5261 component_85[0] = 0;
5262 CLSIDFromString( package->ProductCode, &clsid );
5264 encode_base85_guid( &clsid, productid_85 );
5267 CLSIDFromString( component->ComponentId, &clsid );
5268 encode_base85_guid( &clsid, component_85 );
5271 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5272 debugstr_w(component_85));
5274 sz = 20 + strlenW( feature ) + 20 + 3;
5275 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5276 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5280 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5282 MSIPACKAGE *package = param;
5283 LPCWSTR compgroupid, component, feature, qualifier, text;
5284 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5293 feature = MSI_RecordGetString(rec, 5);
5294 feat = msi_get_loaded_feature(package, feature);
5296 return ERROR_SUCCESS;
5298 feat->Action = msi_get_feature_action( package, feat );
5299 if (feat->Action != INSTALLSTATE_LOCAL &&
5300 feat->Action != INSTALLSTATE_SOURCE &&
5301 feat->Action != INSTALLSTATE_ADVERTISED)
5303 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5304 return ERROR_SUCCESS;
5307 component = MSI_RecordGetString(rec, 3);
5308 comp = msi_get_loaded_component(package, component);
5310 return ERROR_SUCCESS;
5312 compgroupid = MSI_RecordGetString(rec,1);
5313 qualifier = MSI_RecordGetString(rec,2);
5315 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5316 if (rc != ERROR_SUCCESS)
5319 advertise = msi_create_component_advertise_string( package, comp, feature );
5320 text = MSI_RecordGetString( rec, 4 );
5323 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5324 strcpyW( p, advertise );
5326 msi_free( advertise );
5329 existing = msi_reg_get_val_str( hkey, qualifier );
5331 sz = strlenW( advertise ) + 1;
5334 for (p = existing; *p; p += len)
5336 len = strlenW( p ) + 1;
5337 if (strcmpW( advertise, p )) sz += len;
5340 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5342 rc = ERROR_OUTOFMEMORY;
5348 for (p = existing; *p; p += len)
5350 len = strlenW( p ) + 1;
5351 if (strcmpW( advertise, p ))
5353 memcpy( q, p, len * sizeof(WCHAR) );
5358 strcpyW( q, advertise );
5359 q[strlenW( q ) + 1] = 0;
5361 msi_reg_set_val_multi_str( hkey, qualifier, output );
5366 msi_free( advertise );
5367 msi_free( existing );
5370 uirow = MSI_CreateRecord( 2 );
5371 MSI_RecordSetStringW( uirow, 1, compgroupid );
5372 MSI_RecordSetStringW( uirow, 2, qualifier);
5373 msi_ui_actiondata( package, szPublishComponents, uirow );
5374 msiobj_release( &uirow->hdr );
5375 /* FIXME: call ui_progress? */
5381 * At present I am ignorning the advertised components part of this and only
5382 * focusing on the qualified component sets
5384 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5386 static const WCHAR query[] = {
5387 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5388 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5392 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5393 if (rc != ERROR_SUCCESS)
5394 return ERROR_SUCCESS;
5396 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5397 msiobj_release(&view->hdr);
5401 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5403 static const WCHAR szInstallerComponents[] = {
5404 'S','o','f','t','w','a','r','e','\\',
5405 'M','i','c','r','o','s','o','f','t','\\',
5406 'I','n','s','t','a','l','l','e','r','\\',
5407 'C','o','m','p','o','n','e','n','t','s','\\',0};
5409 MSIPACKAGE *package = param;
5410 LPCWSTR compgroupid, component, feature, qualifier;
5414 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5417 feature = MSI_RecordGetString( rec, 5 );
5418 feat = msi_get_loaded_feature( package, feature );
5420 return ERROR_SUCCESS;
5422 feat->Action = msi_get_feature_action( package, feat );
5423 if (feat->Action != INSTALLSTATE_ABSENT)
5425 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5426 return ERROR_SUCCESS;
5429 component = MSI_RecordGetString( rec, 3 );
5430 comp = msi_get_loaded_component( package, component );
5432 return ERROR_SUCCESS;
5434 compgroupid = MSI_RecordGetString( rec, 1 );
5435 qualifier = MSI_RecordGetString( rec, 2 );
5437 squash_guid( compgroupid, squashed );
5438 strcpyW( keypath, szInstallerComponents );
5439 strcatW( keypath, squashed );
5441 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5442 if (res != ERROR_SUCCESS)
5444 WARN("Unable to delete component key %d\n", res);
5447 uirow = MSI_CreateRecord( 2 );
5448 MSI_RecordSetStringW( uirow, 1, compgroupid );
5449 MSI_RecordSetStringW( uirow, 2, qualifier );
5450 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5451 msiobj_release( &uirow->hdr );
5453 return ERROR_SUCCESS;
5456 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5458 static const WCHAR query[] = {
5459 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5460 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5464 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5465 if (rc != ERROR_SUCCESS)
5466 return ERROR_SUCCESS;
5468 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5469 msiobj_release( &view->hdr );
5473 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5475 static const WCHAR query[] =
5476 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5477 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5478 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5479 MSIPACKAGE *package = param;
5480 MSICOMPONENT *component;
5483 SC_HANDLE hscm = NULL, service = NULL;
5485 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5486 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5487 DWORD serv_type, start_type, err_control;
5488 SERVICE_DESCRIPTIONW sd = {NULL};
5490 comp = MSI_RecordGetString( rec, 12 );
5491 component = msi_get_loaded_component( package, comp );
5494 WARN("service component not found\n");
5497 component->Action = msi_get_component_action( package, component );
5498 if (component->Action != INSTALLSTATE_LOCAL)
5500 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5503 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5506 ERR("Failed to open the SC Manager!\n");
5510 start_type = MSI_RecordGetInteger(rec, 5);
5511 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5514 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5515 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5516 serv_type = MSI_RecordGetInteger(rec, 4);
5517 err_control = MSI_RecordGetInteger(rec, 6);
5518 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5519 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5520 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5521 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5522 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5523 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5525 /* fetch the service path */
5526 row = MSI_QueryGetRecord(package->db, query, comp);
5529 ERR("Query failed\n");
5532 key = MSI_RecordGetString(row, 6);
5533 file = msi_get_loaded_file(package, key);
5534 msiobj_release(&row->hdr);
5537 ERR("Failed to load the service file\n");
5541 if (!args || !args[0]) image_path = file->TargetPath;
5544 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5545 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5546 return ERROR_OUTOFMEMORY;
5548 strcpyW(image_path, file->TargetPath);
5549 strcatW(image_path, szSpace);
5550 strcatW(image_path, args);
5552 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5553 start_type, err_control, image_path, load_order,
5554 NULL, depends, serv_name, pass);
5558 if (GetLastError() != ERROR_SERVICE_EXISTS)
5559 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5561 else if (sd.lpDescription)
5563 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5564 WARN("failed to set service description %u\n", GetLastError());
5567 if (image_path != file->TargetPath) msi_free(image_path);
5569 CloseServiceHandle(service);
5570 CloseServiceHandle(hscm);
5573 msi_free(sd.lpDescription);
5574 msi_free(load_order);
5575 msi_free(serv_name);
5580 return ERROR_SUCCESS;
5583 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5585 static const WCHAR query[] = {
5586 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5587 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5591 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5592 if (rc != ERROR_SUCCESS)
5593 return ERROR_SUCCESS;
5595 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5596 msiobj_release(&view->hdr);
5600 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5601 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5603 LPCWSTR *vector, *temp_vector;
5607 static const WCHAR separator[] = {'[','~',']',0};
5610 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5615 vector = msi_alloc(sizeof(LPWSTR));
5623 vector[*numargs - 1] = p;
5625 if ((q = strstrW(p, separator)))
5629 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5635 vector = temp_vector;
5644 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5646 MSIPACKAGE *package = param;
5649 SC_HANDLE scm = NULL, service = NULL;
5650 LPCWSTR component, *vector = NULL;
5651 LPWSTR name, args, display_name = NULL;
5652 DWORD event, numargs, len;
5653 UINT r = ERROR_FUNCTION_FAILED;
5655 component = MSI_RecordGetString(rec, 6);
5656 comp = msi_get_loaded_component(package, component);
5658 return ERROR_SUCCESS;
5660 comp->Action = msi_get_component_action( package, comp );
5661 if (comp->Action != INSTALLSTATE_LOCAL)
5663 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5664 return ERROR_SUCCESS;
5667 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5668 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5669 event = MSI_RecordGetInteger(rec, 3);
5671 if (!(event & msidbServiceControlEventStart))
5677 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5680 ERR("Failed to open the service control manager\n");
5685 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5686 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5688 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5689 GetServiceDisplayNameW( scm, name, display_name, &len );
5692 service = OpenServiceW(scm, name, SERVICE_START);
5695 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5699 vector = msi_service_args_to_vector(args, &numargs);
5701 if (!StartServiceW(service, numargs, vector) &&
5702 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5704 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5711 uirow = MSI_CreateRecord( 2 );
5712 MSI_RecordSetStringW( uirow, 1, display_name );
5713 MSI_RecordSetStringW( uirow, 2, name );
5714 msi_ui_actiondata( package, szStartServices, uirow );
5715 msiobj_release( &uirow->hdr );
5717 CloseServiceHandle(service);
5718 CloseServiceHandle(scm);
5723 msi_free(display_name);
5727 static UINT ACTION_StartServices( MSIPACKAGE *package )
5729 static const WCHAR query[] = {
5730 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5731 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5735 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5736 if (rc != ERROR_SUCCESS)
5737 return ERROR_SUCCESS;
5739 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5740 msiobj_release(&view->hdr);
5744 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5746 DWORD i, needed, count;
5747 ENUM_SERVICE_STATUSW *dependencies;
5751 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5752 0, &needed, &count))
5755 if (GetLastError() != ERROR_MORE_DATA)
5758 dependencies = msi_alloc(needed);
5762 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5763 needed, &needed, &count))
5766 for (i = 0; i < count; i++)
5768 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5769 SERVICE_STOP | SERVICE_QUERY_STATUS);
5773 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5780 msi_free(dependencies);
5784 static UINT stop_service( LPCWSTR name )
5786 SC_HANDLE scm = NULL, service = NULL;
5787 SERVICE_STATUS status;
5788 SERVICE_STATUS_PROCESS ssp;
5791 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5794 WARN("Failed to open the SCM: %d\n", GetLastError());
5798 service = OpenServiceW(scm, name,
5800 SERVICE_QUERY_STATUS |
5801 SERVICE_ENUMERATE_DEPENDENTS);
5804 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5808 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5809 sizeof(SERVICE_STATUS_PROCESS), &needed))
5811 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5815 if (ssp.dwCurrentState == SERVICE_STOPPED)
5818 stop_service_dependents(scm, service);
5820 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5821 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5824 CloseServiceHandle(service);
5825 CloseServiceHandle(scm);
5827 return ERROR_SUCCESS;
5830 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5832 MSIPACKAGE *package = param;
5836 LPWSTR name = NULL, display_name = NULL;
5840 event = MSI_RecordGetInteger( rec, 3 );
5841 if (!(event & msidbServiceControlEventStop))
5842 return ERROR_SUCCESS;
5844 component = MSI_RecordGetString( rec, 6 );
5845 comp = msi_get_loaded_component( package, component );
5847 return ERROR_SUCCESS;
5849 comp->Action = msi_get_component_action( package, comp );
5850 if (comp->Action != INSTALLSTATE_ABSENT)
5852 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5853 return ERROR_SUCCESS;
5856 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5859 ERR("Failed to open the service control manager\n");
5864 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5865 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5867 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5868 GetServiceDisplayNameW( scm, name, display_name, &len );
5870 CloseServiceHandle( scm );
5872 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5873 stop_service( name );
5876 uirow = MSI_CreateRecord( 2 );
5877 MSI_RecordSetStringW( uirow, 1, display_name );
5878 MSI_RecordSetStringW( uirow, 2, name );
5879 msi_ui_actiondata( package, szStopServices, uirow );
5880 msiobj_release( &uirow->hdr );
5883 msi_free( display_name );
5884 return ERROR_SUCCESS;
5887 static UINT ACTION_StopServices( MSIPACKAGE *package )
5889 static const WCHAR query[] = {
5890 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5891 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5895 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5896 if (rc != ERROR_SUCCESS)
5897 return ERROR_SUCCESS;
5899 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5900 msiobj_release(&view->hdr);
5904 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5906 MSIPACKAGE *package = param;
5910 LPWSTR name = NULL, display_name = NULL;
5912 SC_HANDLE scm = NULL, service = NULL;
5914 event = MSI_RecordGetInteger( rec, 3 );
5915 if (!(event & msidbServiceControlEventDelete))
5916 return ERROR_SUCCESS;
5918 component = MSI_RecordGetString(rec, 6);
5919 comp = msi_get_loaded_component(package, component);
5921 return ERROR_SUCCESS;
5923 comp->Action = msi_get_component_action( package, comp );
5924 if (comp->Action != INSTALLSTATE_ABSENT)
5926 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5927 return ERROR_SUCCESS;
5930 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5931 stop_service( name );
5933 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5936 WARN("Failed to open the SCM: %d\n", GetLastError());
5941 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5942 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5944 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5945 GetServiceDisplayNameW( scm, name, display_name, &len );
5948 service = OpenServiceW( scm, name, DELETE );
5951 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5955 if (!DeleteService( service ))
5956 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5959 uirow = MSI_CreateRecord( 2 );
5960 MSI_RecordSetStringW( uirow, 1, display_name );
5961 MSI_RecordSetStringW( uirow, 2, name );
5962 msi_ui_actiondata( package, szDeleteServices, uirow );
5963 msiobj_release( &uirow->hdr );
5965 CloseServiceHandle( service );
5966 CloseServiceHandle( scm );
5968 msi_free( display_name );
5970 return ERROR_SUCCESS;
5973 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5975 static const WCHAR query[] = {
5976 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5977 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5981 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5982 if (rc != ERROR_SUCCESS)
5983 return ERROR_SUCCESS;
5985 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5986 msiobj_release( &view->hdr );
5990 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5992 MSIPACKAGE *package = param;
5993 LPWSTR driver, driver_path, ptr;
5994 WCHAR outpath[MAX_PATH];
5995 MSIFILE *driver_file = NULL, *setup_file = NULL;
5998 LPCWSTR desc, file_key, component;
6000 UINT r = ERROR_SUCCESS;
6002 static const WCHAR driver_fmt[] = {
6003 'D','r','i','v','e','r','=','%','s',0};
6004 static const WCHAR setup_fmt[] = {
6005 'S','e','t','u','p','=','%','s',0};
6006 static const WCHAR usage_fmt[] = {
6007 'F','i','l','e','U','s','a','g','e','=','1',0};
6009 component = MSI_RecordGetString( rec, 2 );
6010 comp = msi_get_loaded_component( package, component );
6012 return ERROR_SUCCESS;
6014 comp->Action = msi_get_component_action( package, comp );
6015 if (comp->Action != INSTALLSTATE_LOCAL)
6017 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6018 return ERROR_SUCCESS;
6020 desc = MSI_RecordGetString(rec, 3);
6022 file_key = MSI_RecordGetString( rec, 4 );
6023 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6025 file_key = MSI_RecordGetString( rec, 5 );
6026 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6030 ERR("ODBC Driver entry not found!\n");
6031 return ERROR_FUNCTION_FAILED;
6034 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6036 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6037 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6039 driver = msi_alloc(len * sizeof(WCHAR));
6041 return ERROR_OUTOFMEMORY;
6044 lstrcpyW(ptr, desc);
6045 ptr += lstrlenW(ptr) + 1;
6047 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6052 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6056 lstrcpyW(ptr, usage_fmt);
6057 ptr += lstrlenW(ptr) + 1;
6060 driver_path = strdupW(driver_file->TargetPath);
6061 ptr = strrchrW(driver_path, '\\');
6062 if (ptr) *ptr = '\0';
6064 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6065 NULL, ODBC_INSTALL_COMPLETE, &usage))
6067 ERR("Failed to install SQL driver!\n");
6068 r = ERROR_FUNCTION_FAILED;
6071 uirow = MSI_CreateRecord( 5 );
6072 MSI_RecordSetStringW( uirow, 1, desc );
6073 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6074 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6075 msi_ui_actiondata( package, szInstallODBC, uirow );
6076 msiobj_release( &uirow->hdr );
6079 msi_free(driver_path);
6084 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6086 MSIPACKAGE *package = param;
6087 LPWSTR translator, translator_path, ptr;
6088 WCHAR outpath[MAX_PATH];
6089 MSIFILE *translator_file = NULL, *setup_file = NULL;
6092 LPCWSTR desc, file_key, component;
6094 UINT r = ERROR_SUCCESS;
6096 static const WCHAR translator_fmt[] = {
6097 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6098 static const WCHAR setup_fmt[] = {
6099 'S','e','t','u','p','=','%','s',0};
6101 component = MSI_RecordGetString( rec, 2 );
6102 comp = msi_get_loaded_component( package, component );
6104 return ERROR_SUCCESS;
6106 comp->Action = msi_get_component_action( package, comp );
6107 if (comp->Action != INSTALLSTATE_LOCAL)
6109 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6110 return ERROR_SUCCESS;
6112 desc = MSI_RecordGetString(rec, 3);
6114 file_key = MSI_RecordGetString( rec, 4 );
6115 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6117 file_key = MSI_RecordGetString( rec, 5 );
6118 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6120 if (!translator_file)
6122 ERR("ODBC Translator entry not found!\n");
6123 return ERROR_FUNCTION_FAILED;
6126 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6128 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6130 translator = msi_alloc(len * sizeof(WCHAR));
6132 return ERROR_OUTOFMEMORY;
6135 lstrcpyW(ptr, desc);
6136 ptr += lstrlenW(ptr) + 1;
6138 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6143 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6148 translator_path = strdupW(translator_file->TargetPath);
6149 ptr = strrchrW(translator_path, '\\');
6150 if (ptr) *ptr = '\0';
6152 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6153 NULL, ODBC_INSTALL_COMPLETE, &usage))
6155 ERR("Failed to install SQL translator!\n");
6156 r = ERROR_FUNCTION_FAILED;
6159 uirow = MSI_CreateRecord( 5 );
6160 MSI_RecordSetStringW( uirow, 1, desc );
6161 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6162 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6163 msi_ui_actiondata( package, szInstallODBC, uirow );
6164 msiobj_release( &uirow->hdr );
6166 msi_free(translator);
6167 msi_free(translator_path);
6172 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6174 MSIPACKAGE *package = param;
6177 LPCWSTR desc, driver, component;
6178 WORD request = ODBC_ADD_SYS_DSN;
6181 UINT r = ERROR_SUCCESS;
6184 static const WCHAR attrs_fmt[] = {
6185 'D','S','N','=','%','s',0 };
6187 component = MSI_RecordGetString( rec, 2 );
6188 comp = msi_get_loaded_component( package, component );
6190 return ERROR_SUCCESS;
6192 comp->Action = msi_get_component_action( package, comp );
6193 if (comp->Action != INSTALLSTATE_LOCAL)
6195 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6196 return ERROR_SUCCESS;
6199 desc = MSI_RecordGetString(rec, 3);
6200 driver = MSI_RecordGetString(rec, 4);
6201 registration = MSI_RecordGetInteger(rec, 5);
6203 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6204 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6206 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6207 attrs = msi_alloc(len * sizeof(WCHAR));
6209 return ERROR_OUTOFMEMORY;
6211 len = sprintfW(attrs, attrs_fmt, desc);
6214 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6216 ERR("Failed to install SQL data source!\n");
6217 r = ERROR_FUNCTION_FAILED;
6220 uirow = MSI_CreateRecord( 5 );
6221 MSI_RecordSetStringW( uirow, 1, desc );
6222 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6223 MSI_RecordSetInteger( uirow, 3, request );
6224 msi_ui_actiondata( package, szInstallODBC, uirow );
6225 msiobj_release( &uirow->hdr );
6232 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6234 static const WCHAR driver_query[] = {
6235 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6236 'O','D','B','C','D','r','i','v','e','r',0};
6237 static const WCHAR translator_query[] = {
6238 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6239 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6240 static const WCHAR source_query[] = {
6241 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6242 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6246 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6247 if (rc == ERROR_SUCCESS)
6249 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6250 msiobj_release(&view->hdr);
6251 if (rc != ERROR_SUCCESS)
6254 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6255 if (rc == ERROR_SUCCESS)
6257 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6258 msiobj_release(&view->hdr);
6259 if (rc != ERROR_SUCCESS)
6262 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6263 if (rc == ERROR_SUCCESS)
6265 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6266 msiobj_release(&view->hdr);
6267 if (rc != ERROR_SUCCESS)
6270 return ERROR_SUCCESS;
6273 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6275 MSIPACKAGE *package = param;
6279 LPCWSTR desc, component;
6281 component = MSI_RecordGetString( rec, 2 );
6282 comp = msi_get_loaded_component( package, component );
6284 return ERROR_SUCCESS;
6286 comp->Action = msi_get_component_action( package, comp );
6287 if (comp->Action != INSTALLSTATE_ABSENT)
6289 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6290 return ERROR_SUCCESS;
6293 desc = MSI_RecordGetString( rec, 3 );
6294 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6296 WARN("Failed to remove ODBC driver\n");
6300 FIXME("Usage count reached 0\n");
6303 uirow = MSI_CreateRecord( 2 );
6304 MSI_RecordSetStringW( uirow, 1, desc );
6305 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6306 msi_ui_actiondata( package, szRemoveODBC, uirow );
6307 msiobj_release( &uirow->hdr );
6309 return ERROR_SUCCESS;
6312 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6314 MSIPACKAGE *package = param;
6318 LPCWSTR desc, component;
6320 component = MSI_RecordGetString( rec, 2 );
6321 comp = msi_get_loaded_component( package, component );
6323 return ERROR_SUCCESS;
6325 comp->Action = msi_get_component_action( package, comp );
6326 if (comp->Action != INSTALLSTATE_ABSENT)
6328 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6329 return ERROR_SUCCESS;
6332 desc = MSI_RecordGetString( rec, 3 );
6333 if (!SQLRemoveTranslatorW( desc, &usage ))
6335 WARN("Failed to remove ODBC translator\n");
6339 FIXME("Usage count reached 0\n");
6342 uirow = MSI_CreateRecord( 2 );
6343 MSI_RecordSetStringW( uirow, 1, desc );
6344 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6345 msi_ui_actiondata( package, szRemoveODBC, uirow );
6346 msiobj_release( &uirow->hdr );
6348 return ERROR_SUCCESS;
6351 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6353 MSIPACKAGE *package = param;
6357 LPCWSTR desc, driver, component;
6358 WORD request = ODBC_REMOVE_SYS_DSN;
6362 static const WCHAR attrs_fmt[] = {
6363 'D','S','N','=','%','s',0 };
6365 component = MSI_RecordGetString( rec, 2 );
6366 comp = msi_get_loaded_component( package, component );
6368 return ERROR_SUCCESS;
6370 comp->Action = msi_get_component_action( package, comp );
6371 if (comp->Action != INSTALLSTATE_ABSENT)
6373 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6374 return ERROR_SUCCESS;
6377 desc = MSI_RecordGetString( rec, 3 );
6378 driver = MSI_RecordGetString( rec, 4 );
6379 registration = MSI_RecordGetInteger( rec, 5 );
6381 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6382 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6384 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6385 attrs = msi_alloc( len * sizeof(WCHAR) );
6387 return ERROR_OUTOFMEMORY;
6389 FIXME("Use ODBCSourceAttribute table\n");
6391 len = sprintfW( attrs, attrs_fmt, desc );
6394 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6396 WARN("Failed to remove ODBC data source\n");
6400 uirow = MSI_CreateRecord( 3 );
6401 MSI_RecordSetStringW( uirow, 1, desc );
6402 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6403 MSI_RecordSetInteger( uirow, 3, request );
6404 msi_ui_actiondata( package, szRemoveODBC, uirow );
6405 msiobj_release( &uirow->hdr );
6407 return ERROR_SUCCESS;
6410 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6412 static const WCHAR driver_query[] = {
6413 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6414 'O','D','B','C','D','r','i','v','e','r',0};
6415 static const WCHAR translator_query[] = {
6416 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6417 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6418 static const WCHAR source_query[] = {
6419 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6420 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6424 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6425 if (rc == ERROR_SUCCESS)
6427 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6428 msiobj_release( &view->hdr );
6429 if (rc != ERROR_SUCCESS)
6432 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6433 if (rc == ERROR_SUCCESS)
6435 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6436 msiobj_release( &view->hdr );
6437 if (rc != ERROR_SUCCESS)
6440 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6441 if (rc == ERROR_SUCCESS)
6443 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6444 msiobj_release( &view->hdr );
6445 if (rc != ERROR_SUCCESS)
6448 return ERROR_SUCCESS;
6451 #define ENV_ACT_SETALWAYS 0x1
6452 #define ENV_ACT_SETABSENT 0x2
6453 #define ENV_ACT_REMOVE 0x4
6454 #define ENV_ACT_REMOVEMATCH 0x8
6456 #define ENV_MOD_MACHINE 0x20000000
6457 #define ENV_MOD_APPEND 0x40000000
6458 #define ENV_MOD_PREFIX 0x80000000
6459 #define ENV_MOD_MASK 0xC0000000
6461 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6463 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6465 LPCWSTR cptr = *name;
6467 static const WCHAR prefix[] = {'[','~',']',0};
6468 static const int prefix_len = 3;
6474 *flags |= ENV_ACT_SETALWAYS;
6475 else if (*cptr == '+')
6476 *flags |= ENV_ACT_SETABSENT;
6477 else if (*cptr == '-')
6478 *flags |= ENV_ACT_REMOVE;
6479 else if (*cptr == '!')
6480 *flags |= ENV_ACT_REMOVEMATCH;
6481 else if (*cptr == '*')
6482 *flags |= ENV_MOD_MACHINE;
6492 ERR("Missing environment variable\n");
6493 return ERROR_FUNCTION_FAILED;
6498 LPCWSTR ptr = *value;
6499 if (!strncmpW(ptr, prefix, prefix_len))
6501 if (ptr[prefix_len] == szSemiColon[0])
6503 *flags |= ENV_MOD_APPEND;
6504 *value += lstrlenW(prefix);
6511 else if (lstrlenW(*value) >= prefix_len)
6513 ptr += lstrlenW(ptr) - prefix_len;
6514 if (!strcmpW( ptr, prefix ))
6516 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6518 *flags |= ENV_MOD_PREFIX;
6519 /* the "[~]" will be removed by deformat_string */;
6529 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6530 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6531 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6532 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6534 ERR("Invalid flags: %08x\n", *flags);
6535 return ERROR_FUNCTION_FAILED;
6539 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6541 return ERROR_SUCCESS;
6544 static UINT open_env_key( DWORD flags, HKEY *key )
6546 static const WCHAR user_env[] =
6547 {'E','n','v','i','r','o','n','m','e','n','t',0};
6548 static const WCHAR machine_env[] =
6549 {'S','y','s','t','e','m','\\',
6550 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6551 'C','o','n','t','r','o','l','\\',
6552 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6553 'E','n','v','i','r','o','n','m','e','n','t',0};
6558 if (flags & ENV_MOD_MACHINE)
6561 root = HKEY_LOCAL_MACHINE;
6566 root = HKEY_CURRENT_USER;
6569 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6570 if (res != ERROR_SUCCESS)
6572 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6573 return ERROR_FUNCTION_FAILED;
6576 return ERROR_SUCCESS;
6579 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6581 MSIPACKAGE *package = param;
6582 LPCWSTR name, value, component;
6583 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6584 DWORD flags, type, size;
6591 component = MSI_RecordGetString(rec, 4);
6592 comp = msi_get_loaded_component(package, component);
6594 return ERROR_SUCCESS;
6596 comp->Action = msi_get_component_action( package, comp );
6597 if (comp->Action != INSTALLSTATE_LOCAL)
6599 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6600 return ERROR_SUCCESS;
6602 name = MSI_RecordGetString(rec, 2);
6603 value = MSI_RecordGetString(rec, 3);
6605 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6607 res = env_parse_flags(&name, &value, &flags);
6608 if (res != ERROR_SUCCESS || !value)
6611 if (value && !deformat_string(package, value, &deformatted))
6613 res = ERROR_OUTOFMEMORY;
6617 value = deformatted;
6619 res = open_env_key( flags, &env );
6620 if (res != ERROR_SUCCESS)
6623 if (flags & ENV_MOD_MACHINE)
6624 action |= 0x20000000;
6628 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6629 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6630 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6633 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6637 /* Nothing to do. */
6640 res = ERROR_SUCCESS;
6644 /* If we are appending but the string was empty, strip ; */
6645 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6647 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6648 newval = strdupW(value);
6651 res = ERROR_OUTOFMEMORY;
6659 /* Contrary to MSDN, +-variable to [~];path works */
6660 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6662 res = ERROR_SUCCESS;
6666 data = msi_alloc(size);
6670 return ERROR_OUTOFMEMORY;
6673 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6674 if (res != ERROR_SUCCESS)
6677 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6680 res = RegDeleteValueW(env, name);
6681 if (res != ERROR_SUCCESS)
6682 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6686 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6687 if (flags & ENV_MOD_MASK)
6691 if (flags & ENV_MOD_APPEND) multiplier++;
6692 if (flags & ENV_MOD_PREFIX) multiplier++;
6693 mod_size = lstrlenW(value) * multiplier;
6694 size += mod_size * sizeof(WCHAR);
6697 newval = msi_alloc(size);
6701 res = ERROR_OUTOFMEMORY;
6705 if (flags & ENV_MOD_PREFIX)
6707 lstrcpyW(newval, value);
6708 ptr = newval + lstrlenW(value);
6709 action |= 0x80000000;
6712 lstrcpyW(ptr, data);
6714 if (flags & ENV_MOD_APPEND)
6716 lstrcatW(newval, value);
6717 action |= 0x40000000;
6720 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6721 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6724 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6728 uirow = MSI_CreateRecord( 3 );
6729 MSI_RecordSetStringW( uirow, 1, name );
6730 MSI_RecordSetStringW( uirow, 2, newval );
6731 MSI_RecordSetInteger( uirow, 3, action );
6732 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6733 msiobj_release( &uirow->hdr );
6735 if (env) RegCloseKey(env);
6736 msi_free(deformatted);
6742 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6744 static const WCHAR query[] = {
6745 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6746 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6750 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6751 if (rc != ERROR_SUCCESS)
6752 return ERROR_SUCCESS;
6754 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6755 msiobj_release(&view->hdr);
6759 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6761 MSIPACKAGE *package = param;
6762 LPCWSTR name, value, component;
6763 LPWSTR deformatted = NULL;
6772 component = MSI_RecordGetString( rec, 4 );
6773 comp = msi_get_loaded_component( package, component );
6775 return ERROR_SUCCESS;
6777 comp->Action = msi_get_component_action( package, comp );
6778 if (comp->Action != INSTALLSTATE_ABSENT)
6780 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6781 return ERROR_SUCCESS;
6783 name = MSI_RecordGetString( rec, 2 );
6784 value = MSI_RecordGetString( rec, 3 );
6786 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6788 r = env_parse_flags( &name, &value, &flags );
6789 if (r != ERROR_SUCCESS)
6792 if (!(flags & ENV_ACT_REMOVE))
6794 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6795 return ERROR_SUCCESS;
6798 if (value && !deformat_string( package, value, &deformatted ))
6799 return ERROR_OUTOFMEMORY;
6801 value = deformatted;
6803 r = open_env_key( flags, &env );
6804 if (r != ERROR_SUCCESS)
6810 if (flags & ENV_MOD_MACHINE)
6811 action |= 0x20000000;
6813 TRACE("Removing %s\n", debugstr_w(name));
6815 res = RegDeleteValueW( env, name );
6816 if (res != ERROR_SUCCESS)
6818 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6823 uirow = MSI_CreateRecord( 3 );
6824 MSI_RecordSetStringW( uirow, 1, name );
6825 MSI_RecordSetStringW( uirow, 2, value );
6826 MSI_RecordSetInteger( uirow, 3, action );
6827 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6828 msiobj_release( &uirow->hdr );
6830 if (env) RegCloseKey( env );
6831 msi_free( deformatted );
6835 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6837 static const WCHAR query[] = {
6838 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6839 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6843 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6844 if (rc != ERROR_SUCCESS)
6845 return ERROR_SUCCESS;
6847 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6848 msiobj_release( &view->hdr );
6852 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6854 LPWSTR key, template, id;
6855 UINT r = ERROR_SUCCESS;
6857 id = msi_dup_property( package->db, szProductID );
6861 return ERROR_SUCCESS;
6863 template = msi_dup_property( package->db, szPIDTemplate );
6864 key = msi_dup_property( package->db, szPIDKEY );
6866 if (key && template)
6868 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6869 r = msi_set_property( package->db, szProductID, key );
6871 msi_free( template );
6876 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6879 package->need_reboot = 1;
6880 return ERROR_SUCCESS;
6883 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6885 static const WCHAR szAvailableFreeReg[] =
6886 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6888 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6890 TRACE("%p %d kilobytes\n", package, space);
6892 uirow = MSI_CreateRecord( 1 );
6893 MSI_RecordSetInteger( uirow, 1, space );
6894 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6895 msiobj_release( &uirow->hdr );
6897 return ERROR_SUCCESS;
6900 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6902 TRACE("%p\n", package);
6904 msi_set_property( package->db, szRollbackDisabled, szOne );
6905 return ERROR_SUCCESS;
6908 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6910 FIXME("%p\n", package);
6911 return ERROR_SUCCESS;
6914 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6916 static const WCHAR driver_query[] = {
6917 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6918 'O','D','B','C','D','r','i','v','e','r',0};
6919 static const WCHAR translator_query[] = {
6920 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6921 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6925 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6926 if (r == ERROR_SUCCESS)
6929 r = MSI_IterateRecords( view, &count, NULL, package );
6930 msiobj_release( &view->hdr );
6931 if (r != ERROR_SUCCESS)
6933 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6935 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6936 if (r == ERROR_SUCCESS)
6939 r = MSI_IterateRecords( view, &count, NULL, package );
6940 msiobj_release( &view->hdr );
6941 if (r != ERROR_SUCCESS)
6943 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6945 return ERROR_SUCCESS;
6948 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6950 MSIPACKAGE *package = param;
6951 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6954 if ((value = msi_dup_property( package->db, property )))
6956 FIXME("remove %s\n", debugstr_w(value));
6959 return ERROR_SUCCESS;
6962 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6964 static const WCHAR query[] = {
6965 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6966 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6970 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6971 if (r == ERROR_SUCCESS)
6973 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6974 msiobj_release( &view->hdr );
6975 if (r != ERROR_SUCCESS)
6978 return ERROR_SUCCESS;
6981 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6983 MSIPACKAGE *package = param;
6984 int attributes = MSI_RecordGetInteger( rec, 5 );
6986 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6988 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6989 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6990 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6991 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6995 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6997 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6998 if (r != ERROR_SUCCESS)
6999 return ERROR_SUCCESS;
7003 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7004 if (r != ERROR_SUCCESS)
7005 return ERROR_SUCCESS;
7007 RegCloseKey( hkey );
7009 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7010 debugstr_w(upgrade_code), debugstr_w(version_min),
7011 debugstr_w(version_max), debugstr_w(language));
7013 return ERROR_SUCCESS;
7016 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7018 static const WCHAR query[] = {
7019 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7020 'U','p','g','r','a','d','e',0};
7024 if (msi_get_property_int( package->db, szInstalled, 0 ))
7026 TRACE("product is installed, skipping action\n");
7027 return ERROR_SUCCESS;
7029 if (msi_get_property_int( package->db, szPreselected, 0 ))
7031 TRACE("Preselected property is set, not migrating feature states\n");
7032 return ERROR_SUCCESS;
7034 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7035 if (r == ERROR_SUCCESS)
7037 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7038 msiobj_release( &view->hdr );
7039 if (r != ERROR_SUCCESS)
7042 return ERROR_SUCCESS;
7045 static void bind_image( const char *filename, const char *path )
7047 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7049 WARN("failed to bind image %u\n", GetLastError());
7053 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7057 MSIPACKAGE *package = param;
7058 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7059 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7060 char *filenameA, *pathA;
7061 WCHAR *pathW, **path_list;
7063 if (!(file = msi_get_loaded_file( package, key )))
7065 WARN("file %s not found\n", debugstr_w(key));
7066 return ERROR_SUCCESS;
7068 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7069 path_list = msi_split_string( paths, ';' );
7070 if (!path_list) bind_image( filenameA, NULL );
7073 for (i = 0; path_list[i] && path_list[i][0]; i++)
7075 deformat_string( package, path_list[i], &pathW );
7076 if ((pathA = strdupWtoA( pathW )))
7078 bind_image( filenameA, pathA );
7084 msi_free( path_list );
7085 msi_free( filenameA );
7086 return ERROR_SUCCESS;
7089 static UINT ACTION_BindImage( MSIPACKAGE *package )
7091 static const WCHAR query[] = {
7092 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7093 'B','i','n','d','I','m','a','g','e',0};
7097 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7098 if (r == ERROR_SUCCESS)
7100 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7101 msiobj_release( &view->hdr );
7102 if (r != ERROR_SUCCESS)
7105 return ERROR_SUCCESS;
7108 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7110 static const WCHAR query[] = {
7111 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7116 r = MSI_OpenQuery( package->db, &view, query, table );
7117 if (r == ERROR_SUCCESS)
7119 r = MSI_IterateRecords(view, &count, NULL, package);
7120 msiobj_release(&view->hdr);
7121 if (r != ERROR_SUCCESS)
7124 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7125 return ERROR_SUCCESS;
7128 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7130 static const WCHAR table[] = {
7131 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7132 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7135 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7137 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7138 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7141 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7143 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7144 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7147 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7149 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7150 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7153 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7155 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7156 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7161 const WCHAR *action;
7162 UINT (*handler)(MSIPACKAGE *);
7163 const WCHAR *action_rollback;
7167 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7168 { szAppSearch, ACTION_AppSearch, NULL },
7169 { szBindImage, ACTION_BindImage, NULL },
7170 { szCCPSearch, ACTION_CCPSearch, NULL },
7171 { szCostFinalize, ACTION_CostFinalize, NULL },
7172 { szCostInitialize, ACTION_CostInitialize, NULL },
7173 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7174 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7175 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7176 { szDisableRollback, ACTION_DisableRollback, NULL },
7177 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7178 { szExecuteAction, ACTION_ExecuteAction, NULL },
7179 { szFileCost, ACTION_FileCost, NULL },
7180 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7181 { szForceReboot, ACTION_ForceReboot, NULL },
7182 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7183 { szInstallExecute, ACTION_InstallExecute, NULL },
7184 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7185 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7186 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7187 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7188 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7189 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7190 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7191 { szInstallValidate, ACTION_InstallValidate, NULL },
7192 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7193 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7194 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7195 { szMoveFiles, ACTION_MoveFiles, NULL },
7196 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7197 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7198 { szPatchFiles, ACTION_PatchFiles, NULL },
7199 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7200 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7201 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7202 { szPublishProduct, ACTION_PublishProduct, NULL },
7203 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7204 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7205 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7206 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7207 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7208 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7209 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7210 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7211 { szRegisterUser, ACTION_RegisterUser, NULL },
7212 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7213 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7214 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7215 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7216 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7217 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7218 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7219 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7220 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7221 { szResolveSource, ACTION_ResolveSource, NULL },
7222 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7223 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7224 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7225 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7226 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7227 { szStartServices, ACTION_StartServices, szStopServices },
7228 { szStopServices, ACTION_StopServices, szStartServices },
7229 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7230 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7231 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7232 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7233 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7234 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7235 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7236 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7237 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7238 { szValidateProductID, ACTION_ValidateProductID, NULL },
7239 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7240 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7241 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7242 { NULL, NULL, NULL }
7245 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7251 while (StandardActions[i].action != NULL)
7253 if (!strcmpW( StandardActions[i].action, action ))
7255 ui_actionstart( package, action );
7256 if (StandardActions[i].handler)
7258 ui_actioninfo( package, action, TRUE, 0 );
7259 *rc = StandardActions[i].handler( package );
7260 ui_actioninfo( package, action, FALSE, *rc );
7262 if (StandardActions[i].action_rollback && !package->need_rollback)
7264 TRACE("scheduling rollback action\n");
7265 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7270 FIXME("unhandled standard action %s\n", debugstr_w(action));
7271 *rc = ERROR_SUCCESS;
7281 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7283 UINT rc = ERROR_SUCCESS;
7286 TRACE("Performing action (%s)\n", debugstr_w(action));
7288 handled = ACTION_HandleStandardAction(package, action, &rc);
7291 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7295 WARN("unhandled msi action %s\n", debugstr_w(action));
7296 rc = ERROR_FUNCTION_NOT_CALLED;
7302 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7304 UINT rc = ERROR_SUCCESS;
7305 BOOL handled = FALSE;
7307 TRACE("Performing action (%s)\n", debugstr_w(action));
7309 handled = ACTION_HandleStandardAction(package, action, &rc);
7312 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7314 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7319 WARN("unhandled msi action %s\n", debugstr_w(action));
7320 rc = ERROR_FUNCTION_NOT_CALLED;
7326 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7328 UINT rc = ERROR_SUCCESS;
7331 static const WCHAR query[] =
7332 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7333 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7334 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7335 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7336 static const WCHAR ui_query[] =
7337 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7338 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7339 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7340 ' ', '=',' ','%','i',0};
7342 if (needs_ui_sequence(package))
7343 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7345 row = MSI_QueryGetRecord(package->db, query, seq);
7349 LPCWSTR action, cond;
7351 TRACE("Running the actions\n");
7353 /* check conditions */
7354 cond = MSI_RecordGetString(row, 2);
7356 /* this is a hack to skip errors in the condition code */
7357 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7359 msiobj_release(&row->hdr);
7360 return ERROR_SUCCESS;
7363 action = MSI_RecordGetString(row, 1);
7366 ERR("failed to fetch action\n");
7367 msiobj_release(&row->hdr);
7368 return ERROR_FUNCTION_FAILED;
7371 if (needs_ui_sequence(package))
7372 rc = ACTION_PerformUIAction(package, action, -1);
7374 rc = ACTION_PerformAction(package, action, -1);
7376 msiobj_release(&row->hdr);
7382 /****************************************************
7383 * TOP level entry points
7384 *****************************************************/
7386 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7387 LPCWSTR szCommandLine )
7391 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7392 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7393 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7395 msi_set_property( package->db, szAction, szInstall );
7397 package->script->InWhatSequence = SEQUENCE_INSTALL;
7404 dir = strdupW(szPackagePath);
7405 p = strrchrW(dir, '\\');
7409 file = szPackagePath + (p - dir);
7414 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7415 GetCurrentDirectoryW(MAX_PATH, dir);
7416 lstrcatW(dir, szBackSlash);
7417 file = szPackagePath;
7420 msi_free( package->PackagePath );
7421 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7422 if (!package->PackagePath)
7425 return ERROR_OUTOFMEMORY;
7428 lstrcpyW(package->PackagePath, dir);
7429 lstrcatW(package->PackagePath, file);
7432 msi_set_sourcedir_props(package, FALSE);
7435 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7436 if (rc != ERROR_SUCCESS)
7439 msi_apply_transforms( package );
7440 msi_apply_patches( package );
7442 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7444 TRACE("setting reinstall property\n");
7445 msi_set_property( package->db, szReinstall, szAll );
7448 /* properties may have been added by a transform */
7449 msi_clone_properties( package );
7451 msi_parse_command_line( package, szCommandLine, FALSE );
7452 msi_adjust_privilege_properties( package );
7453 msi_set_context( package );
7455 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7457 TRACE("disabling rollback\n");
7458 msi_set_property( package->db, szRollbackDisabled, szOne );
7461 if (needs_ui_sequence( package))
7463 package->script->InWhatSequence |= SEQUENCE_UI;
7464 rc = ACTION_ProcessUISequence(package);
7465 ui_exists = ui_sequence_exists(package);
7466 if (rc == ERROR_SUCCESS || !ui_exists)
7468 package->script->InWhatSequence |= SEQUENCE_EXEC;
7469 rc = ACTION_ProcessExecSequence(package, ui_exists);
7473 rc = ACTION_ProcessExecSequence(package, FALSE);
7475 package->script->CurrentlyScripting = FALSE;
7477 /* process the ending type action */
7478 if (rc == ERROR_SUCCESS)
7479 ACTION_PerformActionSequence(package, -1);
7480 else if (rc == ERROR_INSTALL_USEREXIT)
7481 ACTION_PerformActionSequence(package, -2);
7482 else if (rc == ERROR_INSTALL_SUSPEND)
7483 ACTION_PerformActionSequence(package, -4);
7486 ACTION_PerformActionSequence(package, -3);
7487 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7489 package->need_rollback = TRUE;
7493 /* finish up running custom actions */
7494 ACTION_FinishCustomActions(package);
7496 if (package->need_rollback)
7498 WARN("installation failed, running rollback script\n");
7499 execute_script( package, ROLLBACK_SCRIPT );
7502 if (rc == ERROR_SUCCESS && package->need_reboot)
7503 return ERROR_SUCCESS_REBOOT_REQUIRED;