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_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2696 DWORD num_subkeys, num_values;
2698 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2700 if ((res = RegDeleteValueW( hkey, value )))
2702 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2704 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2705 NULL, NULL, NULL, NULL );
2706 RegCloseKey( hkey );
2707 if (!res && !num_subkeys && !num_values)
2709 TRACE("removing empty key %s\n", debugstr_w(keypath));
2710 RegDeleteKeyW( root, keypath );
2714 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2717 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2719 LONG res = RegDeleteTreeW( root, keypath );
2720 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2723 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2725 MSIPACKAGE *package = param;
2726 LPCWSTR component, name, key_str, root_key_str;
2727 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2730 BOOL delete_key = FALSE;
2735 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2737 component = MSI_RecordGetString( row, 6 );
2738 comp = msi_get_loaded_component( package, component );
2740 return ERROR_SUCCESS;
2742 comp->Action = msi_get_component_action( package, comp );
2743 if (comp->Action != INSTALLSTATE_ABSENT)
2745 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2746 return ERROR_SUCCESS;
2749 name = MSI_RecordGetString( row, 4 );
2750 if (MSI_RecordIsNull( row, 5 ) && name )
2752 if (name[0] == '+' && !name[1])
2753 return ERROR_SUCCESS;
2754 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2761 root = MSI_RecordGetInteger( row, 2 );
2762 key_str = MSI_RecordGetString( row, 3 );
2764 root_key_str = get_root_key( package, root, &hkey_root );
2766 return ERROR_SUCCESS;
2768 deformat_string( package, key_str, &deformated_key );
2769 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2770 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2771 strcpyW( ui_key_str, root_key_str );
2772 strcatW( ui_key_str, deformated_key );
2774 deformat_string( package, name, &deformated_name );
2776 keypath = get_keypath( package, hkey_root, deformated_key );
2777 msi_free( deformated_key );
2778 if (delete_key) delete_reg_key( hkey_root, keypath );
2779 else delete_reg_value( hkey_root, keypath, deformated_name );
2780 msi_free( keypath );
2782 uirow = MSI_CreateRecord( 2 );
2783 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2784 MSI_RecordSetStringW( uirow, 2, deformated_name );
2785 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2786 msiobj_release( &uirow->hdr );
2788 msi_free( ui_key_str );
2789 msi_free( deformated_name );
2790 return ERROR_SUCCESS;
2793 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2795 MSIPACKAGE *package = param;
2796 LPCWSTR component, name, key_str, root_key_str;
2797 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2800 BOOL delete_key = FALSE;
2805 component = MSI_RecordGetString( row, 5 );
2806 comp = msi_get_loaded_component( package, component );
2808 return ERROR_SUCCESS;
2810 comp->Action = msi_get_component_action( package, comp );
2811 if (comp->Action != INSTALLSTATE_LOCAL)
2813 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2814 return ERROR_SUCCESS;
2817 if ((name = MSI_RecordGetString( row, 4 )))
2819 if (name[0] == '-' && !name[1])
2826 root = MSI_RecordGetInteger( row, 2 );
2827 key_str = MSI_RecordGetString( row, 3 );
2829 root_key_str = get_root_key( package, root, &hkey_root );
2831 return ERROR_SUCCESS;
2833 deformat_string( package, key_str, &deformated_key );
2834 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2835 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2836 strcpyW( ui_key_str, root_key_str );
2837 strcatW( ui_key_str, deformated_key );
2839 deformat_string( package, name, &deformated_name );
2841 keypath = get_keypath( package, hkey_root, deformated_key );
2842 msi_free( deformated_key );
2843 if (delete_key) delete_reg_key( hkey_root, keypath );
2844 else delete_reg_value( hkey_root, keypath, deformated_name );
2845 msi_free( keypath );
2847 uirow = MSI_CreateRecord( 2 );
2848 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2849 MSI_RecordSetStringW( uirow, 2, deformated_name );
2850 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2851 msiobj_release( &uirow->hdr );
2853 msi_free( ui_key_str );
2854 msi_free( deformated_name );
2855 return ERROR_SUCCESS;
2858 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2860 static const WCHAR registry_query[] = {
2861 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2862 '`','R','e','g','i','s','t','r','y','`',0};
2863 static const WCHAR remove_registry_query[] = {
2864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2865 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2869 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2870 if (rc == ERROR_SUCCESS)
2872 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2873 msiobj_release( &view->hdr );
2874 if (rc != ERROR_SUCCESS)
2877 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2878 if (rc == ERROR_SUCCESS)
2880 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2881 msiobj_release( &view->hdr );
2882 if (rc != ERROR_SUCCESS)
2885 return ERROR_SUCCESS;
2888 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2890 package->script->CurrentlyScripting = TRUE;
2892 return ERROR_SUCCESS;
2896 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2898 static const WCHAR query[]= {
2899 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2900 '`','R','e','g','i','s','t','r','y','`',0};
2902 DWORD total = 0, count = 0;
2904 MSIFEATURE *feature;
2908 TRACE("InstallValidate\n");
2910 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2911 if (rc == ERROR_SUCCESS)
2913 rc = MSI_IterateRecords( view, &count, NULL, package );
2914 msiobj_release( &view->hdr );
2915 if (rc != ERROR_SUCCESS)
2917 total += count * REG_PROGRESS_VALUE;
2919 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2920 total += COMPONENT_PROGRESS_VALUE;
2922 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2923 total += file->FileSize;
2925 msi_ui_progress( package, 0, total, 0, 0 );
2927 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2929 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2930 debugstr_w(feature->Feature), feature->Installed,
2931 feature->ActionRequest, feature->Action);
2933 return ERROR_SUCCESS;
2936 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2938 MSIPACKAGE* package = param;
2939 LPCWSTR cond = NULL;
2940 LPCWSTR message = NULL;
2943 static const WCHAR title[]=
2944 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2946 cond = MSI_RecordGetString(row,1);
2948 r = MSI_EvaluateConditionW(package,cond);
2949 if (r == MSICONDITION_FALSE)
2951 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2954 message = MSI_RecordGetString(row,2);
2955 deformat_string(package,message,&deformated);
2956 MessageBoxW(NULL,deformated,title,MB_OK);
2957 msi_free(deformated);
2960 return ERROR_INSTALL_FAILURE;
2963 return ERROR_SUCCESS;
2966 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2968 static const WCHAR query[] = {
2969 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2970 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2974 TRACE("Checking launch conditions\n");
2976 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2977 if (rc != ERROR_SUCCESS)
2978 return ERROR_SUCCESS;
2980 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2981 msiobj_release(&view->hdr);
2985 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2989 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2991 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2993 static const WCHAR query[] = {
2994 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2995 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
2996 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
2997 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
2998 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3001 LPWSTR deformated, buffer, deformated_name;
3004 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3008 root = MSI_RecordGetInteger(row,2);
3009 key = MSI_RecordGetString(row, 3);
3010 name = MSI_RecordGetString(row, 4);
3011 deformat_string(package, key , &deformated);
3012 deformat_string(package, name, &deformated_name);
3014 len = strlenW(deformated) + 6;
3015 if (deformated_name)
3016 len+=strlenW(deformated_name);
3018 buffer = msi_alloc( len *sizeof(WCHAR));
3020 if (deformated_name)
3021 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3023 sprintfW(buffer,fmt,root,deformated);
3025 msi_free(deformated);
3026 msi_free(deformated_name);
3027 msiobj_release(&row->hdr);
3031 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3033 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3038 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3041 return strdupW( file->TargetPath );
3046 static HKEY openSharedDLLsKey(void)
3049 static const WCHAR path[] =
3050 {'S','o','f','t','w','a','r','e','\\',
3051 'M','i','c','r','o','s','o','f','t','\\',
3052 'W','i','n','d','o','w','s','\\',
3053 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3054 'S','h','a','r','e','d','D','L','L','s',0};
3056 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3060 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3065 DWORD sz = sizeof(count);
3068 hkey = openSharedDLLsKey();
3069 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3070 if (rc != ERROR_SUCCESS)
3076 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3080 hkey = openSharedDLLsKey();
3082 msi_reg_set_val_dword( hkey, path, count );
3084 RegDeleteValueW(hkey,path);
3089 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3091 MSIFEATURE *feature;
3095 /* only refcount DLLs */
3096 if (comp->KeyPath == NULL ||
3098 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3099 comp->Attributes & msidbComponentAttributesODBCDataSource)
3103 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3104 write = (count > 0);
3106 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3110 /* increment counts */
3111 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3115 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3118 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3120 if ( cl->component == comp )
3125 /* decrement counts */
3126 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3130 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3133 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3135 if ( cl->component == comp )
3140 /* ref count all the files in the component */
3145 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3147 if (file->Component == comp)
3148 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3152 /* add a count for permanent */
3153 if (comp->Attributes & msidbComponentAttributesPermanent)
3156 comp->RefCount = count;
3159 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3162 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3166 const WCHAR prefixW[] = {'<','\\',0};
3167 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3168 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3172 strcpyW( keypath, prefixW );
3173 strcatW( keypath, comp->assembly->display_name );
3177 return resolve_keypath( package, comp );
3180 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3182 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3189 squash_guid(package->ProductCode,squished_pc);
3190 msi_set_sourcedir_props(package, FALSE);
3192 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3195 INSTALLSTATE action;
3197 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3198 if (!comp->ComponentId)
3201 squash_guid( comp->ComponentId, squished_cc );
3202 msi_free( comp->FullKeypath );
3203 comp->FullKeypath = build_full_keypath( package, comp );
3205 ACTION_RefCountComponent( package, comp );
3207 if (package->need_rollback) action = comp->Installed;
3208 else action = comp->ActionRequest;
3210 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3211 debugstr_w(comp->Component), debugstr_w(squished_cc),
3212 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3214 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3216 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3217 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3219 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3221 if (rc != ERROR_SUCCESS)
3224 if (comp->Attributes & msidbComponentAttributesPermanent)
3226 static const WCHAR szPermKey[] =
3227 { '0','0','0','0','0','0','0','0','0','0','0','0',
3228 '0','0','0','0','0','0','0','0','0','0','0','0',
3229 '0','0','0','0','0','0','0','0',0 };
3231 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3233 if (action == INSTALLSTATE_LOCAL)
3234 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3240 WCHAR source[MAX_PATH];
3241 WCHAR base[MAX_PATH];
3244 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3245 static const WCHAR query[] = {
3246 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3247 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3248 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3249 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3250 '`','D','i','s','k','I','d','`',0};
3252 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3255 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3256 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3257 ptr2 = strrchrW(source, '\\') + 1;
3258 msiobj_release(&row->hdr);
3260 lstrcpyW(base, package->PackagePath);
3261 ptr = strrchrW(base, '\\');
3264 sourcepath = msi_resolve_file_source(package, file);
3265 ptr = sourcepath + lstrlenW(base);
3266 lstrcpyW(ptr2, ptr);
3267 msi_free(sourcepath);
3269 msi_reg_set_val_str(hkey, squished_pc, source);
3273 else if (action == INSTALLSTATE_ABSENT)
3275 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3276 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3278 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3282 uirow = MSI_CreateRecord(3);
3283 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3284 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3285 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3286 msi_ui_actiondata( package, szProcessComponents, uirow );
3287 msiobj_release( &uirow->hdr );
3289 return ERROR_SUCCESS;
3300 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3301 LPWSTR lpszName, LONG_PTR lParam)
3304 typelib_struct *tl_struct = (typelib_struct*) lParam;
3305 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3309 if (!IS_INTRESOURCE(lpszName))
3311 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3315 sz = strlenW(tl_struct->source)+4;
3316 sz *= sizeof(WCHAR);
3318 if ((INT_PTR)lpszName == 1)
3319 tl_struct->path = strdupW(tl_struct->source);
3322 tl_struct->path = msi_alloc(sz);
3323 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3326 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3327 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3330 msi_free(tl_struct->path);
3331 tl_struct->path = NULL;
3336 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3337 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3339 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3343 msi_free(tl_struct->path);
3344 tl_struct->path = NULL;
3346 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3347 ITypeLib_Release(tl_struct->ptLib);
3352 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3354 MSIPACKAGE* package = param;
3358 typelib_struct tl_struct;
3363 component = MSI_RecordGetString(row,3);
3364 comp = msi_get_loaded_component(package,component);
3366 return ERROR_SUCCESS;
3368 comp->Action = msi_get_component_action( package, comp );
3369 if (comp->Action != INSTALLSTATE_LOCAL)
3371 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3372 return ERROR_SUCCESS;
3375 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3377 TRACE("component has no key path\n");
3378 return ERROR_SUCCESS;
3380 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3382 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3386 guid = MSI_RecordGetString(row,1);
3387 CLSIDFromString( guid, &tl_struct.clsid);
3388 tl_struct.source = strdupW( file->TargetPath );
3389 tl_struct.path = NULL;
3391 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3392 (LONG_PTR)&tl_struct);
3396 LPCWSTR helpid, help_path = NULL;
3399 helpid = MSI_RecordGetString(row,6);
3401 if (helpid) help_path = msi_get_target_folder( package, helpid );
3402 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3405 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3407 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3409 ITypeLib_Release(tl_struct.ptLib);
3410 msi_free(tl_struct.path);
3412 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3414 FreeLibrary(module);
3415 msi_free(tl_struct.source);
3419 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3422 ERR("Failed to load type library: %08x\n", hr);
3423 return ERROR_INSTALL_FAILURE;
3426 ITypeLib_Release(tlib);
3429 return ERROR_SUCCESS;
3432 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3434 static const WCHAR query[] = {
3435 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3436 '`','T','y','p','e','L','i','b','`',0};
3440 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3441 if (rc != ERROR_SUCCESS)
3442 return ERROR_SUCCESS;
3444 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3445 msiobj_release(&view->hdr);
3449 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3451 MSIPACKAGE *package = param;
3452 LPCWSTR component, guid;
3460 component = MSI_RecordGetString( row, 3 );
3461 comp = msi_get_loaded_component( package, component );
3463 return ERROR_SUCCESS;
3465 comp->Action = msi_get_component_action( package, comp );
3466 if (comp->Action != INSTALLSTATE_ABSENT)
3468 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3469 return ERROR_SUCCESS;
3471 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3473 guid = MSI_RecordGetString( row, 1 );
3474 CLSIDFromString( guid, &libid );
3475 version = MSI_RecordGetInteger( row, 4 );
3476 language = MSI_RecordGetInteger( row, 2 );
3479 syskind = SYS_WIN64;
3481 syskind = SYS_WIN32;
3484 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3487 WARN("Failed to unregister typelib: %08x\n", hr);
3490 return ERROR_SUCCESS;
3493 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3495 static const WCHAR query[] = {
3496 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3497 '`','T','y','p','e','L','i','b','`',0};
3501 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3502 if (rc != ERROR_SUCCESS)
3503 return ERROR_SUCCESS;
3505 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3506 msiobj_release( &view->hdr );
3510 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3512 static const WCHAR szlnk[] = {'.','l','n','k',0};
3513 LPCWSTR directory, extension, link_folder;
3514 LPWSTR link_file, filename;
3516 directory = MSI_RecordGetString( row, 2 );
3517 link_folder = msi_get_target_folder( package, directory );
3520 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3523 /* may be needed because of a bug somewhere else */
3524 msi_create_full_path( link_folder );
3526 filename = msi_dup_record_field( row, 3 );
3527 msi_reduce_to_long_filename( filename );
3529 extension = strchrW( filename, '.' );
3530 if (!extension || strcmpiW( extension, szlnk ))
3532 int len = strlenW( filename );
3533 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3534 memcpy( filename + len, szlnk, sizeof(szlnk) );
3536 link_file = msi_build_directory_name( 2, link_folder, filename );
3537 msi_free( filename );
3542 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3544 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3545 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3546 WCHAR *folder, *dest, *path;
3548 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3549 folder = msi_dup_property( package->db, szWindowsFolder );
3552 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3553 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3554 msi_free( appdata );
3556 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3557 msi_create_full_path( dest );
3558 path = msi_build_directory_name( 2, dest, icon_name );
3564 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3566 MSIPACKAGE *package = param;
3567 LPWSTR link_file, deformated, path;
3568 LPCWSTR component, target;
3570 IShellLinkW *sl = NULL;
3571 IPersistFile *pf = NULL;
3574 component = MSI_RecordGetString(row, 4);
3575 comp = msi_get_loaded_component(package, component);
3577 return ERROR_SUCCESS;
3579 comp->Action = msi_get_component_action( package, comp );
3580 if (comp->Action != INSTALLSTATE_LOCAL)
3582 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3583 return ERROR_SUCCESS;
3585 msi_ui_actiondata( package, szCreateShortcuts, row );
3587 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3588 &IID_IShellLinkW, (LPVOID *) &sl );
3592 ERR("CLSID_ShellLink not available\n");
3596 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3599 ERR("QueryInterface(IID_IPersistFile) failed\n");
3603 target = MSI_RecordGetString(row, 5);
3604 if (strchrW(target, '['))
3607 WCHAR *format_string, *p;
3609 if (!(p = strchrW( target, ']' ))) goto err;
3610 len = p - target + 1;
3611 format_string = msi_alloc( (len + 1) * sizeof(WCHAR) );
3612 memcpy( format_string, target, len * sizeof(WCHAR) );
3613 format_string[len] = 0;
3614 deformat_string( package, format_string, &deformated );
3615 msi_free( format_string );
3617 path = msi_alloc( (strlenW( deformated ) + strlenW( p + 1 ) + 2) * sizeof(WCHAR) );
3618 strcpyW( path, deformated );
3619 PathAddBackslashW( path );
3620 strcatW( path, p + 1 );
3621 TRACE("target path is %s\n", debugstr_w(path));
3623 IShellLinkW_SetPath( sl, path );
3624 msi_free( deformated );
3629 FIXME("poorly handled shortcut format, advertised shortcut\n");
3630 IShellLinkW_SetPath(sl,comp->FullKeypath);
3633 if (!MSI_RecordIsNull(row,6))
3635 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3636 deformat_string(package, arguments, &deformated);
3637 IShellLinkW_SetArguments(sl,deformated);
3638 msi_free(deformated);
3641 if (!MSI_RecordIsNull(row,7))
3643 LPCWSTR description = MSI_RecordGetString(row, 7);
3644 IShellLinkW_SetDescription(sl, description);
3647 if (!MSI_RecordIsNull(row,8))
3648 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3650 if (!MSI_RecordIsNull(row,9))
3653 LPCWSTR icon = MSI_RecordGetString(row, 9);
3655 path = msi_build_icon_path(package, icon);
3656 index = MSI_RecordGetInteger(row,10);
3658 /* no value means 0 */
3659 if (index == MSI_NULL_INTEGER)
3662 IShellLinkW_SetIconLocation(sl, path, index);
3666 if (!MSI_RecordIsNull(row,11))
3667 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3669 if (!MSI_RecordIsNull(row,12))
3671 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3672 full_path = msi_get_target_folder( package, wkdir );
3673 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3675 link_file = get_link_file(package, row);
3677 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3678 IPersistFile_Save(pf, link_file, FALSE);
3679 msi_free(link_file);
3683 IPersistFile_Release( pf );
3685 IShellLinkW_Release( sl );
3687 return ERROR_SUCCESS;
3690 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3692 static const WCHAR query[] = {
3693 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3694 '`','S','h','o','r','t','c','u','t','`',0};
3699 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3700 if (rc != ERROR_SUCCESS)
3701 return ERROR_SUCCESS;
3703 res = CoInitialize( NULL );
3705 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3706 msiobj_release(&view->hdr);
3708 if (SUCCEEDED(res)) CoUninitialize();
3712 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3714 MSIPACKAGE *package = param;
3719 component = MSI_RecordGetString( row, 4 );
3720 comp = msi_get_loaded_component( package, component );
3722 return ERROR_SUCCESS;
3724 comp->Action = msi_get_component_action( package, comp );
3725 if (comp->Action != INSTALLSTATE_ABSENT)
3727 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3728 return ERROR_SUCCESS;
3730 msi_ui_actiondata( package, szRemoveShortcuts, row );
3732 link_file = get_link_file( package, row );
3734 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3735 if (!DeleteFileW( link_file ))
3737 WARN("Failed to remove shortcut file %u\n", GetLastError());
3739 msi_free( link_file );
3741 return ERROR_SUCCESS;
3744 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3746 static const WCHAR query[] = {
3747 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3748 '`','S','h','o','r','t','c','u','t','`',0};
3752 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3753 if (rc != ERROR_SUCCESS)
3754 return ERROR_SUCCESS;
3756 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3757 msiobj_release( &view->hdr );
3761 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3763 MSIPACKAGE* package = param;
3771 FileName = MSI_RecordGetString(row,1);
3774 ERR("Unable to get FileName\n");
3775 return ERROR_SUCCESS;
3778 FilePath = msi_build_icon_path(package, FileName);
3780 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3782 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3783 FILE_ATTRIBUTE_NORMAL, NULL);
3785 if (the_file == INVALID_HANDLE_VALUE)
3787 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3789 return ERROR_SUCCESS;
3796 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3797 if (rc != ERROR_SUCCESS)
3799 ERR("Failed to get stream\n");
3800 CloseHandle(the_file);
3801 DeleteFileW(FilePath);
3804 WriteFile(the_file,buffer,sz,&write,NULL);
3805 } while (sz == 1024);
3808 CloseHandle(the_file);
3810 return ERROR_SUCCESS;
3813 static UINT msi_publish_icons(MSIPACKAGE *package)
3815 static const WCHAR query[]= {
3816 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3817 '`','I','c','o','n','`',0};
3821 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3822 if (r == ERROR_SUCCESS)
3824 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3825 msiobj_release(&view->hdr);
3826 if (r != ERROR_SUCCESS)
3829 return ERROR_SUCCESS;
3832 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3838 MSISOURCELISTINFO *info;
3840 r = RegCreateKeyW(hkey, szSourceList, &source);
3841 if (r != ERROR_SUCCESS)
3844 RegCloseKey(source);
3846 buffer = strrchrW(package->PackagePath, '\\') + 1;
3847 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3848 package->Context, MSICODE_PRODUCT,
3849 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3850 if (r != ERROR_SUCCESS)
3853 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3854 package->Context, MSICODE_PRODUCT,
3855 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3856 if (r != ERROR_SUCCESS)
3859 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3860 package->Context, MSICODE_PRODUCT,
3861 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3862 if (r != ERROR_SUCCESS)
3865 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3867 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3868 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3869 info->options, info->value);
3871 MsiSourceListSetInfoW(package->ProductCode, NULL,
3872 info->context, info->options,
3873 info->property, info->value);
3876 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3878 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3879 disk->context, disk->options,
3880 disk->disk_id, disk->volume_label, disk->disk_prompt);
3883 return ERROR_SUCCESS;
3886 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3888 MSIHANDLE hdb, suminfo;
3889 WCHAR guids[MAX_PATH];
3890 WCHAR packcode[SQUISH_GUID_SIZE];
3897 static const WCHAR szARPProductIcon[] =
3898 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3899 static const WCHAR szAssignment[] =
3900 {'A','s','s','i','g','n','m','e','n','t',0};
3901 static const WCHAR szAdvertiseFlags[] =
3902 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3903 static const WCHAR szClients[] =
3904 {'C','l','i','e','n','t','s',0};
3905 static const WCHAR szColon[] = {':',0};
3907 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3908 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3911 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3912 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3915 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3917 buffer = msi_dup_property(package->db, szARPProductIcon);
3920 LPWSTR path = msi_build_icon_path(package, buffer);
3921 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3926 buffer = msi_dup_property(package->db, szProductVersion);
3929 DWORD verdword = msi_version_str_to_dword(buffer);
3930 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3934 msi_reg_set_val_dword(hkey, szAssignment, 0);
3935 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3936 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3937 msi_reg_set_val_str(hkey, szClients, szColon);
3939 hdb = alloc_msihandle(&package->db->hdr);
3941 return ERROR_NOT_ENOUGH_MEMORY;
3943 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3944 MsiCloseHandle(hdb);
3945 if (r != ERROR_SUCCESS)
3949 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3950 NULL, guids, &size);
3951 if (r != ERROR_SUCCESS)
3954 ptr = strchrW(guids, ';');
3956 squash_guid(guids, packcode);
3957 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3960 MsiCloseHandle(suminfo);
3961 return ERROR_SUCCESS;
3964 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3969 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3971 upgrade = msi_dup_property(package->db, szUpgradeCode);
3973 return ERROR_SUCCESS;
3975 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3976 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3978 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3980 if (r != ERROR_SUCCESS)
3982 WARN("failed to open upgrade code key\n");
3984 return ERROR_SUCCESS;
3986 squash_guid(package->ProductCode, squashed_pc);
3987 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3990 return ERROR_SUCCESS;
3993 static BOOL msi_check_publish(MSIPACKAGE *package)
3995 MSIFEATURE *feature;
3997 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3999 feature->Action = msi_get_feature_action( package, feature );
4000 if (feature->Action == INSTALLSTATE_LOCAL)
4007 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4009 MSIFEATURE *feature;
4011 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4013 feature->Action = msi_get_feature_action( package, feature );
4014 if (feature->Action != INSTALLSTATE_ABSENT)
4021 static UINT msi_publish_patches( MSIPACKAGE *package )
4023 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4024 WCHAR patch_squashed[GUID_SIZE];
4025 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4027 MSIPATCHINFO *patch;
4029 WCHAR *p, *all_patches = NULL;
4032 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4033 if (r != ERROR_SUCCESS)
4034 return ERROR_FUNCTION_FAILED;
4036 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4037 if (res != ERROR_SUCCESS)
4039 r = ERROR_FUNCTION_FAILED;
4043 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4044 if (r != ERROR_SUCCESS)
4047 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4049 squash_guid( patch->patchcode, patch_squashed );
4050 len += strlenW( patch_squashed ) + 1;
4053 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4057 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4061 squash_guid( patch->patchcode, p );
4062 p += strlenW( p ) + 1;
4064 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4065 (const BYTE *)patch->transforms,
4066 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4067 if (res != ERROR_SUCCESS)
4070 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4071 if (r != ERROR_SUCCESS)
4074 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4075 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4076 RegCloseKey( patch_key );
4077 if (res != ERROR_SUCCESS)
4080 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4082 res = GetLastError();
4083 ERR("Unable to copy patch package %d\n", res);
4086 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4087 if (res != ERROR_SUCCESS)
4090 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4091 RegCloseKey( patch_key );
4092 if (res != ERROR_SUCCESS)
4096 all_patches[len] = 0;
4097 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4098 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4099 if (res != ERROR_SUCCESS)
4102 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4103 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4104 if (res != ERROR_SUCCESS)
4105 r = ERROR_FUNCTION_FAILED;
4108 RegCloseKey( product_patches_key );
4109 RegCloseKey( patches_key );
4110 RegCloseKey( product_key );
4111 msi_free( all_patches );
4115 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4118 HKEY hukey = NULL, hudkey = NULL;
4121 if (!list_empty(&package->patches))
4123 rc = msi_publish_patches(package);
4124 if (rc != ERROR_SUCCESS)
4128 /* FIXME: also need to publish if the product is in advertise mode */
4129 if (!msi_check_publish(package))
4130 return ERROR_SUCCESS;
4132 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4134 if (rc != ERROR_SUCCESS)
4137 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4138 NULL, &hudkey, TRUE);
4139 if (rc != ERROR_SUCCESS)
4142 rc = msi_publish_upgrade_code(package);
4143 if (rc != ERROR_SUCCESS)
4146 rc = msi_publish_product_properties(package, hukey);
4147 if (rc != ERROR_SUCCESS)
4150 rc = msi_publish_sourcelist(package, hukey);
4151 if (rc != ERROR_SUCCESS)
4154 rc = msi_publish_icons(package);
4157 uirow = MSI_CreateRecord( 1 );
4158 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4159 msi_ui_actiondata( package, szPublishProduct, uirow );
4160 msiobj_release( &uirow->hdr );
4163 RegCloseKey(hudkey);
4167 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4169 WCHAR *filename, *ptr, *folder, *ret;
4170 const WCHAR *dirprop;
4172 filename = msi_dup_record_field( row, 2 );
4173 if (filename && (ptr = strchrW( filename, '|' )))
4178 dirprop = MSI_RecordGetString( row, 3 );
4181 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4182 if (!folder) folder = msi_dup_property( package->db, dirprop );
4185 folder = msi_dup_property( package->db, szWindowsFolder );
4189 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4190 msi_free( filename );
4194 ret = msi_build_directory_name( 2, folder, ptr );
4196 msi_free( filename );
4201 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4203 MSIPACKAGE *package = param;
4204 LPCWSTR component, section, key, value, identifier;
4205 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4210 component = MSI_RecordGetString(row, 8);
4211 comp = msi_get_loaded_component(package,component);
4213 return ERROR_SUCCESS;
4215 comp->Action = msi_get_component_action( package, comp );
4216 if (comp->Action != INSTALLSTATE_LOCAL)
4218 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4219 return ERROR_SUCCESS;
4222 identifier = MSI_RecordGetString(row,1);
4223 section = MSI_RecordGetString(row,4);
4224 key = MSI_RecordGetString(row,5);
4225 value = MSI_RecordGetString(row,6);
4226 action = MSI_RecordGetInteger(row,7);
4228 deformat_string(package,section,&deformated_section);
4229 deformat_string(package,key,&deformated_key);
4230 deformat_string(package,value,&deformated_value);
4232 fullname = get_ini_file_name(package, row);
4236 TRACE("Adding value %s to section %s in %s\n",
4237 debugstr_w(deformated_key), debugstr_w(deformated_section),
4238 debugstr_w(fullname));
4239 WritePrivateProfileStringW(deformated_section, deformated_key,
4240 deformated_value, fullname);
4242 else if (action == 1)
4245 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4246 returned, 10, fullname);
4247 if (returned[0] == 0)
4249 TRACE("Adding value %s to section %s in %s\n",
4250 debugstr_w(deformated_key), debugstr_w(deformated_section),
4251 debugstr_w(fullname));
4253 WritePrivateProfileStringW(deformated_section, deformated_key,
4254 deformated_value, fullname);
4257 else if (action == 3)
4258 FIXME("Append to existing section not yet implemented\n");
4260 uirow = MSI_CreateRecord(4);
4261 MSI_RecordSetStringW(uirow,1,identifier);
4262 MSI_RecordSetStringW(uirow,2,deformated_section);
4263 MSI_RecordSetStringW(uirow,3,deformated_key);
4264 MSI_RecordSetStringW(uirow,4,deformated_value);
4265 msi_ui_actiondata( package, szWriteIniValues, uirow );
4266 msiobj_release( &uirow->hdr );
4269 msi_free(deformated_key);
4270 msi_free(deformated_value);
4271 msi_free(deformated_section);
4272 return ERROR_SUCCESS;
4275 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4277 static const WCHAR query[] = {
4278 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4279 '`','I','n','i','F','i','l','e','`',0};
4283 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4284 if (rc != ERROR_SUCCESS)
4285 return ERROR_SUCCESS;
4287 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4288 msiobj_release(&view->hdr);
4292 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4294 MSIPACKAGE *package = param;
4295 LPCWSTR component, section, key, value, identifier;
4296 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4301 component = MSI_RecordGetString( row, 8 );
4302 comp = msi_get_loaded_component( package, component );
4304 return ERROR_SUCCESS;
4306 comp->Action = msi_get_component_action( package, comp );
4307 if (comp->Action != INSTALLSTATE_ABSENT)
4309 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4310 return ERROR_SUCCESS;
4313 identifier = MSI_RecordGetString( row, 1 );
4314 section = MSI_RecordGetString( row, 4 );
4315 key = MSI_RecordGetString( row, 5 );
4316 value = MSI_RecordGetString( row, 6 );
4317 action = MSI_RecordGetInteger( row, 7 );
4319 deformat_string( package, section, &deformated_section );
4320 deformat_string( package, key, &deformated_key );
4321 deformat_string( package, value, &deformated_value );
4323 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4325 filename = get_ini_file_name( package, row );
4327 TRACE("Removing key %s from section %s in %s\n",
4328 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4330 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4332 WARN("Unable to remove key %u\n", GetLastError());
4334 msi_free( filename );
4337 FIXME("Unsupported action %d\n", action);
4340 uirow = MSI_CreateRecord( 4 );
4341 MSI_RecordSetStringW( uirow, 1, identifier );
4342 MSI_RecordSetStringW( uirow, 2, deformated_section );
4343 MSI_RecordSetStringW( uirow, 3, deformated_key );
4344 MSI_RecordSetStringW( uirow, 4, deformated_value );
4345 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4346 msiobj_release( &uirow->hdr );
4348 msi_free( deformated_key );
4349 msi_free( deformated_value );
4350 msi_free( deformated_section );
4351 return ERROR_SUCCESS;
4354 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4356 MSIPACKAGE *package = param;
4357 LPCWSTR component, section, key, value, identifier;
4358 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4363 component = MSI_RecordGetString( row, 8 );
4364 comp = msi_get_loaded_component( package, component );
4366 return ERROR_SUCCESS;
4368 comp->Action = msi_get_component_action( package, comp );
4369 if (comp->Action != INSTALLSTATE_LOCAL)
4371 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4372 return ERROR_SUCCESS;
4375 identifier = MSI_RecordGetString( row, 1 );
4376 section = MSI_RecordGetString( row, 4 );
4377 key = MSI_RecordGetString( row, 5 );
4378 value = MSI_RecordGetString( row, 6 );
4379 action = MSI_RecordGetInteger( row, 7 );
4381 deformat_string( package, section, &deformated_section );
4382 deformat_string( package, key, &deformated_key );
4383 deformat_string( package, value, &deformated_value );
4385 if (action == msidbIniFileActionRemoveLine)
4387 filename = get_ini_file_name( package, row );
4389 TRACE("Removing key %s from section %s in %s\n",
4390 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4392 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4394 WARN("Unable to remove key %u\n", GetLastError());
4396 msi_free( filename );
4399 FIXME("Unsupported action %d\n", action);
4401 uirow = MSI_CreateRecord( 4 );
4402 MSI_RecordSetStringW( uirow, 1, identifier );
4403 MSI_RecordSetStringW( uirow, 2, deformated_section );
4404 MSI_RecordSetStringW( uirow, 3, deformated_key );
4405 MSI_RecordSetStringW( uirow, 4, deformated_value );
4406 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4407 msiobj_release( &uirow->hdr );
4409 msi_free( deformated_key );
4410 msi_free( deformated_value );
4411 msi_free( deformated_section );
4412 return ERROR_SUCCESS;
4415 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4417 static const WCHAR query[] = {
4418 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4419 '`','I','n','i','F','i','l','e','`',0};
4420 static const WCHAR remove_query[] = {
4421 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4422 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4426 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4427 if (rc == ERROR_SUCCESS)
4429 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4430 msiobj_release( &view->hdr );
4431 if (rc != ERROR_SUCCESS)
4434 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4435 if (rc == ERROR_SUCCESS)
4437 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4438 msiobj_release( &view->hdr );
4439 if (rc != ERROR_SUCCESS)
4442 return ERROR_SUCCESS;
4445 static void register_dll( const WCHAR *dll, BOOL unregister )
4449 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4452 HRESULT (WINAPI *func_ptr)( void );
4453 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4455 func_ptr = (void *)GetProcAddress( hmod, func );
4458 HRESULT hr = func_ptr();
4460 WARN("failed to register dll 0x%08x\n", hr);
4463 WARN("entry point %s not found\n", func);
4464 FreeLibrary( hmod );
4467 WARN("failed to load library %u\n", GetLastError());
4470 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4472 MSIPACKAGE *package = param;
4477 filename = MSI_RecordGetString(row,1);
4478 file = msi_get_loaded_file( package, filename );
4481 WARN("unable to find file %s\n", debugstr_w(filename));
4482 return ERROR_SUCCESS;
4484 file->Component->Action = msi_get_component_action( package, file->Component );
4485 if (file->Component->Action != INSTALLSTATE_LOCAL)
4487 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4488 return ERROR_SUCCESS;
4491 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4492 register_dll( file->TargetPath, FALSE );
4494 uirow = MSI_CreateRecord( 2 );
4495 MSI_RecordSetStringW( uirow, 1, filename );
4496 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4497 msi_ui_actiondata( package, szSelfRegModules, uirow );
4498 msiobj_release( &uirow->hdr );
4500 return ERROR_SUCCESS;
4503 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4505 static const WCHAR query[] = {
4506 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4507 '`','S','e','l','f','R','e','g','`',0};
4511 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4512 if (rc != ERROR_SUCCESS)
4513 return ERROR_SUCCESS;
4515 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4516 msiobj_release(&view->hdr);
4520 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4522 MSIPACKAGE *package = param;
4527 filename = MSI_RecordGetString( row, 1 );
4528 file = msi_get_loaded_file( package, filename );
4531 WARN("unable to find file %s\n", debugstr_w(filename));
4532 return ERROR_SUCCESS;
4534 file->Component->Action = msi_get_component_action( package, file->Component );
4535 if (file->Component->Action != INSTALLSTATE_ABSENT)
4537 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4538 return ERROR_SUCCESS;
4541 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4542 register_dll( file->TargetPath, TRUE );
4544 uirow = MSI_CreateRecord( 2 );
4545 MSI_RecordSetStringW( uirow, 1, filename );
4546 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4547 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4548 msiobj_release( &uirow->hdr );
4550 return ERROR_SUCCESS;
4553 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4555 static const WCHAR query[] = {
4556 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4557 '`','S','e','l','f','R','e','g','`',0};
4561 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4562 if (rc != ERROR_SUCCESS)
4563 return ERROR_SUCCESS;
4565 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4566 msiobj_release( &view->hdr );
4570 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4572 MSIFEATURE *feature;
4574 HKEY hkey = NULL, userdata = NULL;
4576 if (!msi_check_publish(package))
4577 return ERROR_SUCCESS;
4579 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4581 if (rc != ERROR_SUCCESS)
4584 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4586 if (rc != ERROR_SUCCESS)
4589 /* here the guids are base 85 encoded */
4590 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4596 BOOL absent = FALSE;
4599 if (feature->Action != INSTALLSTATE_LOCAL &&
4600 feature->Action != INSTALLSTATE_SOURCE &&
4601 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4604 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4608 if (feature->Feature_Parent)
4609 size += strlenW( feature->Feature_Parent )+2;
4611 data = msi_alloc(size * sizeof(WCHAR));
4614 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4616 MSICOMPONENT* component = cl->component;
4620 if (component->ComponentId)
4622 TRACE("From %s\n",debugstr_w(component->ComponentId));
4623 CLSIDFromString(component->ComponentId, &clsid);
4624 encode_base85_guid(&clsid,buf);
4625 TRACE("to %s\n",debugstr_w(buf));
4630 if (feature->Feature_Parent)
4632 static const WCHAR sep[] = {'\2',0};
4634 strcatW(data,feature->Feature_Parent);
4637 msi_reg_set_val_str( userdata, feature->Feature, data );
4641 if (feature->Feature_Parent)
4642 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4645 size += sizeof(WCHAR);
4646 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4647 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4651 size += 2*sizeof(WCHAR);
4652 data = msi_alloc(size);
4655 if (feature->Feature_Parent)
4656 strcpyW( &data[1], feature->Feature_Parent );
4657 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4663 uirow = MSI_CreateRecord( 1 );
4664 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4665 msi_ui_actiondata( package, szPublishFeatures, uirow );
4666 msiobj_release( &uirow->hdr );
4667 /* FIXME: call msi_ui_progress? */
4672 RegCloseKey(userdata);
4676 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4682 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4684 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4686 if (r == ERROR_SUCCESS)
4688 RegDeleteValueW(hkey, feature->Feature);
4692 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4694 if (r == ERROR_SUCCESS)
4696 RegDeleteValueW(hkey, feature->Feature);
4700 uirow = MSI_CreateRecord( 1 );
4701 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4702 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4703 msiobj_release( &uirow->hdr );
4705 return ERROR_SUCCESS;
4708 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4710 MSIFEATURE *feature;
4712 if (!msi_check_unpublish(package))
4713 return ERROR_SUCCESS;
4715 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4717 msi_unpublish_feature(package, feature);
4720 return ERROR_SUCCESS;
4723 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4727 WCHAR date[9], *val, *buffer;
4728 const WCHAR *prop, *key;
4730 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4731 static const WCHAR modpath_fmt[] =
4732 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4733 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4734 static const WCHAR szModifyPath[] =
4735 {'M','o','d','i','f','y','P','a','t','h',0};
4736 static const WCHAR szUninstallString[] =
4737 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4738 static const WCHAR szEstimatedSize[] =
4739 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4740 static const WCHAR szDisplayVersion[] =
4741 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4742 static const WCHAR szInstallSource[] =
4743 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4744 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4745 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4746 static const WCHAR szAuthorizedCDFPrefix[] =
4747 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4748 static const WCHAR szARPCONTACT[] =
4749 {'A','R','P','C','O','N','T','A','C','T',0};
4750 static const WCHAR szContact[] =
4751 {'C','o','n','t','a','c','t',0};
4752 static const WCHAR szARPCOMMENTS[] =
4753 {'A','R','P','C','O','M','M','E','N','T','S',0};
4754 static const WCHAR szComments[] =
4755 {'C','o','m','m','e','n','t','s',0};
4756 static const WCHAR szProductName[] =
4757 {'P','r','o','d','u','c','t','N','a','m','e',0};
4758 static const WCHAR szDisplayName[] =
4759 {'D','i','s','p','l','a','y','N','a','m','e',0};
4760 static const WCHAR szARPHELPLINK[] =
4761 {'A','R','P','H','E','L','P','L','I','N','K',0};
4762 static const WCHAR szHelpLink[] =
4763 {'H','e','l','p','L','i','n','k',0};
4764 static const WCHAR szARPHELPTELEPHONE[] =
4765 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4766 static const WCHAR szHelpTelephone[] =
4767 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4768 static const WCHAR szARPINSTALLLOCATION[] =
4769 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4770 static const WCHAR szInstallLocation[] =
4771 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4772 static const WCHAR szManufacturer[] =
4773 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4774 static const WCHAR szPublisher[] =
4775 {'P','u','b','l','i','s','h','e','r',0};
4776 static const WCHAR szARPREADME[] =
4777 {'A','R','P','R','E','A','D','M','E',0};
4778 static const WCHAR szReadme[] =
4779 {'R','e','a','d','M','e',0};
4780 static const WCHAR szARPSIZE[] =
4781 {'A','R','P','S','I','Z','E',0};
4782 static const WCHAR szSize[] =
4783 {'S','i','z','e',0};
4784 static const WCHAR szARPURLINFOABOUT[] =
4785 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4786 static const WCHAR szURLInfoAbout[] =
4787 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4788 static const WCHAR szARPURLUPDATEINFO[] =
4789 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4790 static const WCHAR szURLUpdateInfo[] =
4791 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4792 static const WCHAR szARPSYSTEMCOMPONENT[] =
4793 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4794 static const WCHAR szSystemComponent[] =
4795 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4797 static const WCHAR *propval[] = {
4798 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4799 szARPCONTACT, szContact,
4800 szARPCOMMENTS, szComments,
4801 szProductName, szDisplayName,
4802 szARPHELPLINK, szHelpLink,
4803 szARPHELPTELEPHONE, szHelpTelephone,
4804 szARPINSTALLLOCATION, szInstallLocation,
4805 szSourceDir, szInstallSource,
4806 szManufacturer, szPublisher,
4807 szARPREADME, szReadme,
4809 szARPURLINFOABOUT, szURLInfoAbout,
4810 szARPURLUPDATEINFO, szURLUpdateInfo,
4813 const WCHAR **p = propval;
4819 val = msi_dup_property(package->db, prop);
4820 msi_reg_set_val_str(hkey, key, val);
4824 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4825 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4827 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4829 size = deformat_string(package, modpath_fmt, &buffer);
4830 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4831 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4834 /* FIXME: Write real Estimated Size when we have it */
4835 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4837 GetLocalTime(&systime);
4838 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4839 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4841 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4842 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4844 buffer = msi_dup_property(package->db, szProductVersion);
4845 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4848 DWORD verdword = msi_version_str_to_dword(buffer);
4850 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4851 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4852 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4856 return ERROR_SUCCESS;
4859 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4861 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4863 LPWSTR upgrade_code;
4864 HKEY hkey, props, upgrade_key;
4867 /* FIXME: also need to publish if the product is in advertise mode */
4868 if (!msi_check_publish(package))
4869 return ERROR_SUCCESS;
4871 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4872 if (rc != ERROR_SUCCESS)
4875 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4876 if (rc != ERROR_SUCCESS)
4879 rc = msi_publish_install_properties(package, hkey);
4880 if (rc != ERROR_SUCCESS)
4883 rc = msi_publish_install_properties(package, props);
4884 if (rc != ERROR_SUCCESS)
4887 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4890 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4891 if (rc == ERROR_SUCCESS)
4893 squash_guid( package->ProductCode, squashed_pc );
4894 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4895 RegCloseKey( upgrade_key );
4897 msi_free( upgrade_code );
4899 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4900 package->delete_on_close = FALSE;
4903 uirow = MSI_CreateRecord( 1 );
4904 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4905 msi_ui_actiondata( package, szRegisterProduct, uirow );
4906 msiobj_release( &uirow->hdr );
4909 return ERROR_SUCCESS;
4912 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4914 return execute_script(package,INSTALL_SCRIPT);
4917 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4919 MSIPACKAGE *package = param;
4920 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4921 WCHAR *p, *icon_path;
4923 if (!icon) return ERROR_SUCCESS;
4924 if ((icon_path = msi_build_icon_path( package, icon )))
4926 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4927 DeleteFileW( icon_path );
4928 if ((p = strrchrW( icon_path, '\\' )))
4931 RemoveDirectoryW( icon_path );
4933 msi_free( icon_path );
4935 return ERROR_SUCCESS;
4938 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4940 static const WCHAR query[]= {
4941 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4945 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4946 if (r == ERROR_SUCCESS)
4948 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4949 msiobj_release( &view->hdr );
4950 if (r != ERROR_SUCCESS)
4953 return ERROR_SUCCESS;
4956 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4958 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4959 WCHAR *upgrade, **features;
4960 BOOL full_uninstall = TRUE;
4961 MSIFEATURE *feature;
4962 MSIPATCHINFO *patch;
4965 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4967 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4969 features = msi_split_string( remove, ',' );
4970 for (i = 0; features && features[i]; i++)
4972 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4976 if (!full_uninstall)
4977 return ERROR_SUCCESS;
4979 MSIREG_DeleteProductKey(package->ProductCode);
4980 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4981 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4983 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4984 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4985 MSIREG_DeleteUserProductKey(package->ProductCode);
4986 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4988 upgrade = msi_dup_property(package->db, szUpgradeCode);
4991 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4992 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4996 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4998 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4999 if (!strcmpW( package->ProductCode, patch->products ))
5001 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5002 patch->delete_on_close = TRUE;
5004 /* FIXME: remove local patch package if this is the last product */
5006 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5007 package->delete_on_close = TRUE;
5009 msi_unpublish_icons( package );
5010 return ERROR_SUCCESS;
5013 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5018 /* turn off scheduling */
5019 package->script->CurrentlyScripting= FALSE;
5021 /* first do the same as an InstallExecute */
5022 rc = ACTION_InstallExecute(package);
5023 if (rc != ERROR_SUCCESS)
5026 /* then handle Commit Actions */
5027 rc = execute_script(package,COMMIT_SCRIPT);
5028 if (rc != ERROR_SUCCESS)
5031 remove = msi_dup_property(package->db, szRemove);
5032 rc = msi_unpublish_product(package, remove);
5037 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5039 static const WCHAR RunOnce[] = {
5040 'S','o','f','t','w','a','r','e','\\',
5041 'M','i','c','r','o','s','o','f','t','\\',
5042 'W','i','n','d','o','w','s','\\',
5043 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5044 'R','u','n','O','n','c','e',0};
5045 static const WCHAR InstallRunOnce[] = {
5046 'S','o','f','t','w','a','r','e','\\',
5047 'M','i','c','r','o','s','o','f','t','\\',
5048 'W','i','n','d','o','w','s','\\',
5049 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5050 'I','n','s','t','a','l','l','e','r','\\',
5051 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5053 static const WCHAR msiexec_fmt[] = {
5055 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5056 '\"','%','s','\"',0};
5057 static const WCHAR install_fmt[] = {
5058 '/','I',' ','\"','%','s','\"',' ',
5059 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5060 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5061 WCHAR buffer[256], sysdir[MAX_PATH];
5063 WCHAR squished_pc[100];
5065 squash_guid(package->ProductCode,squished_pc);
5067 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5068 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5069 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5072 msi_reg_set_val_str( hkey, squished_pc, buffer );
5075 TRACE("Reboot command %s\n",debugstr_w(buffer));
5077 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5078 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5080 msi_reg_set_val_str( hkey, squished_pc, buffer );
5083 return ERROR_INSTALL_SUSPEND;
5086 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5088 static const WCHAR query[] =
5089 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5090 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5091 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5092 MSIRECORD *rec, *row;
5098 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5100 rec = MSI_CreateRecord( count + 2 );
5101 str = MSI_RecordGetString( row, 1 );
5102 MSI_RecordSetStringW( rec, 0, str );
5103 msiobj_release( &row->hdr );
5104 MSI_RecordSetInteger( rec, 1, error );
5106 va_start( va, count );
5107 for (i = 0; i < count; i++)
5109 str = va_arg( va, const WCHAR *);
5110 MSI_RecordSetStringW( rec, i + 2, str );
5114 MSI_FormatRecordW( package, rec, NULL, &size );
5116 data = msi_alloc( size * sizeof(WCHAR) );
5117 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5119 msiobj_release( &rec->hdr );
5123 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5129 * We are currently doing what should be done here in the top level Install
5130 * however for Administrative and uninstalls this step will be needed
5132 if (!package->PackagePath)
5133 return ERROR_SUCCESS;
5135 msi_set_sourcedir_props(package, TRUE);
5137 attrib = GetFileAttributesW(package->db->path);
5138 if (attrib == INVALID_FILE_ATTRIBUTES)
5143 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5144 package->Context, MSICODE_PRODUCT,
5145 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5146 if (rc == ERROR_MORE_DATA)
5148 prompt = msi_alloc(size * sizeof(WCHAR));
5149 MsiSourceListGetInfoW(package->ProductCode, NULL,
5150 package->Context, MSICODE_PRODUCT,
5151 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5154 prompt = strdupW(package->db->path);
5156 msg = msi_build_error_string(package, 1302, 1, prompt);
5158 while(attrib == INVALID_FILE_ATTRIBUTES)
5160 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5164 return ERROR_INSTALL_USEREXIT;
5166 attrib = GetFileAttributesW(package->db->path);
5172 return ERROR_SUCCESS;
5177 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5180 LPWSTR buffer, productid = NULL;
5181 UINT i, rc = ERROR_SUCCESS;
5184 static const WCHAR szPropKeys[][80] =
5186 {'P','r','o','d','u','c','t','I','D',0},
5187 {'U','S','E','R','N','A','M','E',0},
5188 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5192 static const WCHAR szRegKeys[][80] =
5194 {'P','r','o','d','u','c','t','I','D',0},
5195 {'R','e','g','O','w','n','e','r',0},
5196 {'R','e','g','C','o','m','p','a','n','y',0},
5200 if (msi_check_unpublish(package))
5202 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5206 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5210 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5212 if (rc != ERROR_SUCCESS)
5215 for( i = 0; szPropKeys[i][0]; i++ )
5217 buffer = msi_dup_property( package->db, szPropKeys[i] );
5218 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5223 uirow = MSI_CreateRecord( 1 );
5224 MSI_RecordSetStringW( uirow, 1, productid );
5225 msi_ui_actiondata( package, szRegisterUser, uirow );
5226 msiobj_release( &uirow->hdr );
5228 msi_free(productid);
5234 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5238 package->script->InWhatSequence |= SEQUENCE_EXEC;
5239 rc = ACTION_ProcessExecSequence(package,FALSE);
5243 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5245 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5246 WCHAR productid_85[21], component_85[21], *ret;
5250 /* > is used if there is a component GUID and < if not. */
5252 productid_85[0] = 0;
5253 component_85[0] = 0;
5254 CLSIDFromString( package->ProductCode, &clsid );
5256 encode_base85_guid( &clsid, productid_85 );
5259 CLSIDFromString( component->ComponentId, &clsid );
5260 encode_base85_guid( &clsid, component_85 );
5263 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5264 debugstr_w(component_85));
5266 sz = 20 + strlenW( feature ) + 20 + 3;
5267 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5268 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5272 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5274 MSIPACKAGE *package = param;
5275 LPCWSTR compgroupid, component, feature, qualifier, text;
5276 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5285 feature = MSI_RecordGetString(rec, 5);
5286 feat = msi_get_loaded_feature(package, feature);
5288 return ERROR_SUCCESS;
5290 feat->Action = msi_get_feature_action( package, feat );
5291 if (feat->Action != INSTALLSTATE_LOCAL &&
5292 feat->Action != INSTALLSTATE_SOURCE &&
5293 feat->Action != INSTALLSTATE_ADVERTISED)
5295 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5296 return ERROR_SUCCESS;
5299 component = MSI_RecordGetString(rec, 3);
5300 comp = msi_get_loaded_component(package, component);
5302 return ERROR_SUCCESS;
5304 compgroupid = MSI_RecordGetString(rec,1);
5305 qualifier = MSI_RecordGetString(rec,2);
5307 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5308 if (rc != ERROR_SUCCESS)
5311 advertise = msi_create_component_advertise_string( package, comp, feature );
5312 text = MSI_RecordGetString( rec, 4 );
5315 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5316 strcpyW( p, advertise );
5318 msi_free( advertise );
5321 existing = msi_reg_get_val_str( hkey, qualifier );
5323 sz = strlenW( advertise ) + 1;
5326 for (p = existing; *p; p += len)
5328 len = strlenW( p ) + 1;
5329 if (strcmpW( advertise, p )) sz += len;
5332 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5334 rc = ERROR_OUTOFMEMORY;
5340 for (p = existing; *p; p += len)
5342 len = strlenW( p ) + 1;
5343 if (strcmpW( advertise, p ))
5345 memcpy( q, p, len * sizeof(WCHAR) );
5350 strcpyW( q, advertise );
5351 q[strlenW( q ) + 1] = 0;
5353 msi_reg_set_val_multi_str( hkey, qualifier, output );
5358 msi_free( advertise );
5359 msi_free( existing );
5362 uirow = MSI_CreateRecord( 2 );
5363 MSI_RecordSetStringW( uirow, 1, compgroupid );
5364 MSI_RecordSetStringW( uirow, 2, qualifier);
5365 msi_ui_actiondata( package, szPublishComponents, uirow );
5366 msiobj_release( &uirow->hdr );
5367 /* FIXME: call ui_progress? */
5373 * At present I am ignorning the advertised components part of this and only
5374 * focusing on the qualified component sets
5376 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5378 static const WCHAR query[] = {
5379 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5380 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5384 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5385 if (rc != ERROR_SUCCESS)
5386 return ERROR_SUCCESS;
5388 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5389 msiobj_release(&view->hdr);
5393 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5395 static const WCHAR szInstallerComponents[] = {
5396 'S','o','f','t','w','a','r','e','\\',
5397 'M','i','c','r','o','s','o','f','t','\\',
5398 'I','n','s','t','a','l','l','e','r','\\',
5399 'C','o','m','p','o','n','e','n','t','s','\\',0};
5401 MSIPACKAGE *package = param;
5402 LPCWSTR compgroupid, component, feature, qualifier;
5406 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5409 feature = MSI_RecordGetString( rec, 5 );
5410 feat = msi_get_loaded_feature( package, feature );
5412 return ERROR_SUCCESS;
5414 feat->Action = msi_get_feature_action( package, feat );
5415 if (feat->Action != INSTALLSTATE_ABSENT)
5417 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5418 return ERROR_SUCCESS;
5421 component = MSI_RecordGetString( rec, 3 );
5422 comp = msi_get_loaded_component( package, component );
5424 return ERROR_SUCCESS;
5426 compgroupid = MSI_RecordGetString( rec, 1 );
5427 qualifier = MSI_RecordGetString( rec, 2 );
5429 squash_guid( compgroupid, squashed );
5430 strcpyW( keypath, szInstallerComponents );
5431 strcatW( keypath, squashed );
5433 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5434 if (res != ERROR_SUCCESS)
5436 WARN("Unable to delete component key %d\n", res);
5439 uirow = MSI_CreateRecord( 2 );
5440 MSI_RecordSetStringW( uirow, 1, compgroupid );
5441 MSI_RecordSetStringW( uirow, 2, qualifier );
5442 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5443 msiobj_release( &uirow->hdr );
5445 return ERROR_SUCCESS;
5448 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5450 static const WCHAR query[] = {
5451 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5452 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5456 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5457 if (rc != ERROR_SUCCESS)
5458 return ERROR_SUCCESS;
5460 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5461 msiobj_release( &view->hdr );
5465 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5467 static const WCHAR query[] =
5468 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5469 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5470 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5471 MSIPACKAGE *package = param;
5472 MSICOMPONENT *component;
5475 SC_HANDLE hscm = NULL, service = NULL;
5477 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5478 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5479 DWORD serv_type, start_type, err_control;
5480 SERVICE_DESCRIPTIONW sd = {NULL};
5482 comp = MSI_RecordGetString( rec, 12 );
5483 component = msi_get_loaded_component( package, comp );
5486 WARN("service component not found\n");
5489 component->Action = msi_get_component_action( package, component );
5490 if (component->Action != INSTALLSTATE_LOCAL)
5492 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5495 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5498 ERR("Failed to open the SC Manager!\n");
5502 start_type = MSI_RecordGetInteger(rec, 5);
5503 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5506 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5507 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5508 serv_type = MSI_RecordGetInteger(rec, 4);
5509 err_control = MSI_RecordGetInteger(rec, 6);
5510 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5511 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5512 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5513 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5514 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5515 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5517 /* fetch the service path */
5518 row = MSI_QueryGetRecord(package->db, query, comp);
5521 ERR("Query failed\n");
5524 key = MSI_RecordGetString(row, 6);
5525 file = msi_get_loaded_file(package, key);
5526 msiobj_release(&row->hdr);
5529 ERR("Failed to load the service file\n");
5533 if (!args || !args[0]) image_path = file->TargetPath;
5536 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5537 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5538 return ERROR_OUTOFMEMORY;
5540 strcpyW(image_path, file->TargetPath);
5541 strcatW(image_path, szSpace);
5542 strcatW(image_path, args);
5544 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5545 start_type, err_control, image_path, load_order,
5546 NULL, depends, serv_name, pass);
5550 if (GetLastError() != ERROR_SERVICE_EXISTS)
5551 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5553 else if (sd.lpDescription)
5555 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5556 WARN("failed to set service description %u\n", GetLastError());
5559 if (image_path != file->TargetPath) msi_free(image_path);
5561 CloseServiceHandle(service);
5562 CloseServiceHandle(hscm);
5565 msi_free(sd.lpDescription);
5566 msi_free(load_order);
5567 msi_free(serv_name);
5572 return ERROR_SUCCESS;
5575 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5577 static const WCHAR query[] = {
5578 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5579 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5583 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5584 if (rc != ERROR_SUCCESS)
5585 return ERROR_SUCCESS;
5587 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5588 msiobj_release(&view->hdr);
5592 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5593 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5595 LPCWSTR *vector, *temp_vector;
5599 static const WCHAR separator[] = {'[','~',']',0};
5602 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5607 vector = msi_alloc(sizeof(LPWSTR));
5615 vector[*numargs - 1] = p;
5617 if ((q = strstrW(p, separator)))
5621 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5627 vector = temp_vector;
5636 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5638 MSIPACKAGE *package = param;
5641 SC_HANDLE scm = NULL, service = NULL;
5642 LPCWSTR component, *vector = NULL;
5643 LPWSTR name, args, display_name = NULL;
5644 DWORD event, numargs, len, wait, dummy;
5645 UINT r = ERROR_FUNCTION_FAILED;
5646 SERVICE_STATUS_PROCESS status;
5647 ULONGLONG start_time;
5649 component = MSI_RecordGetString(rec, 6);
5650 comp = msi_get_loaded_component(package, component);
5652 return ERROR_SUCCESS;
5654 comp->Action = msi_get_component_action( package, comp );
5655 if (comp->Action != INSTALLSTATE_LOCAL)
5657 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5658 return ERROR_SUCCESS;
5661 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5662 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5663 event = MSI_RecordGetInteger(rec, 3);
5664 wait = MSI_RecordGetInteger(rec, 5);
5666 if (!(event & msidbServiceControlEventStart))
5672 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5675 ERR("Failed to open the service control manager\n");
5680 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5681 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5683 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5684 GetServiceDisplayNameW( scm, name, display_name, &len );
5687 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5690 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5694 vector = msi_service_args_to_vector(args, &numargs);
5696 if (!StartServiceW(service, numargs, vector) &&
5697 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5699 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5706 /* wait for at most 30 seconds for the service to be up and running */
5707 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5708 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5710 TRACE("failed to query service status (%u)\n", GetLastError());
5713 start_time = GetTickCount64();
5714 while (status.dwCurrentState == SERVICE_START_PENDING)
5716 if (GetTickCount64() - start_time > 30000) break;
5718 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5719 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5721 TRACE("failed to query service status (%u)\n", GetLastError());
5725 if (status.dwCurrentState != SERVICE_RUNNING)
5727 WARN("service failed to start %u\n", status.dwCurrentState);
5728 r = ERROR_FUNCTION_FAILED;
5733 uirow = MSI_CreateRecord( 2 );
5734 MSI_RecordSetStringW( uirow, 1, display_name );
5735 MSI_RecordSetStringW( uirow, 2, name );
5736 msi_ui_actiondata( package, szStartServices, uirow );
5737 msiobj_release( &uirow->hdr );
5739 CloseServiceHandle(service);
5740 CloseServiceHandle(scm);
5745 msi_free(display_name);
5749 static UINT ACTION_StartServices( MSIPACKAGE *package )
5751 static const WCHAR query[] = {
5752 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5753 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5757 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5758 if (rc != ERROR_SUCCESS)
5759 return ERROR_SUCCESS;
5761 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5762 msiobj_release(&view->hdr);
5766 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5768 DWORD i, needed, count;
5769 ENUM_SERVICE_STATUSW *dependencies;
5773 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5774 0, &needed, &count))
5777 if (GetLastError() != ERROR_MORE_DATA)
5780 dependencies = msi_alloc(needed);
5784 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5785 needed, &needed, &count))
5788 for (i = 0; i < count; i++)
5790 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5791 SERVICE_STOP | SERVICE_QUERY_STATUS);
5795 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5802 msi_free(dependencies);
5806 static UINT stop_service( LPCWSTR name )
5808 SC_HANDLE scm = NULL, service = NULL;
5809 SERVICE_STATUS status;
5810 SERVICE_STATUS_PROCESS ssp;
5813 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5816 WARN("Failed to open the SCM: %d\n", GetLastError());
5820 service = OpenServiceW(scm, name,
5822 SERVICE_QUERY_STATUS |
5823 SERVICE_ENUMERATE_DEPENDENTS);
5826 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5830 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5831 sizeof(SERVICE_STATUS_PROCESS), &needed))
5833 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5837 if (ssp.dwCurrentState == SERVICE_STOPPED)
5840 stop_service_dependents(scm, service);
5842 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5843 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5846 CloseServiceHandle(service);
5847 CloseServiceHandle(scm);
5849 return ERROR_SUCCESS;
5852 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5854 MSIPACKAGE *package = param;
5858 LPWSTR name = NULL, display_name = NULL;
5862 event = MSI_RecordGetInteger( rec, 3 );
5863 if (!(event & msidbServiceControlEventStop))
5864 return ERROR_SUCCESS;
5866 component = MSI_RecordGetString( rec, 6 );
5867 comp = msi_get_loaded_component( package, component );
5869 return ERROR_SUCCESS;
5871 comp->Action = msi_get_component_action( package, comp );
5872 if (comp->Action != INSTALLSTATE_ABSENT)
5874 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5875 return ERROR_SUCCESS;
5878 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5881 ERR("Failed to open the service control manager\n");
5886 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5887 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5889 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5890 GetServiceDisplayNameW( scm, name, display_name, &len );
5892 CloseServiceHandle( scm );
5894 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5895 stop_service( name );
5898 uirow = MSI_CreateRecord( 2 );
5899 MSI_RecordSetStringW( uirow, 1, display_name );
5900 MSI_RecordSetStringW( uirow, 2, name );
5901 msi_ui_actiondata( package, szStopServices, uirow );
5902 msiobj_release( &uirow->hdr );
5905 msi_free( display_name );
5906 return ERROR_SUCCESS;
5909 static UINT ACTION_StopServices( MSIPACKAGE *package )
5911 static const WCHAR query[] = {
5912 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5913 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5917 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5918 if (rc != ERROR_SUCCESS)
5919 return ERROR_SUCCESS;
5921 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5922 msiobj_release(&view->hdr);
5926 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5928 MSIPACKAGE *package = param;
5932 LPWSTR name = NULL, display_name = NULL;
5934 SC_HANDLE scm = NULL, service = NULL;
5936 event = MSI_RecordGetInteger( rec, 3 );
5937 if (!(event & msidbServiceControlEventDelete))
5938 return ERROR_SUCCESS;
5940 component = MSI_RecordGetString(rec, 6);
5941 comp = msi_get_loaded_component(package, component);
5943 return ERROR_SUCCESS;
5945 comp->Action = msi_get_component_action( package, comp );
5946 if (comp->Action != INSTALLSTATE_ABSENT)
5948 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5949 return ERROR_SUCCESS;
5952 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5953 stop_service( name );
5955 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5958 WARN("Failed to open the SCM: %d\n", GetLastError());
5963 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5964 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5966 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5967 GetServiceDisplayNameW( scm, name, display_name, &len );
5970 service = OpenServiceW( scm, name, DELETE );
5973 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5977 if (!DeleteService( service ))
5978 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5981 uirow = MSI_CreateRecord( 2 );
5982 MSI_RecordSetStringW( uirow, 1, display_name );
5983 MSI_RecordSetStringW( uirow, 2, name );
5984 msi_ui_actiondata( package, szDeleteServices, uirow );
5985 msiobj_release( &uirow->hdr );
5987 CloseServiceHandle( service );
5988 CloseServiceHandle( scm );
5990 msi_free( display_name );
5992 return ERROR_SUCCESS;
5995 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5997 static const WCHAR query[] = {
5998 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5999 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6003 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6004 if (rc != ERROR_SUCCESS)
6005 return ERROR_SUCCESS;
6007 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6008 msiobj_release( &view->hdr );
6012 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6014 MSIPACKAGE *package = param;
6015 LPWSTR driver, driver_path, ptr;
6016 WCHAR outpath[MAX_PATH];
6017 MSIFILE *driver_file = NULL, *setup_file = NULL;
6020 LPCWSTR desc, file_key, component;
6022 UINT r = ERROR_SUCCESS;
6024 static const WCHAR driver_fmt[] = {
6025 'D','r','i','v','e','r','=','%','s',0};
6026 static const WCHAR setup_fmt[] = {
6027 'S','e','t','u','p','=','%','s',0};
6028 static const WCHAR usage_fmt[] = {
6029 'F','i','l','e','U','s','a','g','e','=','1',0};
6031 component = MSI_RecordGetString( rec, 2 );
6032 comp = msi_get_loaded_component( package, component );
6034 return ERROR_SUCCESS;
6036 comp->Action = msi_get_component_action( package, comp );
6037 if (comp->Action != INSTALLSTATE_LOCAL)
6039 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6040 return ERROR_SUCCESS;
6042 desc = MSI_RecordGetString(rec, 3);
6044 file_key = MSI_RecordGetString( rec, 4 );
6045 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6047 file_key = MSI_RecordGetString( rec, 5 );
6048 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6052 ERR("ODBC Driver entry not found!\n");
6053 return ERROR_FUNCTION_FAILED;
6056 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6058 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6059 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6061 driver = msi_alloc(len * sizeof(WCHAR));
6063 return ERROR_OUTOFMEMORY;
6066 lstrcpyW(ptr, desc);
6067 ptr += lstrlenW(ptr) + 1;
6069 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6074 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6078 lstrcpyW(ptr, usage_fmt);
6079 ptr += lstrlenW(ptr) + 1;
6082 driver_path = strdupW(driver_file->TargetPath);
6083 ptr = strrchrW(driver_path, '\\');
6084 if (ptr) *ptr = '\0';
6086 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6087 NULL, ODBC_INSTALL_COMPLETE, &usage))
6089 ERR("Failed to install SQL driver!\n");
6090 r = ERROR_FUNCTION_FAILED;
6093 uirow = MSI_CreateRecord( 5 );
6094 MSI_RecordSetStringW( uirow, 1, desc );
6095 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6096 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6097 msi_ui_actiondata( package, szInstallODBC, uirow );
6098 msiobj_release( &uirow->hdr );
6101 msi_free(driver_path);
6106 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6108 MSIPACKAGE *package = param;
6109 LPWSTR translator, translator_path, ptr;
6110 WCHAR outpath[MAX_PATH];
6111 MSIFILE *translator_file = NULL, *setup_file = NULL;
6114 LPCWSTR desc, file_key, component;
6116 UINT r = ERROR_SUCCESS;
6118 static const WCHAR translator_fmt[] = {
6119 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6120 static const WCHAR setup_fmt[] = {
6121 'S','e','t','u','p','=','%','s',0};
6123 component = MSI_RecordGetString( rec, 2 );
6124 comp = msi_get_loaded_component( package, component );
6126 return ERROR_SUCCESS;
6128 comp->Action = msi_get_component_action( package, comp );
6129 if (comp->Action != INSTALLSTATE_LOCAL)
6131 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6132 return ERROR_SUCCESS;
6134 desc = MSI_RecordGetString(rec, 3);
6136 file_key = MSI_RecordGetString( rec, 4 );
6137 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6139 file_key = MSI_RecordGetString( rec, 5 );
6140 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6142 if (!translator_file)
6144 ERR("ODBC Translator entry not found!\n");
6145 return ERROR_FUNCTION_FAILED;
6148 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6150 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6152 translator = msi_alloc(len * sizeof(WCHAR));
6154 return ERROR_OUTOFMEMORY;
6157 lstrcpyW(ptr, desc);
6158 ptr += lstrlenW(ptr) + 1;
6160 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6165 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6170 translator_path = strdupW(translator_file->TargetPath);
6171 ptr = strrchrW(translator_path, '\\');
6172 if (ptr) *ptr = '\0';
6174 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6175 NULL, ODBC_INSTALL_COMPLETE, &usage))
6177 ERR("Failed to install SQL translator!\n");
6178 r = ERROR_FUNCTION_FAILED;
6181 uirow = MSI_CreateRecord( 5 );
6182 MSI_RecordSetStringW( uirow, 1, desc );
6183 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6184 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6185 msi_ui_actiondata( package, szInstallODBC, uirow );
6186 msiobj_release( &uirow->hdr );
6188 msi_free(translator);
6189 msi_free(translator_path);
6194 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6196 MSIPACKAGE *package = param;
6199 LPCWSTR desc, driver, component;
6200 WORD request = ODBC_ADD_SYS_DSN;
6203 UINT r = ERROR_SUCCESS;
6206 static const WCHAR attrs_fmt[] = {
6207 'D','S','N','=','%','s',0 };
6209 component = MSI_RecordGetString( rec, 2 );
6210 comp = msi_get_loaded_component( package, component );
6212 return ERROR_SUCCESS;
6214 comp->Action = msi_get_component_action( package, comp );
6215 if (comp->Action != INSTALLSTATE_LOCAL)
6217 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6218 return ERROR_SUCCESS;
6221 desc = MSI_RecordGetString(rec, 3);
6222 driver = MSI_RecordGetString(rec, 4);
6223 registration = MSI_RecordGetInteger(rec, 5);
6225 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6226 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6228 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6229 attrs = msi_alloc(len * sizeof(WCHAR));
6231 return ERROR_OUTOFMEMORY;
6233 len = sprintfW(attrs, attrs_fmt, desc);
6236 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6238 ERR("Failed to install SQL data source!\n");
6239 r = ERROR_FUNCTION_FAILED;
6242 uirow = MSI_CreateRecord( 5 );
6243 MSI_RecordSetStringW( uirow, 1, desc );
6244 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6245 MSI_RecordSetInteger( uirow, 3, request );
6246 msi_ui_actiondata( package, szInstallODBC, uirow );
6247 msiobj_release( &uirow->hdr );
6254 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6256 static const WCHAR driver_query[] = {
6257 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6258 'O','D','B','C','D','r','i','v','e','r',0};
6259 static const WCHAR translator_query[] = {
6260 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6261 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6262 static const WCHAR source_query[] = {
6263 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6264 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6268 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6269 if (rc == ERROR_SUCCESS)
6271 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6272 msiobj_release(&view->hdr);
6273 if (rc != ERROR_SUCCESS)
6276 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6277 if (rc == ERROR_SUCCESS)
6279 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6280 msiobj_release(&view->hdr);
6281 if (rc != ERROR_SUCCESS)
6284 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6285 if (rc == ERROR_SUCCESS)
6287 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6288 msiobj_release(&view->hdr);
6289 if (rc != ERROR_SUCCESS)
6292 return ERROR_SUCCESS;
6295 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6297 MSIPACKAGE *package = param;
6301 LPCWSTR desc, component;
6303 component = MSI_RecordGetString( rec, 2 );
6304 comp = msi_get_loaded_component( package, component );
6306 return ERROR_SUCCESS;
6308 comp->Action = msi_get_component_action( package, comp );
6309 if (comp->Action != INSTALLSTATE_ABSENT)
6311 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6312 return ERROR_SUCCESS;
6315 desc = MSI_RecordGetString( rec, 3 );
6316 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6318 WARN("Failed to remove ODBC driver\n");
6322 FIXME("Usage count reached 0\n");
6325 uirow = MSI_CreateRecord( 2 );
6326 MSI_RecordSetStringW( uirow, 1, desc );
6327 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6328 msi_ui_actiondata( package, szRemoveODBC, uirow );
6329 msiobj_release( &uirow->hdr );
6331 return ERROR_SUCCESS;
6334 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6336 MSIPACKAGE *package = param;
6340 LPCWSTR desc, component;
6342 component = MSI_RecordGetString( rec, 2 );
6343 comp = msi_get_loaded_component( package, component );
6345 return ERROR_SUCCESS;
6347 comp->Action = msi_get_component_action( package, comp );
6348 if (comp->Action != INSTALLSTATE_ABSENT)
6350 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6351 return ERROR_SUCCESS;
6354 desc = MSI_RecordGetString( rec, 3 );
6355 if (!SQLRemoveTranslatorW( desc, &usage ))
6357 WARN("Failed to remove ODBC translator\n");
6361 FIXME("Usage count reached 0\n");
6364 uirow = MSI_CreateRecord( 2 );
6365 MSI_RecordSetStringW( uirow, 1, desc );
6366 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6367 msi_ui_actiondata( package, szRemoveODBC, uirow );
6368 msiobj_release( &uirow->hdr );
6370 return ERROR_SUCCESS;
6373 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6375 MSIPACKAGE *package = param;
6379 LPCWSTR desc, driver, component;
6380 WORD request = ODBC_REMOVE_SYS_DSN;
6384 static const WCHAR attrs_fmt[] = {
6385 'D','S','N','=','%','s',0 };
6387 component = MSI_RecordGetString( rec, 2 );
6388 comp = msi_get_loaded_component( package, component );
6390 return ERROR_SUCCESS;
6392 comp->Action = msi_get_component_action( package, comp );
6393 if (comp->Action != INSTALLSTATE_ABSENT)
6395 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6396 return ERROR_SUCCESS;
6399 desc = MSI_RecordGetString( rec, 3 );
6400 driver = MSI_RecordGetString( rec, 4 );
6401 registration = MSI_RecordGetInteger( rec, 5 );
6403 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6404 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6406 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6407 attrs = msi_alloc( len * sizeof(WCHAR) );
6409 return ERROR_OUTOFMEMORY;
6411 FIXME("Use ODBCSourceAttribute table\n");
6413 len = sprintfW( attrs, attrs_fmt, desc );
6416 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6418 WARN("Failed to remove ODBC data source\n");
6422 uirow = MSI_CreateRecord( 3 );
6423 MSI_RecordSetStringW( uirow, 1, desc );
6424 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6425 MSI_RecordSetInteger( uirow, 3, request );
6426 msi_ui_actiondata( package, szRemoveODBC, uirow );
6427 msiobj_release( &uirow->hdr );
6429 return ERROR_SUCCESS;
6432 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6434 static const WCHAR driver_query[] = {
6435 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6436 'O','D','B','C','D','r','i','v','e','r',0};
6437 static const WCHAR translator_query[] = {
6438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6439 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6440 static const WCHAR source_query[] = {
6441 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6442 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6446 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6447 if (rc == ERROR_SUCCESS)
6449 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6450 msiobj_release( &view->hdr );
6451 if (rc != ERROR_SUCCESS)
6454 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6455 if (rc == ERROR_SUCCESS)
6457 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6458 msiobj_release( &view->hdr );
6459 if (rc != ERROR_SUCCESS)
6462 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6463 if (rc == ERROR_SUCCESS)
6465 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6466 msiobj_release( &view->hdr );
6467 if (rc != ERROR_SUCCESS)
6470 return ERROR_SUCCESS;
6473 #define ENV_ACT_SETALWAYS 0x1
6474 #define ENV_ACT_SETABSENT 0x2
6475 #define ENV_ACT_REMOVE 0x4
6476 #define ENV_ACT_REMOVEMATCH 0x8
6478 #define ENV_MOD_MACHINE 0x20000000
6479 #define ENV_MOD_APPEND 0x40000000
6480 #define ENV_MOD_PREFIX 0x80000000
6481 #define ENV_MOD_MASK 0xC0000000
6483 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6485 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6487 LPCWSTR cptr = *name;
6489 static const WCHAR prefix[] = {'[','~',']',0};
6490 static const int prefix_len = 3;
6496 *flags |= ENV_ACT_SETALWAYS;
6497 else if (*cptr == '+')
6498 *flags |= ENV_ACT_SETABSENT;
6499 else if (*cptr == '-')
6500 *flags |= ENV_ACT_REMOVE;
6501 else if (*cptr == '!')
6502 *flags |= ENV_ACT_REMOVEMATCH;
6503 else if (*cptr == '*')
6504 *flags |= ENV_MOD_MACHINE;
6514 ERR("Missing environment variable\n");
6515 return ERROR_FUNCTION_FAILED;
6520 LPCWSTR ptr = *value;
6521 if (!strncmpW(ptr, prefix, prefix_len))
6523 if (ptr[prefix_len] == szSemiColon[0])
6525 *flags |= ENV_MOD_APPEND;
6526 *value += lstrlenW(prefix);
6533 else if (lstrlenW(*value) >= prefix_len)
6535 ptr += lstrlenW(ptr) - prefix_len;
6536 if (!strcmpW( ptr, prefix ))
6538 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6540 *flags |= ENV_MOD_PREFIX;
6541 /* the "[~]" will be removed by deformat_string */;
6551 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6552 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6553 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6554 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6556 ERR("Invalid flags: %08x\n", *flags);
6557 return ERROR_FUNCTION_FAILED;
6561 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6563 return ERROR_SUCCESS;
6566 static UINT open_env_key( DWORD flags, HKEY *key )
6568 static const WCHAR user_env[] =
6569 {'E','n','v','i','r','o','n','m','e','n','t',0};
6570 static const WCHAR machine_env[] =
6571 {'S','y','s','t','e','m','\\',
6572 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6573 'C','o','n','t','r','o','l','\\',
6574 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6575 'E','n','v','i','r','o','n','m','e','n','t',0};
6580 if (flags & ENV_MOD_MACHINE)
6583 root = HKEY_LOCAL_MACHINE;
6588 root = HKEY_CURRENT_USER;
6591 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6592 if (res != ERROR_SUCCESS)
6594 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6595 return ERROR_FUNCTION_FAILED;
6598 return ERROR_SUCCESS;
6601 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6603 MSIPACKAGE *package = param;
6604 LPCWSTR name, value, component;
6605 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6606 DWORD flags, type, size;
6613 component = MSI_RecordGetString(rec, 4);
6614 comp = msi_get_loaded_component(package, component);
6616 return ERROR_SUCCESS;
6618 comp->Action = msi_get_component_action( package, comp );
6619 if (comp->Action != INSTALLSTATE_LOCAL)
6621 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6622 return ERROR_SUCCESS;
6624 name = MSI_RecordGetString(rec, 2);
6625 value = MSI_RecordGetString(rec, 3);
6627 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6629 res = env_parse_flags(&name, &value, &flags);
6630 if (res != ERROR_SUCCESS || !value)
6633 if (value && !deformat_string(package, value, &deformatted))
6635 res = ERROR_OUTOFMEMORY;
6639 value = deformatted;
6641 res = open_env_key( flags, &env );
6642 if (res != ERROR_SUCCESS)
6645 if (flags & ENV_MOD_MACHINE)
6646 action |= 0x20000000;
6650 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6651 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6652 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6655 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6659 /* Nothing to do. */
6662 res = ERROR_SUCCESS;
6666 /* If we are appending but the string was empty, strip ; */
6667 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6669 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6670 newval = strdupW(value);
6673 res = ERROR_OUTOFMEMORY;
6681 /* Contrary to MSDN, +-variable to [~];path works */
6682 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6684 res = ERROR_SUCCESS;
6688 data = msi_alloc(size);
6692 return ERROR_OUTOFMEMORY;
6695 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6696 if (res != ERROR_SUCCESS)
6699 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6702 res = RegDeleteValueW(env, name);
6703 if (res != ERROR_SUCCESS)
6704 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6708 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6709 if (flags & ENV_MOD_MASK)
6713 if (flags & ENV_MOD_APPEND) multiplier++;
6714 if (flags & ENV_MOD_PREFIX) multiplier++;
6715 mod_size = lstrlenW(value) * multiplier;
6716 size += mod_size * sizeof(WCHAR);
6719 newval = msi_alloc(size);
6723 res = ERROR_OUTOFMEMORY;
6727 if (flags & ENV_MOD_PREFIX)
6729 lstrcpyW(newval, value);
6730 ptr = newval + lstrlenW(value);
6731 action |= 0x80000000;
6734 lstrcpyW(ptr, data);
6736 if (flags & ENV_MOD_APPEND)
6738 lstrcatW(newval, value);
6739 action |= 0x40000000;
6742 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6743 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6746 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6750 uirow = MSI_CreateRecord( 3 );
6751 MSI_RecordSetStringW( uirow, 1, name );
6752 MSI_RecordSetStringW( uirow, 2, newval );
6753 MSI_RecordSetInteger( uirow, 3, action );
6754 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6755 msiobj_release( &uirow->hdr );
6757 if (env) RegCloseKey(env);
6758 msi_free(deformatted);
6764 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6766 static const WCHAR query[] = {
6767 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6768 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6772 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6773 if (rc != ERROR_SUCCESS)
6774 return ERROR_SUCCESS;
6776 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6777 msiobj_release(&view->hdr);
6781 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6783 MSIPACKAGE *package = param;
6784 LPCWSTR name, value, component;
6785 LPWSTR deformatted = NULL;
6794 component = MSI_RecordGetString( rec, 4 );
6795 comp = msi_get_loaded_component( package, component );
6797 return ERROR_SUCCESS;
6799 comp->Action = msi_get_component_action( package, comp );
6800 if (comp->Action != INSTALLSTATE_ABSENT)
6802 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6803 return ERROR_SUCCESS;
6805 name = MSI_RecordGetString( rec, 2 );
6806 value = MSI_RecordGetString( rec, 3 );
6808 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6810 r = env_parse_flags( &name, &value, &flags );
6811 if (r != ERROR_SUCCESS)
6814 if (!(flags & ENV_ACT_REMOVE))
6816 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6817 return ERROR_SUCCESS;
6820 if (value && !deformat_string( package, value, &deformatted ))
6821 return ERROR_OUTOFMEMORY;
6823 value = deformatted;
6825 r = open_env_key( flags, &env );
6826 if (r != ERROR_SUCCESS)
6832 if (flags & ENV_MOD_MACHINE)
6833 action |= 0x20000000;
6835 TRACE("Removing %s\n", debugstr_w(name));
6837 res = RegDeleteValueW( env, name );
6838 if (res != ERROR_SUCCESS)
6840 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6845 uirow = MSI_CreateRecord( 3 );
6846 MSI_RecordSetStringW( uirow, 1, name );
6847 MSI_RecordSetStringW( uirow, 2, value );
6848 MSI_RecordSetInteger( uirow, 3, action );
6849 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6850 msiobj_release( &uirow->hdr );
6852 if (env) RegCloseKey( env );
6853 msi_free( deformatted );
6857 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6859 static const WCHAR query[] = {
6860 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6861 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6865 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6866 if (rc != ERROR_SUCCESS)
6867 return ERROR_SUCCESS;
6869 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6870 msiobj_release( &view->hdr );
6874 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6876 LPWSTR key, template, id;
6877 UINT r = ERROR_SUCCESS;
6879 id = msi_dup_property( package->db, szProductID );
6883 return ERROR_SUCCESS;
6885 template = msi_dup_property( package->db, szPIDTemplate );
6886 key = msi_dup_property( package->db, szPIDKEY );
6888 if (key && template)
6890 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6891 r = msi_set_property( package->db, szProductID, key );
6893 msi_free( template );
6898 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6901 package->need_reboot = 1;
6902 return ERROR_SUCCESS;
6905 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6907 static const WCHAR szAvailableFreeReg[] =
6908 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6910 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6912 TRACE("%p %d kilobytes\n", package, space);
6914 uirow = MSI_CreateRecord( 1 );
6915 MSI_RecordSetInteger( uirow, 1, space );
6916 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6917 msiobj_release( &uirow->hdr );
6919 return ERROR_SUCCESS;
6922 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6924 TRACE("%p\n", package);
6926 msi_set_property( package->db, szRollbackDisabled, szOne );
6927 return ERROR_SUCCESS;
6930 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6932 FIXME("%p\n", package);
6933 return ERROR_SUCCESS;
6936 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6938 static const WCHAR driver_query[] = {
6939 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6940 'O','D','B','C','D','r','i','v','e','r',0};
6941 static const WCHAR translator_query[] = {
6942 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6943 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6947 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6948 if (r == ERROR_SUCCESS)
6951 r = MSI_IterateRecords( view, &count, NULL, package );
6952 msiobj_release( &view->hdr );
6953 if (r != ERROR_SUCCESS)
6955 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6957 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6958 if (r == ERROR_SUCCESS)
6961 r = MSI_IterateRecords( view, &count, NULL, package );
6962 msiobj_release( &view->hdr );
6963 if (r != ERROR_SUCCESS)
6965 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6967 return ERROR_SUCCESS;
6970 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6972 MSIPACKAGE *package = param;
6973 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6976 if ((value = msi_dup_property( package->db, property )))
6978 FIXME("remove %s\n", debugstr_w(value));
6981 return ERROR_SUCCESS;
6984 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6986 static const WCHAR query[] = {
6987 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6988 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6992 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6993 if (r == ERROR_SUCCESS)
6995 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6996 msiobj_release( &view->hdr );
6997 if (r != ERROR_SUCCESS)
7000 return ERROR_SUCCESS;
7003 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7005 MSIPACKAGE *package = param;
7006 int attributes = MSI_RecordGetInteger( rec, 5 );
7008 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7010 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7011 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7012 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7013 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7017 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7019 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7020 if (r != ERROR_SUCCESS)
7021 return ERROR_SUCCESS;
7025 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7026 if (r != ERROR_SUCCESS)
7027 return ERROR_SUCCESS;
7029 RegCloseKey( hkey );
7031 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7032 debugstr_w(upgrade_code), debugstr_w(version_min),
7033 debugstr_w(version_max), debugstr_w(language));
7035 return ERROR_SUCCESS;
7038 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7040 static const WCHAR query[] = {
7041 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7042 'U','p','g','r','a','d','e',0};
7046 if (msi_get_property_int( package->db, szInstalled, 0 ))
7048 TRACE("product is installed, skipping action\n");
7049 return ERROR_SUCCESS;
7051 if (msi_get_property_int( package->db, szPreselected, 0 ))
7053 TRACE("Preselected property is set, not migrating feature states\n");
7054 return ERROR_SUCCESS;
7056 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7057 if (r == ERROR_SUCCESS)
7059 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7060 msiobj_release( &view->hdr );
7061 if (r != ERROR_SUCCESS)
7064 return ERROR_SUCCESS;
7067 static void bind_image( const char *filename, const char *path )
7069 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7071 WARN("failed to bind image %u\n", GetLastError());
7075 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7079 MSIPACKAGE *package = param;
7080 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7081 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7082 char *filenameA, *pathA;
7083 WCHAR *pathW, **path_list;
7085 if (!(file = msi_get_loaded_file( package, key )))
7087 WARN("file %s not found\n", debugstr_w(key));
7088 return ERROR_SUCCESS;
7090 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7091 path_list = msi_split_string( paths, ';' );
7092 if (!path_list) bind_image( filenameA, NULL );
7095 for (i = 0; path_list[i] && path_list[i][0]; i++)
7097 deformat_string( package, path_list[i], &pathW );
7098 if ((pathA = strdupWtoA( pathW )))
7100 bind_image( filenameA, pathA );
7106 msi_free( path_list );
7107 msi_free( filenameA );
7108 return ERROR_SUCCESS;
7111 static UINT ACTION_BindImage( MSIPACKAGE *package )
7113 static const WCHAR query[] = {
7114 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7115 'B','i','n','d','I','m','a','g','e',0};
7119 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7120 if (r == ERROR_SUCCESS)
7122 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7123 msiobj_release( &view->hdr );
7124 if (r != ERROR_SUCCESS)
7127 return ERROR_SUCCESS;
7130 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7132 static const WCHAR query[] = {
7133 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7138 r = MSI_OpenQuery( package->db, &view, query, table );
7139 if (r == ERROR_SUCCESS)
7141 r = MSI_IterateRecords(view, &count, NULL, package);
7142 msiobj_release(&view->hdr);
7143 if (r != ERROR_SUCCESS)
7146 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7147 return ERROR_SUCCESS;
7150 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7152 static const WCHAR table[] = {
7153 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7154 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7157 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7159 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7160 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7163 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7165 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7166 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7169 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7171 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7172 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7175 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7177 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7178 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7183 const WCHAR *action;
7184 UINT (*handler)(MSIPACKAGE *);
7185 const WCHAR *action_rollback;
7189 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7190 { szAppSearch, ACTION_AppSearch, NULL },
7191 { szBindImage, ACTION_BindImage, NULL },
7192 { szCCPSearch, ACTION_CCPSearch, NULL },
7193 { szCostFinalize, ACTION_CostFinalize, NULL },
7194 { szCostInitialize, ACTION_CostInitialize, NULL },
7195 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7196 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7197 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7198 { szDisableRollback, ACTION_DisableRollback, NULL },
7199 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7200 { szExecuteAction, ACTION_ExecuteAction, NULL },
7201 { szFileCost, ACTION_FileCost, NULL },
7202 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7203 { szForceReboot, ACTION_ForceReboot, NULL },
7204 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7205 { szInstallExecute, ACTION_InstallExecute, NULL },
7206 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7207 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7208 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7209 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7210 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7211 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7212 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7213 { szInstallValidate, ACTION_InstallValidate, NULL },
7214 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7215 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7216 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7217 { szMoveFiles, ACTION_MoveFiles, NULL },
7218 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7219 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7220 { szPatchFiles, ACTION_PatchFiles, NULL },
7221 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7222 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7223 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7224 { szPublishProduct, ACTION_PublishProduct, NULL },
7225 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7226 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7227 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7228 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7229 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7230 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7231 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7232 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7233 { szRegisterUser, ACTION_RegisterUser, NULL },
7234 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7235 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7236 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7237 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7238 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7239 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7240 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7241 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7242 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7243 { szResolveSource, ACTION_ResolveSource, NULL },
7244 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7245 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7246 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7247 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7248 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7249 { szStartServices, ACTION_StartServices, szStopServices },
7250 { szStopServices, ACTION_StopServices, szStartServices },
7251 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7252 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7253 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7254 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7255 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7256 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7257 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7258 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7259 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7260 { szValidateProductID, ACTION_ValidateProductID, NULL },
7261 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7262 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7263 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7264 { NULL, NULL, NULL }
7267 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7273 while (StandardActions[i].action != NULL)
7275 if (!strcmpW( StandardActions[i].action, action ))
7277 ui_actionstart( package, action );
7278 if (StandardActions[i].handler)
7280 ui_actioninfo( package, action, TRUE, 0 );
7281 *rc = StandardActions[i].handler( package );
7282 ui_actioninfo( package, action, FALSE, *rc );
7284 if (StandardActions[i].action_rollback && !package->need_rollback)
7286 TRACE("scheduling rollback action\n");
7287 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7292 FIXME("unhandled standard action %s\n", debugstr_w(action));
7293 *rc = ERROR_SUCCESS;
7303 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7305 UINT rc = ERROR_SUCCESS;
7308 TRACE("Performing action (%s)\n", debugstr_w(action));
7310 handled = ACTION_HandleStandardAction(package, action, &rc);
7313 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7317 WARN("unhandled msi action %s\n", debugstr_w(action));
7318 rc = ERROR_FUNCTION_NOT_CALLED;
7324 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7326 UINT rc = ERROR_SUCCESS;
7327 BOOL handled = FALSE;
7329 TRACE("Performing action (%s)\n", debugstr_w(action));
7331 handled = ACTION_HandleStandardAction(package, action, &rc);
7334 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7336 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7341 WARN("unhandled msi action %s\n", debugstr_w(action));
7342 rc = ERROR_FUNCTION_NOT_CALLED;
7348 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7350 UINT rc = ERROR_SUCCESS;
7353 static const WCHAR query[] =
7354 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7355 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7356 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7357 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7358 static const WCHAR ui_query[] =
7359 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7360 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7361 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7362 ' ', '=',' ','%','i',0};
7364 if (needs_ui_sequence(package))
7365 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7367 row = MSI_QueryGetRecord(package->db, query, seq);
7371 LPCWSTR action, cond;
7373 TRACE("Running the actions\n");
7375 /* check conditions */
7376 cond = MSI_RecordGetString(row, 2);
7378 /* this is a hack to skip errors in the condition code */
7379 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7381 msiobj_release(&row->hdr);
7382 return ERROR_SUCCESS;
7385 action = MSI_RecordGetString(row, 1);
7388 ERR("failed to fetch action\n");
7389 msiobj_release(&row->hdr);
7390 return ERROR_FUNCTION_FAILED;
7393 if (needs_ui_sequence(package))
7394 rc = ACTION_PerformUIAction(package, action, -1);
7396 rc = ACTION_PerformAction(package, action, -1);
7398 msiobj_release(&row->hdr);
7404 /****************************************************
7405 * TOP level entry points
7406 *****************************************************/
7408 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7409 LPCWSTR szCommandLine )
7413 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7414 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7415 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7417 msi_set_property( package->db, szAction, szInstall );
7419 package->script->InWhatSequence = SEQUENCE_INSTALL;
7426 dir = strdupW(szPackagePath);
7427 p = strrchrW(dir, '\\');
7431 file = szPackagePath + (p - dir);
7436 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7437 GetCurrentDirectoryW(MAX_PATH, dir);
7438 lstrcatW(dir, szBackSlash);
7439 file = szPackagePath;
7442 msi_free( package->PackagePath );
7443 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7444 if (!package->PackagePath)
7447 return ERROR_OUTOFMEMORY;
7450 lstrcpyW(package->PackagePath, dir);
7451 lstrcatW(package->PackagePath, file);
7454 msi_set_sourcedir_props(package, FALSE);
7457 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7458 if (rc != ERROR_SUCCESS)
7461 msi_apply_transforms( package );
7462 msi_apply_patches( package );
7464 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7466 TRACE("setting reinstall property\n");
7467 msi_set_property( package->db, szReinstall, szAll );
7470 /* properties may have been added by a transform */
7471 msi_clone_properties( package );
7473 msi_parse_command_line( package, szCommandLine, FALSE );
7474 msi_adjust_privilege_properties( package );
7475 msi_set_context( package );
7477 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7479 TRACE("disabling rollback\n");
7480 msi_set_property( package->db, szRollbackDisabled, szOne );
7483 if (needs_ui_sequence( package))
7485 package->script->InWhatSequence |= SEQUENCE_UI;
7486 rc = ACTION_ProcessUISequence(package);
7487 ui_exists = ui_sequence_exists(package);
7488 if (rc == ERROR_SUCCESS || !ui_exists)
7490 package->script->InWhatSequence |= SEQUENCE_EXEC;
7491 rc = ACTION_ProcessExecSequence(package, ui_exists);
7495 rc = ACTION_ProcessExecSequence(package, FALSE);
7497 package->script->CurrentlyScripting = FALSE;
7499 /* process the ending type action */
7500 if (rc == ERROR_SUCCESS)
7501 ACTION_PerformActionSequence(package, -1);
7502 else if (rc == ERROR_INSTALL_USEREXIT)
7503 ACTION_PerformActionSequence(package, -2);
7504 else if (rc == ERROR_INSTALL_SUSPEND)
7505 ACTION_PerformActionSequence(package, -4);
7508 ACTION_PerformActionSequence(package, -3);
7509 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7511 package->need_rollback = TRUE;
7515 /* finish up running custom actions */
7516 ACTION_FinishCustomActions(package);
7518 if (package->need_rollback)
7520 WARN("installation failed, running rollback script\n");
7521 execute_script( package, ROLLBACK_SCRIPT );
7524 if (rc == ERROR_SUCCESS && package->need_reboot)
7525 return ERROR_SUCCESS_REBOOT_REQUIRED;