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, SCRIPT_NONE);
529 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
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 == SCRIPT_ROLLBACK)
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 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2290 parent = msi_get_loaded_folder( package, folder->Parent );
2291 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2294 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2296 msi_clean_path( path );
2297 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2299 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2303 msi_set_property( package->db, folder->Directory, path );
2304 msi_free( folder->ResolvedTarget );
2305 folder->ResolvedTarget = path;
2307 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2310 msi_resolve_target_folder( package, child->Directory, load_prop );
2312 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2315 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2317 static const WCHAR query[] = {
2318 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2319 '`','C','o','n','d','i','t','i','o','n','`',0};
2320 static const WCHAR szOutOfDiskSpace[] = {
2321 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2327 TRACE("Building directory properties\n");
2328 msi_resolve_target_folder( package, szTargetDir, TRUE );
2330 TRACE("Evaluating component conditions\n");
2331 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2333 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2335 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2336 comp->Enabled = FALSE;
2339 comp->Enabled = TRUE;
2342 /* read components states from the registry */
2343 ACTION_GetComponentInstallStates(package);
2344 ACTION_GetFeatureInstallStates(package);
2346 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2348 TRACE("Evaluating feature conditions\n");
2350 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2351 if (rc == ERROR_SUCCESS)
2353 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2354 msiobj_release( &view->hdr );
2355 if (rc != ERROR_SUCCESS)
2360 TRACE("Calculating file cost\n");
2361 calculate_file_cost( package );
2363 msi_set_property( package->db, szCostingComplete, szOne );
2364 /* set default run level if not set */
2365 level = msi_dup_property( package->db, szInstallLevel );
2367 msi_set_property( package->db, szInstallLevel, szOne );
2370 /* FIXME: check volume disk space */
2371 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2373 return MSI_SetFeatureStates(package);
2376 /* OK this value is "interpreted" and then formatted based on the
2377 first few characters */
2378 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2383 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2389 LPWSTR deformated = NULL;
2392 deformat_string(package, &value[2], &deformated);
2394 /* binary value type */
2398 *size = (strlenW(ptr)/2)+1;
2400 *size = strlenW(ptr)/2;
2402 data = msi_alloc(*size);
2408 /* if uneven pad with a zero in front */
2414 data[count] = (BYTE)strtol(byte,NULL,0);
2416 TRACE("Uneven byte count\n");
2424 data[count] = (BYTE)strtol(byte,NULL,0);
2427 msi_free(deformated);
2429 TRACE("Data %i bytes(%i)\n",*size,count);
2436 deformat_string(package, &value[1], &deformated);
2439 *size = sizeof(DWORD);
2440 data = msi_alloc(*size);
2446 if ( (*p < '0') || (*p > '9') )
2452 if (deformated[0] == '-')
2455 TRACE("DWORD %i\n",*(LPDWORD)data);
2457 msi_free(deformated);
2462 static const WCHAR szMulti[] = {'[','~',']',0};
2471 *type=REG_EXPAND_SZ;
2479 if (strstrW(value, szMulti))
2480 *type = REG_MULTI_SZ;
2482 /* remove initial delimiter */
2483 if (!strncmpW(value, szMulti, 3))
2486 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2488 /* add double NULL terminator */
2489 if (*type == REG_MULTI_SZ)
2491 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2492 data = msi_realloc_zero(data, *size);
2498 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2505 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2507 *root_key = HKEY_LOCAL_MACHINE;
2512 *root_key = HKEY_CURRENT_USER;
2517 *root_key = HKEY_CLASSES_ROOT;
2521 *root_key = HKEY_CURRENT_USER;
2525 *root_key = HKEY_LOCAL_MACHINE;
2529 *root_key = HKEY_USERS;
2533 ERR("Unknown root %i\n", root);
2540 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2542 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2543 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2545 if (is_64bit && package->platform == PLATFORM_INTEL &&
2546 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2551 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2552 if (!(path_32node = msi_alloc( size ))) return NULL;
2554 memcpy( path_32node, path, len * sizeof(WCHAR) );
2555 strcpyW( path_32node + len, szWow6432Node );
2556 strcatW( path_32node, szBackSlash );
2557 strcatW( path_32node, path + len );
2561 return strdupW( path );
2564 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2566 MSIPACKAGE *package = param;
2567 LPSTR value_data = NULL;
2568 HKEY root_key, hkey;
2570 LPWSTR deformated, uikey, keypath;
2571 LPCWSTR szRoot, component, name, key, value;
2575 BOOL check_first = FALSE;
2578 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2580 component = MSI_RecordGetString(row, 6);
2581 comp = msi_get_loaded_component(package,component);
2583 return ERROR_SUCCESS;
2585 comp->Action = msi_get_component_action( package, comp );
2586 if (comp->Action != INSTALLSTATE_LOCAL)
2588 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2589 return ERROR_SUCCESS;
2592 name = MSI_RecordGetString(row, 4);
2593 if( MSI_RecordIsNull(row,5) && name )
2595 /* null values can have special meanings */
2596 if (name[0]=='-' && name[1] == 0)
2597 return ERROR_SUCCESS;
2598 else if ((name[0]=='+' && name[1] == 0) ||
2599 (name[0] == '*' && name[1] == 0))
2604 root = MSI_RecordGetInteger(row,2);
2605 key = MSI_RecordGetString(row, 3);
2607 szRoot = get_root_key( package, root, &root_key );
2609 return ERROR_SUCCESS;
2611 deformat_string(package, key , &deformated);
2612 size = strlenW(deformated) + strlenW(szRoot) + 1;
2613 uikey = msi_alloc(size*sizeof(WCHAR));
2614 strcpyW(uikey,szRoot);
2615 strcatW(uikey,deformated);
2617 keypath = get_keypath( package, root_key, deformated );
2618 msi_free( deformated );
2619 if (RegCreateKeyW( root_key, keypath, &hkey ))
2621 ERR("Could not create key %s\n", debugstr_w(keypath));
2624 return ERROR_SUCCESS;
2627 value = MSI_RecordGetString(row,5);
2629 value_data = parse_value(package, value, &type, &size);
2632 value_data = (LPSTR)strdupW(szEmpty);
2633 size = sizeof(szEmpty);
2637 deformat_string(package, name, &deformated);
2641 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2643 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2648 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2649 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2651 TRACE("value %s of %s checked already exists\n",
2652 debugstr_w(deformated), debugstr_w(uikey));
2656 TRACE("Checked and setting value %s of %s\n",
2657 debugstr_w(deformated), debugstr_w(uikey));
2658 if (deformated || size)
2659 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2664 uirow = MSI_CreateRecord(3);
2665 MSI_RecordSetStringW(uirow,2,deformated);
2666 MSI_RecordSetStringW(uirow,1,uikey);
2667 if (type == REG_SZ || type == REG_EXPAND_SZ)
2668 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2669 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2670 msiobj_release( &uirow->hdr );
2672 msi_free(value_data);
2673 msi_free(deformated);
2677 return ERROR_SUCCESS;
2680 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2682 static const WCHAR query[] = {
2683 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2684 '`','R','e','g','i','s','t','r','y','`',0};
2688 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2689 if (rc != ERROR_SUCCESS)
2690 return ERROR_SUCCESS;
2692 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2693 msiobj_release(&view->hdr);
2697 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2701 DWORD num_subkeys, num_values;
2703 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2705 if ((res = RegDeleteValueW( hkey, value )))
2707 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2709 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2710 NULL, NULL, NULL, NULL );
2711 RegCloseKey( hkey );
2712 if (!res && !num_subkeys && !num_values)
2714 TRACE("removing empty key %s\n", debugstr_w(keypath));
2715 RegDeleteKeyW( root, keypath );
2719 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2722 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2724 LONG res = RegDeleteTreeW( root, keypath );
2725 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2728 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2730 MSIPACKAGE *package = param;
2731 LPCWSTR component, name, key_str, root_key_str;
2732 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2735 BOOL delete_key = FALSE;
2740 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2742 component = MSI_RecordGetString( row, 6 );
2743 comp = msi_get_loaded_component( package, component );
2745 return ERROR_SUCCESS;
2747 comp->Action = msi_get_component_action( package, comp );
2748 if (comp->Action != INSTALLSTATE_ABSENT)
2750 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2751 return ERROR_SUCCESS;
2754 name = MSI_RecordGetString( row, 4 );
2755 if (MSI_RecordIsNull( row, 5 ) && name )
2757 if (name[0] == '+' && !name[1])
2758 return ERROR_SUCCESS;
2759 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2766 root = MSI_RecordGetInteger( row, 2 );
2767 key_str = MSI_RecordGetString( row, 3 );
2769 root_key_str = get_root_key( package, root, &hkey_root );
2771 return ERROR_SUCCESS;
2773 deformat_string( package, key_str, &deformated_key );
2774 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2775 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2776 strcpyW( ui_key_str, root_key_str );
2777 strcatW( ui_key_str, deformated_key );
2779 deformat_string( package, name, &deformated_name );
2781 keypath = get_keypath( package, hkey_root, deformated_key );
2782 msi_free( deformated_key );
2783 if (delete_key) delete_reg_key( hkey_root, keypath );
2784 else delete_reg_value( hkey_root, keypath, deformated_name );
2785 msi_free( keypath );
2787 uirow = MSI_CreateRecord( 2 );
2788 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2789 MSI_RecordSetStringW( uirow, 2, deformated_name );
2790 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2791 msiobj_release( &uirow->hdr );
2793 msi_free( ui_key_str );
2794 msi_free( deformated_name );
2795 return ERROR_SUCCESS;
2798 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2800 MSIPACKAGE *package = param;
2801 LPCWSTR component, name, key_str, root_key_str;
2802 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2805 BOOL delete_key = FALSE;
2810 component = MSI_RecordGetString( row, 5 );
2811 comp = msi_get_loaded_component( package, component );
2813 return ERROR_SUCCESS;
2815 comp->Action = msi_get_component_action( package, comp );
2816 if (comp->Action != INSTALLSTATE_LOCAL)
2818 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2819 return ERROR_SUCCESS;
2822 if ((name = MSI_RecordGetString( row, 4 )))
2824 if (name[0] == '-' && !name[1])
2831 root = MSI_RecordGetInteger( row, 2 );
2832 key_str = MSI_RecordGetString( row, 3 );
2834 root_key_str = get_root_key( package, root, &hkey_root );
2836 return ERROR_SUCCESS;
2838 deformat_string( package, key_str, &deformated_key );
2839 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2840 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2841 strcpyW( ui_key_str, root_key_str );
2842 strcatW( ui_key_str, deformated_key );
2844 deformat_string( package, name, &deformated_name );
2846 keypath = get_keypath( package, hkey_root, deformated_key );
2847 msi_free( deformated_key );
2848 if (delete_key) delete_reg_key( hkey_root, keypath );
2849 else delete_reg_value( hkey_root, keypath, deformated_name );
2850 msi_free( keypath );
2852 uirow = MSI_CreateRecord( 2 );
2853 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2854 MSI_RecordSetStringW( uirow, 2, deformated_name );
2855 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2856 msiobj_release( &uirow->hdr );
2858 msi_free( ui_key_str );
2859 msi_free( deformated_name );
2860 return ERROR_SUCCESS;
2863 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2865 static const WCHAR registry_query[] = {
2866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2867 '`','R','e','g','i','s','t','r','y','`',0};
2868 static const WCHAR remove_registry_query[] = {
2869 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2870 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2874 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2875 if (rc == ERROR_SUCCESS)
2877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2878 msiobj_release( &view->hdr );
2879 if (rc != ERROR_SUCCESS)
2882 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2883 if (rc == ERROR_SUCCESS)
2885 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2886 msiobj_release( &view->hdr );
2887 if (rc != ERROR_SUCCESS)
2890 return ERROR_SUCCESS;
2893 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2895 package->script->CurrentlyScripting = TRUE;
2897 return ERROR_SUCCESS;
2901 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2903 static const WCHAR query[]= {
2904 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2905 '`','R','e','g','i','s','t','r','y','`',0};
2907 DWORD total = 0, count = 0;
2909 MSIFEATURE *feature;
2913 TRACE("InstallValidate\n");
2915 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2916 if (rc == ERROR_SUCCESS)
2918 rc = MSI_IterateRecords( view, &count, NULL, package );
2919 msiobj_release( &view->hdr );
2920 if (rc != ERROR_SUCCESS)
2922 total += count * REG_PROGRESS_VALUE;
2924 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2925 total += COMPONENT_PROGRESS_VALUE;
2927 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2928 total += file->FileSize;
2930 msi_ui_progress( package, 0, total, 0, 0 );
2932 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2934 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2935 debugstr_w(feature->Feature), feature->Installed,
2936 feature->ActionRequest, feature->Action);
2938 return ERROR_SUCCESS;
2941 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2943 MSIPACKAGE* package = param;
2944 LPCWSTR cond = NULL;
2945 LPCWSTR message = NULL;
2948 static const WCHAR title[]=
2949 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2951 cond = MSI_RecordGetString(row,1);
2953 r = MSI_EvaluateConditionW(package,cond);
2954 if (r == MSICONDITION_FALSE)
2956 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2959 message = MSI_RecordGetString(row,2);
2960 deformat_string(package,message,&deformated);
2961 MessageBoxW(NULL,deformated,title,MB_OK);
2962 msi_free(deformated);
2965 return ERROR_INSTALL_FAILURE;
2968 return ERROR_SUCCESS;
2971 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2973 static const WCHAR query[] = {
2974 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2975 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2979 TRACE("Checking launch conditions\n");
2981 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2982 if (rc != ERROR_SUCCESS)
2983 return ERROR_SUCCESS;
2985 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2986 msiobj_release(&view->hdr);
2990 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2994 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2996 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2998 static const WCHAR query[] = {
2999 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3000 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3001 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3002 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3003 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3006 LPWSTR deformated, buffer, deformated_name;
3009 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3013 root = MSI_RecordGetInteger(row,2);
3014 key = MSI_RecordGetString(row, 3);
3015 name = MSI_RecordGetString(row, 4);
3016 deformat_string(package, key , &deformated);
3017 deformat_string(package, name, &deformated_name);
3019 len = strlenW(deformated) + 6;
3020 if (deformated_name)
3021 len+=strlenW(deformated_name);
3023 buffer = msi_alloc( len *sizeof(WCHAR));
3025 if (deformated_name)
3026 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3028 sprintfW(buffer,fmt,root,deformated);
3030 msi_free(deformated);
3031 msi_free(deformated_name);
3032 msiobj_release(&row->hdr);
3036 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3038 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3043 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3046 return strdupW( file->TargetPath );
3051 static HKEY openSharedDLLsKey(void)
3054 static const WCHAR path[] =
3055 {'S','o','f','t','w','a','r','e','\\',
3056 'M','i','c','r','o','s','o','f','t','\\',
3057 'W','i','n','d','o','w','s','\\',
3058 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3059 'S','h','a','r','e','d','D','L','L','s',0};
3061 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3065 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3070 DWORD sz = sizeof(count);
3073 hkey = openSharedDLLsKey();
3074 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3075 if (rc != ERROR_SUCCESS)
3081 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3085 hkey = openSharedDLLsKey();
3087 msi_reg_set_val_dword( hkey, path, count );
3089 RegDeleteValueW(hkey,path);
3094 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3096 MSIFEATURE *feature;
3100 /* only refcount DLLs */
3101 if (comp->KeyPath == NULL ||
3103 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3104 comp->Attributes & msidbComponentAttributesODBCDataSource)
3108 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3109 write = (count > 0);
3111 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3115 /* increment counts */
3116 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3120 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3123 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3125 if ( cl->component == comp )
3130 /* decrement counts */
3131 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3135 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3138 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3140 if ( cl->component == comp )
3145 /* ref count all the files in the component */
3150 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3152 if (file->Component == comp)
3153 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3157 /* add a count for permanent */
3158 if (comp->Attributes & msidbComponentAttributesPermanent)
3161 comp->RefCount = count;
3164 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3167 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3171 const WCHAR prefixW[] = {'<','\\',0};
3172 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3173 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3177 strcpyW( keypath, prefixW );
3178 strcatW( keypath, comp->assembly->display_name );
3182 return resolve_keypath( package, comp );
3185 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3187 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3194 squash_guid(package->ProductCode,squished_pc);
3195 msi_set_sourcedir_props(package, FALSE);
3197 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3200 INSTALLSTATE action;
3202 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3203 if (!comp->ComponentId)
3206 squash_guid( comp->ComponentId, squished_cc );
3207 msi_free( comp->FullKeypath );
3208 comp->FullKeypath = build_full_keypath( package, comp );
3210 ACTION_RefCountComponent( package, comp );
3212 if (package->need_rollback) action = comp->Installed;
3213 else action = comp->ActionRequest;
3215 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3216 debugstr_w(comp->Component), debugstr_w(squished_cc),
3217 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3219 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3221 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3222 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3224 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3226 if (rc != ERROR_SUCCESS)
3229 if (comp->Attributes & msidbComponentAttributesPermanent)
3231 static const WCHAR szPermKey[] =
3232 { '0','0','0','0','0','0','0','0','0','0','0','0',
3233 '0','0','0','0','0','0','0','0','0','0','0','0',
3234 '0','0','0','0','0','0','0','0',0 };
3236 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3238 if (action == INSTALLSTATE_LOCAL)
3239 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3245 WCHAR source[MAX_PATH];
3246 WCHAR base[MAX_PATH];
3249 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3250 static const WCHAR query[] = {
3251 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3252 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3253 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3254 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3255 '`','D','i','s','k','I','d','`',0};
3257 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3260 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3261 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3262 ptr2 = strrchrW(source, '\\') + 1;
3263 msiobj_release(&row->hdr);
3265 lstrcpyW(base, package->PackagePath);
3266 ptr = strrchrW(base, '\\');
3269 sourcepath = msi_resolve_file_source(package, file);
3270 ptr = sourcepath + lstrlenW(base);
3271 lstrcpyW(ptr2, ptr);
3272 msi_free(sourcepath);
3274 msi_reg_set_val_str(hkey, squished_pc, source);
3278 else if (action == INSTALLSTATE_ABSENT)
3280 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3281 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3283 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3287 uirow = MSI_CreateRecord(3);
3288 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3289 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3290 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3291 msi_ui_actiondata( package, szProcessComponents, uirow );
3292 msiobj_release( &uirow->hdr );
3294 return ERROR_SUCCESS;
3305 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3306 LPWSTR lpszName, LONG_PTR lParam)
3309 typelib_struct *tl_struct = (typelib_struct*) lParam;
3310 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3314 if (!IS_INTRESOURCE(lpszName))
3316 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3320 sz = strlenW(tl_struct->source)+4;
3321 sz *= sizeof(WCHAR);
3323 if ((INT_PTR)lpszName == 1)
3324 tl_struct->path = strdupW(tl_struct->source);
3327 tl_struct->path = msi_alloc(sz);
3328 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3331 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3332 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3335 msi_free(tl_struct->path);
3336 tl_struct->path = NULL;
3341 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3342 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3344 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3348 msi_free(tl_struct->path);
3349 tl_struct->path = NULL;
3351 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3352 ITypeLib_Release(tl_struct->ptLib);
3357 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3359 MSIPACKAGE* package = param;
3363 typelib_struct tl_struct;
3368 component = MSI_RecordGetString(row,3);
3369 comp = msi_get_loaded_component(package,component);
3371 return ERROR_SUCCESS;
3373 comp->Action = msi_get_component_action( package, comp );
3374 if (comp->Action != INSTALLSTATE_LOCAL)
3376 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3377 return ERROR_SUCCESS;
3380 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3382 TRACE("component has no key path\n");
3383 return ERROR_SUCCESS;
3385 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3387 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3391 guid = MSI_RecordGetString(row,1);
3392 CLSIDFromString( guid, &tl_struct.clsid);
3393 tl_struct.source = strdupW( file->TargetPath );
3394 tl_struct.path = NULL;
3396 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3397 (LONG_PTR)&tl_struct);
3401 LPCWSTR helpid, help_path = NULL;
3404 helpid = MSI_RecordGetString(row,6);
3406 if (helpid) help_path = msi_get_target_folder( package, helpid );
3407 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3410 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3412 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3414 ITypeLib_Release(tl_struct.ptLib);
3415 msi_free(tl_struct.path);
3417 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3419 FreeLibrary(module);
3420 msi_free(tl_struct.source);
3424 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3427 ERR("Failed to load type library: %08x\n", hr);
3428 return ERROR_INSTALL_FAILURE;
3431 ITypeLib_Release(tlib);
3434 return ERROR_SUCCESS;
3437 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3439 static const WCHAR query[] = {
3440 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3441 '`','T','y','p','e','L','i','b','`',0};
3445 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3446 if (rc != ERROR_SUCCESS)
3447 return ERROR_SUCCESS;
3449 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3450 msiobj_release(&view->hdr);
3454 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3456 MSIPACKAGE *package = param;
3457 LPCWSTR component, guid;
3465 component = MSI_RecordGetString( row, 3 );
3466 comp = msi_get_loaded_component( package, component );
3468 return ERROR_SUCCESS;
3470 comp->Action = msi_get_component_action( package, comp );
3471 if (comp->Action != INSTALLSTATE_ABSENT)
3473 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3474 return ERROR_SUCCESS;
3476 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3478 guid = MSI_RecordGetString( row, 1 );
3479 CLSIDFromString( guid, &libid );
3480 version = MSI_RecordGetInteger( row, 4 );
3481 language = MSI_RecordGetInteger( row, 2 );
3484 syskind = SYS_WIN64;
3486 syskind = SYS_WIN32;
3489 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3492 WARN("Failed to unregister typelib: %08x\n", hr);
3495 return ERROR_SUCCESS;
3498 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3500 static const WCHAR query[] = {
3501 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3502 '`','T','y','p','e','L','i','b','`',0};
3506 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3507 if (rc != ERROR_SUCCESS)
3508 return ERROR_SUCCESS;
3510 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3511 msiobj_release( &view->hdr );
3515 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3517 static const WCHAR szlnk[] = {'.','l','n','k',0};
3518 LPCWSTR directory, extension, link_folder;
3519 LPWSTR link_file, filename;
3521 directory = MSI_RecordGetString( row, 2 );
3522 link_folder = msi_get_target_folder( package, directory );
3525 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3528 /* may be needed because of a bug somewhere else */
3529 msi_create_full_path( link_folder );
3531 filename = msi_dup_record_field( row, 3 );
3532 msi_reduce_to_long_filename( filename );
3534 extension = strchrW( filename, '.' );
3535 if (!extension || strcmpiW( extension, szlnk ))
3537 int len = strlenW( filename );
3538 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3539 memcpy( filename + len, szlnk, sizeof(szlnk) );
3541 link_file = msi_build_directory_name( 2, link_folder, filename );
3542 msi_free( filename );
3547 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3549 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3550 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3551 WCHAR *folder, *dest, *path;
3553 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3554 folder = msi_dup_property( package->db, szWindowsFolder );
3557 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3558 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3559 msi_free( appdata );
3561 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3562 msi_create_full_path( dest );
3563 path = msi_build_directory_name( 2, dest, icon_name );
3569 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3571 MSIPACKAGE *package = param;
3572 LPWSTR link_file, deformated, path;
3573 LPCWSTR component, target;
3575 IShellLinkW *sl = NULL;
3576 IPersistFile *pf = NULL;
3579 component = MSI_RecordGetString(row, 4);
3580 comp = msi_get_loaded_component(package, component);
3582 return ERROR_SUCCESS;
3584 comp->Action = msi_get_component_action( package, comp );
3585 if (comp->Action != INSTALLSTATE_LOCAL)
3587 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3588 return ERROR_SUCCESS;
3590 msi_ui_actiondata( package, szCreateShortcuts, row );
3592 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3593 &IID_IShellLinkW, (LPVOID *) &sl );
3597 ERR("CLSID_ShellLink not available\n");
3601 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3604 ERR("QueryInterface(IID_IPersistFile) failed\n");
3608 target = MSI_RecordGetString(row, 5);
3609 if (strchrW(target, '['))
3612 WCHAR *format_string, *p;
3614 if (!(p = strchrW( target, ']' ))) goto err;
3615 len = p - target + 1;
3616 format_string = msi_alloc( (len + 1) * sizeof(WCHAR) );
3617 memcpy( format_string, target, len * sizeof(WCHAR) );
3618 format_string[len] = 0;
3619 deformat_string( package, format_string, &deformated );
3620 msi_free( format_string );
3622 path = msi_alloc( (strlenW( deformated ) + strlenW( p + 1 ) + 2) * sizeof(WCHAR) );
3623 strcpyW( path, deformated );
3624 PathAddBackslashW( path );
3625 strcatW( path, p + 1 );
3626 TRACE("target path is %s\n", debugstr_w(path));
3628 IShellLinkW_SetPath( sl, path );
3629 msi_free( deformated );
3634 FIXME("poorly handled shortcut format, advertised shortcut\n");
3635 IShellLinkW_SetPath(sl,comp->FullKeypath);
3638 if (!MSI_RecordIsNull(row,6))
3640 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3641 deformat_string(package, arguments, &deformated);
3642 IShellLinkW_SetArguments(sl,deformated);
3643 msi_free(deformated);
3646 if (!MSI_RecordIsNull(row,7))
3648 LPCWSTR description = MSI_RecordGetString(row, 7);
3649 IShellLinkW_SetDescription(sl, description);
3652 if (!MSI_RecordIsNull(row,8))
3653 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3655 if (!MSI_RecordIsNull(row,9))
3658 LPCWSTR icon = MSI_RecordGetString(row, 9);
3660 path = msi_build_icon_path(package, icon);
3661 index = MSI_RecordGetInteger(row,10);
3663 /* no value means 0 */
3664 if (index == MSI_NULL_INTEGER)
3667 IShellLinkW_SetIconLocation(sl, path, index);
3671 if (!MSI_RecordIsNull(row,11))
3672 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3674 if (!MSI_RecordIsNull(row,12))
3676 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3677 full_path = msi_get_target_folder( package, wkdir );
3678 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3680 link_file = get_link_file(package, row);
3682 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3683 IPersistFile_Save(pf, link_file, FALSE);
3684 msi_free(link_file);
3688 IPersistFile_Release( pf );
3690 IShellLinkW_Release( sl );
3692 return ERROR_SUCCESS;
3695 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3697 static const WCHAR query[] = {
3698 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3699 '`','S','h','o','r','t','c','u','t','`',0};
3704 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3705 if (rc != ERROR_SUCCESS)
3706 return ERROR_SUCCESS;
3708 res = CoInitialize( NULL );
3710 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3711 msiobj_release(&view->hdr);
3713 if (SUCCEEDED(res)) CoUninitialize();
3717 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3719 MSIPACKAGE *package = param;
3724 component = MSI_RecordGetString( row, 4 );
3725 comp = msi_get_loaded_component( package, component );
3727 return ERROR_SUCCESS;
3729 comp->Action = msi_get_component_action( package, comp );
3730 if (comp->Action != INSTALLSTATE_ABSENT)
3732 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3733 return ERROR_SUCCESS;
3735 msi_ui_actiondata( package, szRemoveShortcuts, row );
3737 link_file = get_link_file( package, row );
3739 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3740 if (!DeleteFileW( link_file ))
3742 WARN("Failed to remove shortcut file %u\n", GetLastError());
3744 msi_free( link_file );
3746 return ERROR_SUCCESS;
3749 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3751 static const WCHAR query[] = {
3752 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3753 '`','S','h','o','r','t','c','u','t','`',0};
3757 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3758 if (rc != ERROR_SUCCESS)
3759 return ERROR_SUCCESS;
3761 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3762 msiobj_release( &view->hdr );
3766 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3768 MSIPACKAGE* package = param;
3776 FileName = MSI_RecordGetString(row,1);
3779 ERR("Unable to get FileName\n");
3780 return ERROR_SUCCESS;
3783 FilePath = msi_build_icon_path(package, FileName);
3785 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3787 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3788 FILE_ATTRIBUTE_NORMAL, NULL);
3790 if (the_file == INVALID_HANDLE_VALUE)
3792 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3794 return ERROR_SUCCESS;
3801 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3802 if (rc != ERROR_SUCCESS)
3804 ERR("Failed to get stream\n");
3805 CloseHandle(the_file);
3806 DeleteFileW(FilePath);
3809 WriteFile(the_file,buffer,sz,&write,NULL);
3810 } while (sz == 1024);
3813 CloseHandle(the_file);
3815 return ERROR_SUCCESS;
3818 static UINT msi_publish_icons(MSIPACKAGE *package)
3820 static const WCHAR query[]= {
3821 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3822 '`','I','c','o','n','`',0};
3826 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3827 if (r == ERROR_SUCCESS)
3829 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3830 msiobj_release(&view->hdr);
3831 if (r != ERROR_SUCCESS)
3834 return ERROR_SUCCESS;
3837 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3843 MSISOURCELISTINFO *info;
3845 r = RegCreateKeyW(hkey, szSourceList, &source);
3846 if (r != ERROR_SUCCESS)
3849 RegCloseKey(source);
3851 buffer = strrchrW(package->PackagePath, '\\') + 1;
3852 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3853 package->Context, MSICODE_PRODUCT,
3854 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3855 if (r != ERROR_SUCCESS)
3858 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3859 package->Context, MSICODE_PRODUCT,
3860 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3861 if (r != ERROR_SUCCESS)
3864 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3865 package->Context, MSICODE_PRODUCT,
3866 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3867 if (r != ERROR_SUCCESS)
3870 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3872 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3873 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3874 info->options, info->value);
3876 MsiSourceListSetInfoW(package->ProductCode, NULL,
3877 info->context, info->options,
3878 info->property, info->value);
3881 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3883 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3884 disk->context, disk->options,
3885 disk->disk_id, disk->volume_label, disk->disk_prompt);
3888 return ERROR_SUCCESS;
3891 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3893 MSIHANDLE hdb, suminfo;
3894 WCHAR guids[MAX_PATH];
3895 WCHAR packcode[SQUISH_GUID_SIZE];
3902 static const WCHAR szARPProductIcon[] =
3903 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3904 static const WCHAR szAssignment[] =
3905 {'A','s','s','i','g','n','m','e','n','t',0};
3906 static const WCHAR szAdvertiseFlags[] =
3907 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3908 static const WCHAR szClients[] =
3909 {'C','l','i','e','n','t','s',0};
3910 static const WCHAR szColon[] = {':',0};
3912 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3913 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3916 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3917 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3922 buffer = msi_dup_property(package->db, szARPProductIcon);
3925 LPWSTR path = msi_build_icon_path(package, buffer);
3926 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3931 buffer = msi_dup_property(package->db, szProductVersion);
3934 DWORD verdword = msi_version_str_to_dword(buffer);
3935 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3939 msi_reg_set_val_dword(hkey, szAssignment, 0);
3940 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3941 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3942 msi_reg_set_val_str(hkey, szClients, szColon);
3944 hdb = alloc_msihandle(&package->db->hdr);
3946 return ERROR_NOT_ENOUGH_MEMORY;
3948 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3949 MsiCloseHandle(hdb);
3950 if (r != ERROR_SUCCESS)
3954 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3955 NULL, guids, &size);
3956 if (r != ERROR_SUCCESS)
3959 ptr = strchrW(guids, ';');
3961 squash_guid(guids, packcode);
3962 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3965 MsiCloseHandle(suminfo);
3966 return ERROR_SUCCESS;
3969 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3974 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3976 upgrade = msi_dup_property(package->db, szUpgradeCode);
3978 return ERROR_SUCCESS;
3980 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3981 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3983 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3985 if (r != ERROR_SUCCESS)
3987 WARN("failed to open upgrade code key\n");
3989 return ERROR_SUCCESS;
3991 squash_guid(package->ProductCode, squashed_pc);
3992 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3995 return ERROR_SUCCESS;
3998 static BOOL msi_check_publish(MSIPACKAGE *package)
4000 MSIFEATURE *feature;
4002 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4004 feature->Action = msi_get_feature_action( package, feature );
4005 if (feature->Action == INSTALLSTATE_LOCAL)
4012 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4014 MSIFEATURE *feature;
4016 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4018 feature->Action = msi_get_feature_action( package, feature );
4019 if (feature->Action != INSTALLSTATE_ABSENT)
4026 static UINT msi_publish_patches( MSIPACKAGE *package )
4028 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4029 WCHAR patch_squashed[GUID_SIZE];
4030 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4032 MSIPATCHINFO *patch;
4034 WCHAR *p, *all_patches = NULL;
4037 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4038 if (r != ERROR_SUCCESS)
4039 return ERROR_FUNCTION_FAILED;
4041 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4042 if (res != ERROR_SUCCESS)
4044 r = ERROR_FUNCTION_FAILED;
4048 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4049 if (r != ERROR_SUCCESS)
4052 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4054 squash_guid( patch->patchcode, patch_squashed );
4055 len += strlenW( patch_squashed ) + 1;
4058 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4062 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4066 squash_guid( patch->patchcode, p );
4067 p += strlenW( p ) + 1;
4069 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4070 (const BYTE *)patch->transforms,
4071 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4072 if (res != ERROR_SUCCESS)
4075 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4076 if (r != ERROR_SUCCESS)
4079 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4080 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4081 RegCloseKey( patch_key );
4082 if (res != ERROR_SUCCESS)
4085 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4087 res = GetLastError();
4088 ERR("Unable to copy patch package %d\n", res);
4091 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4092 if (res != ERROR_SUCCESS)
4095 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4096 RegCloseKey( patch_key );
4097 if (res != ERROR_SUCCESS)
4101 all_patches[len] = 0;
4102 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4103 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4104 if (res != ERROR_SUCCESS)
4107 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4108 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4109 if (res != ERROR_SUCCESS)
4110 r = ERROR_FUNCTION_FAILED;
4113 RegCloseKey( product_patches_key );
4114 RegCloseKey( patches_key );
4115 RegCloseKey( product_key );
4116 msi_free( all_patches );
4120 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4123 HKEY hukey = NULL, hudkey = NULL;
4126 if (!list_empty(&package->patches))
4128 rc = msi_publish_patches(package);
4129 if (rc != ERROR_SUCCESS)
4133 /* FIXME: also need to publish if the product is in advertise mode */
4134 if (!msi_check_publish(package))
4135 return ERROR_SUCCESS;
4137 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4139 if (rc != ERROR_SUCCESS)
4142 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4143 NULL, &hudkey, TRUE);
4144 if (rc != ERROR_SUCCESS)
4147 rc = msi_publish_upgrade_code(package);
4148 if (rc != ERROR_SUCCESS)
4151 rc = msi_publish_product_properties(package, hukey);
4152 if (rc != ERROR_SUCCESS)
4155 rc = msi_publish_sourcelist(package, hukey);
4156 if (rc != ERROR_SUCCESS)
4159 rc = msi_publish_icons(package);
4162 uirow = MSI_CreateRecord( 1 );
4163 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4164 msi_ui_actiondata( package, szPublishProduct, uirow );
4165 msiobj_release( &uirow->hdr );
4168 RegCloseKey(hudkey);
4172 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4174 WCHAR *filename, *ptr, *folder, *ret;
4175 const WCHAR *dirprop;
4177 filename = msi_dup_record_field( row, 2 );
4178 if (filename && (ptr = strchrW( filename, '|' )))
4183 dirprop = MSI_RecordGetString( row, 3 );
4186 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4187 if (!folder) folder = msi_dup_property( package->db, dirprop );
4190 folder = msi_dup_property( package->db, szWindowsFolder );
4194 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4195 msi_free( filename );
4199 ret = msi_build_directory_name( 2, folder, ptr );
4201 msi_free( filename );
4206 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4208 MSIPACKAGE *package = param;
4209 LPCWSTR component, section, key, value, identifier;
4210 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4215 component = MSI_RecordGetString(row, 8);
4216 comp = msi_get_loaded_component(package,component);
4218 return ERROR_SUCCESS;
4220 comp->Action = msi_get_component_action( package, comp );
4221 if (comp->Action != INSTALLSTATE_LOCAL)
4223 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4224 return ERROR_SUCCESS;
4227 identifier = MSI_RecordGetString(row,1);
4228 section = MSI_RecordGetString(row,4);
4229 key = MSI_RecordGetString(row,5);
4230 value = MSI_RecordGetString(row,6);
4231 action = MSI_RecordGetInteger(row,7);
4233 deformat_string(package,section,&deformated_section);
4234 deformat_string(package,key,&deformated_key);
4235 deformat_string(package,value,&deformated_value);
4237 fullname = get_ini_file_name(package, row);
4241 TRACE("Adding value %s to section %s in %s\n",
4242 debugstr_w(deformated_key), debugstr_w(deformated_section),
4243 debugstr_w(fullname));
4244 WritePrivateProfileStringW(deformated_section, deformated_key,
4245 deformated_value, fullname);
4247 else if (action == 1)
4250 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4251 returned, 10, fullname);
4252 if (returned[0] == 0)
4254 TRACE("Adding value %s to section %s in %s\n",
4255 debugstr_w(deformated_key), debugstr_w(deformated_section),
4256 debugstr_w(fullname));
4258 WritePrivateProfileStringW(deformated_section, deformated_key,
4259 deformated_value, fullname);
4262 else if (action == 3)
4263 FIXME("Append to existing section not yet implemented\n");
4265 uirow = MSI_CreateRecord(4);
4266 MSI_RecordSetStringW(uirow,1,identifier);
4267 MSI_RecordSetStringW(uirow,2,deformated_section);
4268 MSI_RecordSetStringW(uirow,3,deformated_key);
4269 MSI_RecordSetStringW(uirow,4,deformated_value);
4270 msi_ui_actiondata( package, szWriteIniValues, uirow );
4271 msiobj_release( &uirow->hdr );
4274 msi_free(deformated_key);
4275 msi_free(deformated_value);
4276 msi_free(deformated_section);
4277 return ERROR_SUCCESS;
4280 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4282 static const WCHAR query[] = {
4283 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4284 '`','I','n','i','F','i','l','e','`',0};
4288 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4289 if (rc != ERROR_SUCCESS)
4290 return ERROR_SUCCESS;
4292 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4293 msiobj_release(&view->hdr);
4297 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4299 MSIPACKAGE *package = param;
4300 LPCWSTR component, section, key, value, identifier;
4301 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4306 component = MSI_RecordGetString( row, 8 );
4307 comp = msi_get_loaded_component( package, component );
4309 return ERROR_SUCCESS;
4311 comp->Action = msi_get_component_action( package, comp );
4312 if (comp->Action != INSTALLSTATE_ABSENT)
4314 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4315 return ERROR_SUCCESS;
4318 identifier = MSI_RecordGetString( row, 1 );
4319 section = MSI_RecordGetString( row, 4 );
4320 key = MSI_RecordGetString( row, 5 );
4321 value = MSI_RecordGetString( row, 6 );
4322 action = MSI_RecordGetInteger( row, 7 );
4324 deformat_string( package, section, &deformated_section );
4325 deformat_string( package, key, &deformated_key );
4326 deformat_string( package, value, &deformated_value );
4328 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4330 filename = get_ini_file_name( package, row );
4332 TRACE("Removing key %s from section %s in %s\n",
4333 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4335 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4337 WARN("Unable to remove key %u\n", GetLastError());
4339 msi_free( filename );
4342 FIXME("Unsupported action %d\n", action);
4345 uirow = MSI_CreateRecord( 4 );
4346 MSI_RecordSetStringW( uirow, 1, identifier );
4347 MSI_RecordSetStringW( uirow, 2, deformated_section );
4348 MSI_RecordSetStringW( uirow, 3, deformated_key );
4349 MSI_RecordSetStringW( uirow, 4, deformated_value );
4350 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4351 msiobj_release( &uirow->hdr );
4353 msi_free( deformated_key );
4354 msi_free( deformated_value );
4355 msi_free( deformated_section );
4356 return ERROR_SUCCESS;
4359 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4361 MSIPACKAGE *package = param;
4362 LPCWSTR component, section, key, value, identifier;
4363 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4368 component = MSI_RecordGetString( row, 8 );
4369 comp = msi_get_loaded_component( package, component );
4371 return ERROR_SUCCESS;
4373 comp->Action = msi_get_component_action( package, comp );
4374 if (comp->Action != INSTALLSTATE_LOCAL)
4376 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4377 return ERROR_SUCCESS;
4380 identifier = MSI_RecordGetString( row, 1 );
4381 section = MSI_RecordGetString( row, 4 );
4382 key = MSI_RecordGetString( row, 5 );
4383 value = MSI_RecordGetString( row, 6 );
4384 action = MSI_RecordGetInteger( row, 7 );
4386 deformat_string( package, section, &deformated_section );
4387 deformat_string( package, key, &deformated_key );
4388 deformat_string( package, value, &deformated_value );
4390 if (action == msidbIniFileActionRemoveLine)
4392 filename = get_ini_file_name( package, row );
4394 TRACE("Removing key %s from section %s in %s\n",
4395 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4397 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4399 WARN("Unable to remove key %u\n", GetLastError());
4401 msi_free( filename );
4404 FIXME("Unsupported action %d\n", action);
4406 uirow = MSI_CreateRecord( 4 );
4407 MSI_RecordSetStringW( uirow, 1, identifier );
4408 MSI_RecordSetStringW( uirow, 2, deformated_section );
4409 MSI_RecordSetStringW( uirow, 3, deformated_key );
4410 MSI_RecordSetStringW( uirow, 4, deformated_value );
4411 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4412 msiobj_release( &uirow->hdr );
4414 msi_free( deformated_key );
4415 msi_free( deformated_value );
4416 msi_free( deformated_section );
4417 return ERROR_SUCCESS;
4420 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4422 static const WCHAR query[] = {
4423 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4424 '`','I','n','i','F','i','l','e','`',0};
4425 static const WCHAR remove_query[] = {
4426 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4427 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4431 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4432 if (rc == ERROR_SUCCESS)
4434 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4435 msiobj_release( &view->hdr );
4436 if (rc != ERROR_SUCCESS)
4439 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4440 if (rc == ERROR_SUCCESS)
4442 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4443 msiobj_release( &view->hdr );
4444 if (rc != ERROR_SUCCESS)
4447 return ERROR_SUCCESS;
4450 static void register_dll( const WCHAR *dll, BOOL unregister )
4454 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4457 HRESULT (WINAPI *func_ptr)( void );
4458 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4460 func_ptr = (void *)GetProcAddress( hmod, func );
4463 HRESULT hr = func_ptr();
4465 WARN("failed to register dll 0x%08x\n", hr);
4468 WARN("entry point %s not found\n", func);
4469 FreeLibrary( hmod );
4472 WARN("failed to load library %u\n", GetLastError());
4475 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4477 MSIPACKAGE *package = param;
4482 filename = MSI_RecordGetString(row,1);
4483 file = msi_get_loaded_file( package, filename );
4486 WARN("unable to find file %s\n", debugstr_w(filename));
4487 return ERROR_SUCCESS;
4489 file->Component->Action = msi_get_component_action( package, file->Component );
4490 if (file->Component->Action != INSTALLSTATE_LOCAL)
4492 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4493 return ERROR_SUCCESS;
4496 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4497 register_dll( file->TargetPath, FALSE );
4499 uirow = MSI_CreateRecord( 2 );
4500 MSI_RecordSetStringW( uirow, 1, filename );
4501 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4502 msi_ui_actiondata( package, szSelfRegModules, uirow );
4503 msiobj_release( &uirow->hdr );
4505 return ERROR_SUCCESS;
4508 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4510 static const WCHAR query[] = {
4511 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4512 '`','S','e','l','f','R','e','g','`',0};
4516 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4517 if (rc != ERROR_SUCCESS)
4518 return ERROR_SUCCESS;
4520 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4521 msiobj_release(&view->hdr);
4525 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4527 MSIPACKAGE *package = param;
4532 filename = MSI_RecordGetString( row, 1 );
4533 file = msi_get_loaded_file( package, filename );
4536 WARN("unable to find file %s\n", debugstr_w(filename));
4537 return ERROR_SUCCESS;
4539 file->Component->Action = msi_get_component_action( package, file->Component );
4540 if (file->Component->Action != INSTALLSTATE_ABSENT)
4542 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4543 return ERROR_SUCCESS;
4546 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4547 register_dll( file->TargetPath, TRUE );
4549 uirow = MSI_CreateRecord( 2 );
4550 MSI_RecordSetStringW( uirow, 1, filename );
4551 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4552 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4553 msiobj_release( &uirow->hdr );
4555 return ERROR_SUCCESS;
4558 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4560 static const WCHAR query[] = {
4561 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4562 '`','S','e','l','f','R','e','g','`',0};
4566 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4567 if (rc != ERROR_SUCCESS)
4568 return ERROR_SUCCESS;
4570 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4571 msiobj_release( &view->hdr );
4575 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4577 MSIFEATURE *feature;
4579 HKEY hkey = NULL, userdata = NULL;
4581 if (!msi_check_publish(package))
4582 return ERROR_SUCCESS;
4584 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4586 if (rc != ERROR_SUCCESS)
4589 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4591 if (rc != ERROR_SUCCESS)
4594 /* here the guids are base 85 encoded */
4595 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4601 BOOL absent = FALSE;
4604 if (feature->Action != INSTALLSTATE_LOCAL &&
4605 feature->Action != INSTALLSTATE_SOURCE &&
4606 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4609 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4613 if (feature->Feature_Parent)
4614 size += strlenW( feature->Feature_Parent )+2;
4616 data = msi_alloc(size * sizeof(WCHAR));
4619 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4621 MSICOMPONENT* component = cl->component;
4625 if (component->ComponentId)
4627 TRACE("From %s\n",debugstr_w(component->ComponentId));
4628 CLSIDFromString(component->ComponentId, &clsid);
4629 encode_base85_guid(&clsid,buf);
4630 TRACE("to %s\n",debugstr_w(buf));
4635 if (feature->Feature_Parent)
4637 static const WCHAR sep[] = {'\2',0};
4639 strcatW(data,feature->Feature_Parent);
4642 msi_reg_set_val_str( userdata, feature->Feature, data );
4646 if (feature->Feature_Parent)
4647 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4650 size += sizeof(WCHAR);
4651 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4652 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4656 size += 2*sizeof(WCHAR);
4657 data = msi_alloc(size);
4660 if (feature->Feature_Parent)
4661 strcpyW( &data[1], feature->Feature_Parent );
4662 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4668 uirow = MSI_CreateRecord( 1 );
4669 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4670 msi_ui_actiondata( package, szPublishFeatures, uirow );
4671 msiobj_release( &uirow->hdr );
4672 /* FIXME: call msi_ui_progress? */
4677 RegCloseKey(userdata);
4681 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4687 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4689 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4691 if (r == ERROR_SUCCESS)
4693 RegDeleteValueW(hkey, feature->Feature);
4697 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4699 if (r == ERROR_SUCCESS)
4701 RegDeleteValueW(hkey, feature->Feature);
4705 uirow = MSI_CreateRecord( 1 );
4706 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4707 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4708 msiobj_release( &uirow->hdr );
4710 return ERROR_SUCCESS;
4713 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4715 MSIFEATURE *feature;
4717 if (!msi_check_unpublish(package))
4718 return ERROR_SUCCESS;
4720 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4722 msi_unpublish_feature(package, feature);
4725 return ERROR_SUCCESS;
4728 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4732 WCHAR date[9], *val, *buffer;
4733 const WCHAR *prop, *key;
4735 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4736 static const WCHAR modpath_fmt[] =
4737 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4738 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4739 static const WCHAR szModifyPath[] =
4740 {'M','o','d','i','f','y','P','a','t','h',0};
4741 static const WCHAR szUninstallString[] =
4742 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4743 static const WCHAR szEstimatedSize[] =
4744 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4745 static const WCHAR szDisplayVersion[] =
4746 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4747 static const WCHAR szInstallSource[] =
4748 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4749 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4750 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4751 static const WCHAR szAuthorizedCDFPrefix[] =
4752 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4753 static const WCHAR szARPCONTACT[] =
4754 {'A','R','P','C','O','N','T','A','C','T',0};
4755 static const WCHAR szContact[] =
4756 {'C','o','n','t','a','c','t',0};
4757 static const WCHAR szARPCOMMENTS[] =
4758 {'A','R','P','C','O','M','M','E','N','T','S',0};
4759 static const WCHAR szComments[] =
4760 {'C','o','m','m','e','n','t','s',0};
4761 static const WCHAR szProductName[] =
4762 {'P','r','o','d','u','c','t','N','a','m','e',0};
4763 static const WCHAR szDisplayName[] =
4764 {'D','i','s','p','l','a','y','N','a','m','e',0};
4765 static const WCHAR szARPHELPLINK[] =
4766 {'A','R','P','H','E','L','P','L','I','N','K',0};
4767 static const WCHAR szHelpLink[] =
4768 {'H','e','l','p','L','i','n','k',0};
4769 static const WCHAR szARPHELPTELEPHONE[] =
4770 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4771 static const WCHAR szHelpTelephone[] =
4772 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4773 static const WCHAR szARPINSTALLLOCATION[] =
4774 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4775 static const WCHAR szInstallLocation[] =
4776 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4777 static const WCHAR szManufacturer[] =
4778 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4779 static const WCHAR szPublisher[] =
4780 {'P','u','b','l','i','s','h','e','r',0};
4781 static const WCHAR szARPREADME[] =
4782 {'A','R','P','R','E','A','D','M','E',0};
4783 static const WCHAR szReadme[] =
4784 {'R','e','a','d','M','e',0};
4785 static const WCHAR szARPSIZE[] =
4786 {'A','R','P','S','I','Z','E',0};
4787 static const WCHAR szSize[] =
4788 {'S','i','z','e',0};
4789 static const WCHAR szARPURLINFOABOUT[] =
4790 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4791 static const WCHAR szURLInfoAbout[] =
4792 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4793 static const WCHAR szARPURLUPDATEINFO[] =
4794 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4795 static const WCHAR szURLUpdateInfo[] =
4796 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4797 static const WCHAR szARPSYSTEMCOMPONENT[] =
4798 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4799 static const WCHAR szSystemComponent[] =
4800 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4802 static const WCHAR *propval[] = {
4803 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4804 szARPCONTACT, szContact,
4805 szARPCOMMENTS, szComments,
4806 szProductName, szDisplayName,
4807 szARPHELPLINK, szHelpLink,
4808 szARPHELPTELEPHONE, szHelpTelephone,
4809 szARPINSTALLLOCATION, szInstallLocation,
4810 szSourceDir, szInstallSource,
4811 szManufacturer, szPublisher,
4812 szARPREADME, szReadme,
4814 szARPURLINFOABOUT, szURLInfoAbout,
4815 szARPURLUPDATEINFO, szURLUpdateInfo,
4818 const WCHAR **p = propval;
4824 val = msi_dup_property(package->db, prop);
4825 msi_reg_set_val_str(hkey, key, val);
4829 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4830 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4832 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4834 size = deformat_string(package, modpath_fmt, &buffer);
4835 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4836 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4839 /* FIXME: Write real Estimated Size when we have it */
4840 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4842 GetLocalTime(&systime);
4843 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4844 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4846 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4847 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4849 buffer = msi_dup_property(package->db, szProductVersion);
4850 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4853 DWORD verdword = msi_version_str_to_dword(buffer);
4855 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4856 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4857 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4861 return ERROR_SUCCESS;
4864 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4866 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4868 LPWSTR upgrade_code;
4869 HKEY hkey, props, upgrade_key;
4872 /* FIXME: also need to publish if the product is in advertise mode */
4873 if (!msi_check_publish(package))
4874 return ERROR_SUCCESS;
4876 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4877 if (rc != ERROR_SUCCESS)
4880 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4881 if (rc != ERROR_SUCCESS)
4884 rc = msi_publish_install_properties(package, hkey);
4885 if (rc != ERROR_SUCCESS)
4888 rc = msi_publish_install_properties(package, props);
4889 if (rc != ERROR_SUCCESS)
4892 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4895 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4896 if (rc == ERROR_SUCCESS)
4898 squash_guid( package->ProductCode, squashed_pc );
4899 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4900 RegCloseKey( upgrade_key );
4902 msi_free( upgrade_code );
4904 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4905 package->delete_on_close = FALSE;
4908 uirow = MSI_CreateRecord( 1 );
4909 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4910 msi_ui_actiondata( package, szRegisterProduct, uirow );
4911 msiobj_release( &uirow->hdr );
4914 return ERROR_SUCCESS;
4917 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4919 return execute_script(package, SCRIPT_INSTALL);
4922 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4924 MSIPACKAGE *package = param;
4925 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4926 WCHAR *p, *icon_path;
4928 if (!icon) return ERROR_SUCCESS;
4929 if ((icon_path = msi_build_icon_path( package, icon )))
4931 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4932 DeleteFileW( icon_path );
4933 if ((p = strrchrW( icon_path, '\\' )))
4936 RemoveDirectoryW( icon_path );
4938 msi_free( icon_path );
4940 return ERROR_SUCCESS;
4943 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4945 static const WCHAR query[]= {
4946 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4950 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4951 if (r == ERROR_SUCCESS)
4953 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4954 msiobj_release( &view->hdr );
4955 if (r != ERROR_SUCCESS)
4958 return ERROR_SUCCESS;
4961 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4963 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4964 WCHAR *upgrade, **features;
4965 BOOL full_uninstall = TRUE;
4966 MSIFEATURE *feature;
4967 MSIPATCHINFO *patch;
4970 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4972 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4974 features = msi_split_string( remove, ',' );
4975 for (i = 0; features && features[i]; i++)
4977 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4981 if (!full_uninstall)
4982 return ERROR_SUCCESS;
4984 MSIREG_DeleteProductKey(package->ProductCode);
4985 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4986 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4988 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4989 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4990 MSIREG_DeleteUserProductKey(package->ProductCode);
4991 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4993 upgrade = msi_dup_property(package->db, szUpgradeCode);
4996 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4997 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5001 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5003 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5004 if (!strcmpW( package->ProductCode, patch->products ))
5006 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5007 patch->delete_on_close = TRUE;
5009 /* FIXME: remove local patch package if this is the last product */
5011 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5012 package->delete_on_close = TRUE;
5014 msi_unpublish_icons( package );
5015 return ERROR_SUCCESS;
5018 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5023 /* turn off scheduling */
5024 package->script->CurrentlyScripting= FALSE;
5026 /* first do the same as an InstallExecute */
5027 rc = ACTION_InstallExecute(package);
5028 if (rc != ERROR_SUCCESS)
5031 /* then handle commit actions */
5032 rc = execute_script(package, SCRIPT_COMMIT);
5033 if (rc != ERROR_SUCCESS)
5036 remove = msi_dup_property(package->db, szRemove);
5037 rc = msi_unpublish_product(package, remove);
5042 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5044 static const WCHAR RunOnce[] = {
5045 'S','o','f','t','w','a','r','e','\\',
5046 'M','i','c','r','o','s','o','f','t','\\',
5047 'W','i','n','d','o','w','s','\\',
5048 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5049 'R','u','n','O','n','c','e',0};
5050 static const WCHAR InstallRunOnce[] = {
5051 'S','o','f','t','w','a','r','e','\\',
5052 'M','i','c','r','o','s','o','f','t','\\',
5053 'W','i','n','d','o','w','s','\\',
5054 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5055 'I','n','s','t','a','l','l','e','r','\\',
5056 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5058 static const WCHAR msiexec_fmt[] = {
5060 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5061 '\"','%','s','\"',0};
5062 static const WCHAR install_fmt[] = {
5063 '/','I',' ','\"','%','s','\"',' ',
5064 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5065 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5066 WCHAR buffer[256], sysdir[MAX_PATH];
5068 WCHAR squished_pc[100];
5070 squash_guid(package->ProductCode,squished_pc);
5072 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5073 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5074 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5077 msi_reg_set_val_str( hkey, squished_pc, buffer );
5080 TRACE("Reboot command %s\n",debugstr_w(buffer));
5082 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5083 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5085 msi_reg_set_val_str( hkey, squished_pc, buffer );
5088 return ERROR_INSTALL_SUSPEND;
5091 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5093 static const WCHAR query[] =
5094 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5095 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5096 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5097 MSIRECORD *rec, *row;
5103 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5105 rec = MSI_CreateRecord( count + 2 );
5106 str = MSI_RecordGetString( row, 1 );
5107 MSI_RecordSetStringW( rec, 0, str );
5108 msiobj_release( &row->hdr );
5109 MSI_RecordSetInteger( rec, 1, error );
5111 va_start( va, count );
5112 for (i = 0; i < count; i++)
5114 str = va_arg( va, const WCHAR *);
5115 MSI_RecordSetStringW( rec, i + 2, str );
5119 MSI_FormatRecordW( package, rec, NULL, &size );
5121 data = msi_alloc( size * sizeof(WCHAR) );
5122 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5124 msiobj_release( &rec->hdr );
5128 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5134 * We are currently doing what should be done here in the top level Install
5135 * however for Administrative and uninstalls this step will be needed
5137 if (!package->PackagePath)
5138 return ERROR_SUCCESS;
5140 msi_set_sourcedir_props(package, TRUE);
5142 attrib = GetFileAttributesW(package->db->path);
5143 if (attrib == INVALID_FILE_ATTRIBUTES)
5148 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5149 package->Context, MSICODE_PRODUCT,
5150 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5151 if (rc == ERROR_MORE_DATA)
5153 prompt = msi_alloc(size * sizeof(WCHAR));
5154 MsiSourceListGetInfoW(package->ProductCode, NULL,
5155 package->Context, MSICODE_PRODUCT,
5156 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5159 prompt = strdupW(package->db->path);
5161 msg = msi_build_error_string(package, 1302, 1, prompt);
5163 while(attrib == INVALID_FILE_ATTRIBUTES)
5165 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5169 return ERROR_INSTALL_USEREXIT;
5171 attrib = GetFileAttributesW(package->db->path);
5177 return ERROR_SUCCESS;
5182 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5185 LPWSTR buffer, productid = NULL;
5186 UINT i, rc = ERROR_SUCCESS;
5189 static const WCHAR szPropKeys[][80] =
5191 {'P','r','o','d','u','c','t','I','D',0},
5192 {'U','S','E','R','N','A','M','E',0},
5193 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5197 static const WCHAR szRegKeys[][80] =
5199 {'P','r','o','d','u','c','t','I','D',0},
5200 {'R','e','g','O','w','n','e','r',0},
5201 {'R','e','g','C','o','m','p','a','n','y',0},
5205 if (msi_check_unpublish(package))
5207 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5211 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5215 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5217 if (rc != ERROR_SUCCESS)
5220 for( i = 0; szPropKeys[i][0]; i++ )
5222 buffer = msi_dup_property( package->db, szPropKeys[i] );
5223 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5228 uirow = MSI_CreateRecord( 1 );
5229 MSI_RecordSetStringW( uirow, 1, productid );
5230 msi_ui_actiondata( package, szRegisterUser, uirow );
5231 msiobj_release( &uirow->hdr );
5233 msi_free(productid);
5239 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5243 package->script->InWhatSequence |= SEQUENCE_EXEC;
5244 rc = ACTION_ProcessExecSequence(package,FALSE);
5248 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5250 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5251 WCHAR productid_85[21], component_85[21], *ret;
5255 /* > is used if there is a component GUID and < if not. */
5257 productid_85[0] = 0;
5258 component_85[0] = 0;
5259 CLSIDFromString( package->ProductCode, &clsid );
5261 encode_base85_guid( &clsid, productid_85 );
5264 CLSIDFromString( component->ComponentId, &clsid );
5265 encode_base85_guid( &clsid, component_85 );
5268 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5269 debugstr_w(component_85));
5271 sz = 20 + strlenW( feature ) + 20 + 3;
5272 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5273 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5277 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5279 MSIPACKAGE *package = param;
5280 LPCWSTR compgroupid, component, feature, qualifier, text;
5281 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5290 feature = MSI_RecordGetString(rec, 5);
5291 feat = msi_get_loaded_feature(package, feature);
5293 return ERROR_SUCCESS;
5295 feat->Action = msi_get_feature_action( package, feat );
5296 if (feat->Action != INSTALLSTATE_LOCAL &&
5297 feat->Action != INSTALLSTATE_SOURCE &&
5298 feat->Action != INSTALLSTATE_ADVERTISED)
5300 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5301 return ERROR_SUCCESS;
5304 component = MSI_RecordGetString(rec, 3);
5305 comp = msi_get_loaded_component(package, component);
5307 return ERROR_SUCCESS;
5309 compgroupid = MSI_RecordGetString(rec,1);
5310 qualifier = MSI_RecordGetString(rec,2);
5312 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5313 if (rc != ERROR_SUCCESS)
5316 advertise = msi_create_component_advertise_string( package, comp, feature );
5317 text = MSI_RecordGetString( rec, 4 );
5320 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5321 strcpyW( p, advertise );
5323 msi_free( advertise );
5326 existing = msi_reg_get_val_str( hkey, qualifier );
5328 sz = strlenW( advertise ) + 1;
5331 for (p = existing; *p; p += len)
5333 len = strlenW( p ) + 1;
5334 if (strcmpW( advertise, p )) sz += len;
5337 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5339 rc = ERROR_OUTOFMEMORY;
5345 for (p = existing; *p; p += len)
5347 len = strlenW( p ) + 1;
5348 if (strcmpW( advertise, p ))
5350 memcpy( q, p, len * sizeof(WCHAR) );
5355 strcpyW( q, advertise );
5356 q[strlenW( q ) + 1] = 0;
5358 msi_reg_set_val_multi_str( hkey, qualifier, output );
5363 msi_free( advertise );
5364 msi_free( existing );
5367 uirow = MSI_CreateRecord( 2 );
5368 MSI_RecordSetStringW( uirow, 1, compgroupid );
5369 MSI_RecordSetStringW( uirow, 2, qualifier);
5370 msi_ui_actiondata( package, szPublishComponents, uirow );
5371 msiobj_release( &uirow->hdr );
5372 /* FIXME: call ui_progress? */
5378 * At present I am ignorning the advertised components part of this and only
5379 * focusing on the qualified component sets
5381 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5383 static const WCHAR query[] = {
5384 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5385 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5389 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5390 if (rc != ERROR_SUCCESS)
5391 return ERROR_SUCCESS;
5393 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5394 msiobj_release(&view->hdr);
5398 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5400 static const WCHAR szInstallerComponents[] = {
5401 'S','o','f','t','w','a','r','e','\\',
5402 'M','i','c','r','o','s','o','f','t','\\',
5403 'I','n','s','t','a','l','l','e','r','\\',
5404 'C','o','m','p','o','n','e','n','t','s','\\',0};
5406 MSIPACKAGE *package = param;
5407 LPCWSTR compgroupid, component, feature, qualifier;
5411 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5414 feature = MSI_RecordGetString( rec, 5 );
5415 feat = msi_get_loaded_feature( package, feature );
5417 return ERROR_SUCCESS;
5419 feat->Action = msi_get_feature_action( package, feat );
5420 if (feat->Action != INSTALLSTATE_ABSENT)
5422 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5423 return ERROR_SUCCESS;
5426 component = MSI_RecordGetString( rec, 3 );
5427 comp = msi_get_loaded_component( package, component );
5429 return ERROR_SUCCESS;
5431 compgroupid = MSI_RecordGetString( rec, 1 );
5432 qualifier = MSI_RecordGetString( rec, 2 );
5434 squash_guid( compgroupid, squashed );
5435 strcpyW( keypath, szInstallerComponents );
5436 strcatW( keypath, squashed );
5438 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5439 if (res != ERROR_SUCCESS)
5441 WARN("Unable to delete component key %d\n", res);
5444 uirow = MSI_CreateRecord( 2 );
5445 MSI_RecordSetStringW( uirow, 1, compgroupid );
5446 MSI_RecordSetStringW( uirow, 2, qualifier );
5447 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5448 msiobj_release( &uirow->hdr );
5450 return ERROR_SUCCESS;
5453 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5455 static const WCHAR query[] = {
5456 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5457 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5461 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5462 if (rc != ERROR_SUCCESS)
5463 return ERROR_SUCCESS;
5465 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5466 msiobj_release( &view->hdr );
5470 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5472 static const WCHAR query[] =
5473 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5474 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5475 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5476 MSIPACKAGE *package = param;
5477 MSICOMPONENT *component;
5480 SC_HANDLE hscm = NULL, service = NULL;
5482 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5483 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5484 DWORD serv_type, start_type, err_control;
5485 SERVICE_DESCRIPTIONW sd = {NULL};
5487 comp = MSI_RecordGetString( rec, 12 );
5488 component = msi_get_loaded_component( package, comp );
5491 WARN("service component not found\n");
5494 component->Action = msi_get_component_action( package, component );
5495 if (component->Action != INSTALLSTATE_LOCAL)
5497 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5500 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5503 ERR("Failed to open the SC Manager!\n");
5507 start_type = MSI_RecordGetInteger(rec, 5);
5508 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5511 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5512 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5513 serv_type = MSI_RecordGetInteger(rec, 4);
5514 err_control = MSI_RecordGetInteger(rec, 6);
5515 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5516 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5517 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5518 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5519 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5520 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5522 /* fetch the service path */
5523 row = MSI_QueryGetRecord(package->db, query, comp);
5526 ERR("Query failed\n");
5529 key = MSI_RecordGetString(row, 6);
5530 file = msi_get_loaded_file(package, key);
5531 msiobj_release(&row->hdr);
5534 ERR("Failed to load the service file\n");
5538 if (!args || !args[0]) image_path = file->TargetPath;
5541 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5542 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5543 return ERROR_OUTOFMEMORY;
5545 strcpyW(image_path, file->TargetPath);
5546 strcatW(image_path, szSpace);
5547 strcatW(image_path, args);
5549 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5550 start_type, err_control, image_path, load_order,
5551 NULL, depends, serv_name, pass);
5555 if (GetLastError() != ERROR_SERVICE_EXISTS)
5556 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5558 else if (sd.lpDescription)
5560 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5561 WARN("failed to set service description %u\n", GetLastError());
5564 if (image_path != file->TargetPath) msi_free(image_path);
5566 CloseServiceHandle(service);
5567 CloseServiceHandle(hscm);
5570 msi_free(sd.lpDescription);
5571 msi_free(load_order);
5572 msi_free(serv_name);
5577 return ERROR_SUCCESS;
5580 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5582 static const WCHAR query[] = {
5583 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5584 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5588 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5589 if (rc != ERROR_SUCCESS)
5590 return ERROR_SUCCESS;
5592 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5593 msiobj_release(&view->hdr);
5597 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5598 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5600 LPCWSTR *vector, *temp_vector;
5604 static const WCHAR separator[] = {'[','~',']',0};
5607 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5612 vector = msi_alloc(sizeof(LPWSTR));
5620 vector[*numargs - 1] = p;
5622 if ((q = strstrW(p, separator)))
5626 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5632 vector = temp_vector;
5641 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5643 MSIPACKAGE *package = param;
5646 SC_HANDLE scm = NULL, service = NULL;
5647 LPCWSTR component, *vector = NULL;
5648 LPWSTR name, args, display_name = NULL;
5649 DWORD event, numargs, len, wait, dummy;
5650 UINT r = ERROR_FUNCTION_FAILED;
5651 SERVICE_STATUS_PROCESS status;
5652 ULONGLONG start_time;
5654 component = MSI_RecordGetString(rec, 6);
5655 comp = msi_get_loaded_component(package, component);
5657 return ERROR_SUCCESS;
5659 comp->Action = msi_get_component_action( package, comp );
5660 if (comp->Action != INSTALLSTATE_LOCAL)
5662 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5663 return ERROR_SUCCESS;
5666 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5667 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5668 event = MSI_RecordGetInteger(rec, 3);
5669 wait = MSI_RecordGetInteger(rec, 5);
5671 if (!(event & msidbServiceControlEventStart))
5677 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5680 ERR("Failed to open the service control manager\n");
5685 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5686 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5688 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5689 GetServiceDisplayNameW( scm, name, display_name, &len );
5692 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5695 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5699 vector = msi_service_args_to_vector(args, &numargs);
5701 if (!StartServiceW(service, numargs, vector) &&
5702 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5704 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5711 /* wait for at most 30 seconds for the service to be up and running */
5712 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5713 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5715 TRACE("failed to query service status (%u)\n", GetLastError());
5718 start_time = GetTickCount64();
5719 while (status.dwCurrentState == SERVICE_START_PENDING)
5721 if (GetTickCount64() - start_time > 30000) break;
5723 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5724 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5726 TRACE("failed to query service status (%u)\n", GetLastError());
5730 if (status.dwCurrentState != SERVICE_RUNNING)
5732 WARN("service failed to start %u\n", status.dwCurrentState);
5733 r = ERROR_FUNCTION_FAILED;
5738 uirow = MSI_CreateRecord( 2 );
5739 MSI_RecordSetStringW( uirow, 1, display_name );
5740 MSI_RecordSetStringW( uirow, 2, name );
5741 msi_ui_actiondata( package, szStartServices, uirow );
5742 msiobj_release( &uirow->hdr );
5744 CloseServiceHandle(service);
5745 CloseServiceHandle(scm);
5750 msi_free(display_name);
5754 static UINT ACTION_StartServices( MSIPACKAGE *package )
5756 static const WCHAR query[] = {
5757 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5758 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5762 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5763 if (rc != ERROR_SUCCESS)
5764 return ERROR_SUCCESS;
5766 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5767 msiobj_release(&view->hdr);
5771 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5773 DWORD i, needed, count;
5774 ENUM_SERVICE_STATUSW *dependencies;
5778 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5779 0, &needed, &count))
5782 if (GetLastError() != ERROR_MORE_DATA)
5785 dependencies = msi_alloc(needed);
5789 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5790 needed, &needed, &count))
5793 for (i = 0; i < count; i++)
5795 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5796 SERVICE_STOP | SERVICE_QUERY_STATUS);
5800 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5807 msi_free(dependencies);
5811 static UINT stop_service( LPCWSTR name )
5813 SC_HANDLE scm = NULL, service = NULL;
5814 SERVICE_STATUS status;
5815 SERVICE_STATUS_PROCESS ssp;
5818 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5821 WARN("Failed to open the SCM: %d\n", GetLastError());
5825 service = OpenServiceW(scm, name,
5827 SERVICE_QUERY_STATUS |
5828 SERVICE_ENUMERATE_DEPENDENTS);
5831 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5835 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5836 sizeof(SERVICE_STATUS_PROCESS), &needed))
5838 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5842 if (ssp.dwCurrentState == SERVICE_STOPPED)
5845 stop_service_dependents(scm, service);
5847 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5848 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5851 CloseServiceHandle(service);
5852 CloseServiceHandle(scm);
5854 return ERROR_SUCCESS;
5857 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5859 MSIPACKAGE *package = param;
5863 LPWSTR name = NULL, display_name = NULL;
5867 event = MSI_RecordGetInteger( rec, 3 );
5868 if (!(event & msidbServiceControlEventStop))
5869 return ERROR_SUCCESS;
5871 component = MSI_RecordGetString( rec, 6 );
5872 comp = msi_get_loaded_component( package, component );
5874 return ERROR_SUCCESS;
5876 comp->Action = msi_get_component_action( package, comp );
5877 if (comp->Action != INSTALLSTATE_ABSENT)
5879 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5880 return ERROR_SUCCESS;
5883 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5886 ERR("Failed to open the service control manager\n");
5891 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5892 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5894 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5895 GetServiceDisplayNameW( scm, name, display_name, &len );
5897 CloseServiceHandle( scm );
5899 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5900 stop_service( name );
5903 uirow = MSI_CreateRecord( 2 );
5904 MSI_RecordSetStringW( uirow, 1, display_name );
5905 MSI_RecordSetStringW( uirow, 2, name );
5906 msi_ui_actiondata( package, szStopServices, uirow );
5907 msiobj_release( &uirow->hdr );
5910 msi_free( display_name );
5911 return ERROR_SUCCESS;
5914 static UINT ACTION_StopServices( MSIPACKAGE *package )
5916 static const WCHAR query[] = {
5917 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5918 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5922 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5923 if (rc != ERROR_SUCCESS)
5924 return ERROR_SUCCESS;
5926 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5927 msiobj_release(&view->hdr);
5931 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5933 MSIPACKAGE *package = param;
5937 LPWSTR name = NULL, display_name = NULL;
5939 SC_HANDLE scm = NULL, service = NULL;
5941 event = MSI_RecordGetInteger( rec, 3 );
5942 if (!(event & msidbServiceControlEventDelete))
5943 return ERROR_SUCCESS;
5945 component = MSI_RecordGetString(rec, 6);
5946 comp = msi_get_loaded_component(package, component);
5948 return ERROR_SUCCESS;
5950 comp->Action = msi_get_component_action( package, comp );
5951 if (comp->Action != INSTALLSTATE_ABSENT)
5953 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5954 return ERROR_SUCCESS;
5957 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5958 stop_service( name );
5960 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5963 WARN("Failed to open the SCM: %d\n", GetLastError());
5968 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5969 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5971 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5972 GetServiceDisplayNameW( scm, name, display_name, &len );
5975 service = OpenServiceW( scm, name, DELETE );
5978 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5982 if (!DeleteService( service ))
5983 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5986 uirow = MSI_CreateRecord( 2 );
5987 MSI_RecordSetStringW( uirow, 1, display_name );
5988 MSI_RecordSetStringW( uirow, 2, name );
5989 msi_ui_actiondata( package, szDeleteServices, uirow );
5990 msiobj_release( &uirow->hdr );
5992 CloseServiceHandle( service );
5993 CloseServiceHandle( scm );
5995 msi_free( display_name );
5997 return ERROR_SUCCESS;
6000 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6002 static const WCHAR query[] = {
6003 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6004 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6008 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6009 if (rc != ERROR_SUCCESS)
6010 return ERROR_SUCCESS;
6012 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6013 msiobj_release( &view->hdr );
6017 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6019 MSIPACKAGE *package = param;
6020 LPWSTR driver, driver_path, ptr;
6021 WCHAR outpath[MAX_PATH];
6022 MSIFILE *driver_file = NULL, *setup_file = NULL;
6025 LPCWSTR desc, file_key, component;
6027 UINT r = ERROR_SUCCESS;
6029 static const WCHAR driver_fmt[] = {
6030 'D','r','i','v','e','r','=','%','s',0};
6031 static const WCHAR setup_fmt[] = {
6032 'S','e','t','u','p','=','%','s',0};
6033 static const WCHAR usage_fmt[] = {
6034 'F','i','l','e','U','s','a','g','e','=','1',0};
6036 component = MSI_RecordGetString( rec, 2 );
6037 comp = msi_get_loaded_component( package, component );
6039 return ERROR_SUCCESS;
6041 comp->Action = msi_get_component_action( package, comp );
6042 if (comp->Action != INSTALLSTATE_LOCAL)
6044 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6045 return ERROR_SUCCESS;
6047 desc = MSI_RecordGetString(rec, 3);
6049 file_key = MSI_RecordGetString( rec, 4 );
6050 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6052 file_key = MSI_RecordGetString( rec, 5 );
6053 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6057 ERR("ODBC Driver entry not found!\n");
6058 return ERROR_FUNCTION_FAILED;
6061 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6063 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6064 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6066 driver = msi_alloc(len * sizeof(WCHAR));
6068 return ERROR_OUTOFMEMORY;
6071 lstrcpyW(ptr, desc);
6072 ptr += lstrlenW(ptr) + 1;
6074 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6079 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6083 lstrcpyW(ptr, usage_fmt);
6084 ptr += lstrlenW(ptr) + 1;
6087 driver_path = strdupW(driver_file->TargetPath);
6088 ptr = strrchrW(driver_path, '\\');
6089 if (ptr) *ptr = '\0';
6091 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6092 NULL, ODBC_INSTALL_COMPLETE, &usage))
6094 ERR("Failed to install SQL driver!\n");
6095 r = ERROR_FUNCTION_FAILED;
6098 uirow = MSI_CreateRecord( 5 );
6099 MSI_RecordSetStringW( uirow, 1, desc );
6100 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6101 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6102 msi_ui_actiondata( package, szInstallODBC, uirow );
6103 msiobj_release( &uirow->hdr );
6106 msi_free(driver_path);
6111 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6113 MSIPACKAGE *package = param;
6114 LPWSTR translator, translator_path, ptr;
6115 WCHAR outpath[MAX_PATH];
6116 MSIFILE *translator_file = NULL, *setup_file = NULL;
6119 LPCWSTR desc, file_key, component;
6121 UINT r = ERROR_SUCCESS;
6123 static const WCHAR translator_fmt[] = {
6124 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6125 static const WCHAR setup_fmt[] = {
6126 'S','e','t','u','p','=','%','s',0};
6128 component = MSI_RecordGetString( rec, 2 );
6129 comp = msi_get_loaded_component( package, component );
6131 return ERROR_SUCCESS;
6133 comp->Action = msi_get_component_action( package, comp );
6134 if (comp->Action != INSTALLSTATE_LOCAL)
6136 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6137 return ERROR_SUCCESS;
6139 desc = MSI_RecordGetString(rec, 3);
6141 file_key = MSI_RecordGetString( rec, 4 );
6142 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6144 file_key = MSI_RecordGetString( rec, 5 );
6145 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6147 if (!translator_file)
6149 ERR("ODBC Translator entry not found!\n");
6150 return ERROR_FUNCTION_FAILED;
6153 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6155 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6157 translator = msi_alloc(len * sizeof(WCHAR));
6159 return ERROR_OUTOFMEMORY;
6162 lstrcpyW(ptr, desc);
6163 ptr += lstrlenW(ptr) + 1;
6165 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6170 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6175 translator_path = strdupW(translator_file->TargetPath);
6176 ptr = strrchrW(translator_path, '\\');
6177 if (ptr) *ptr = '\0';
6179 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6180 NULL, ODBC_INSTALL_COMPLETE, &usage))
6182 ERR("Failed to install SQL translator!\n");
6183 r = ERROR_FUNCTION_FAILED;
6186 uirow = MSI_CreateRecord( 5 );
6187 MSI_RecordSetStringW( uirow, 1, desc );
6188 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6189 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6190 msi_ui_actiondata( package, szInstallODBC, uirow );
6191 msiobj_release( &uirow->hdr );
6193 msi_free(translator);
6194 msi_free(translator_path);
6199 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6201 MSIPACKAGE *package = param;
6204 LPCWSTR desc, driver, component;
6205 WORD request = ODBC_ADD_SYS_DSN;
6208 UINT r = ERROR_SUCCESS;
6211 static const WCHAR attrs_fmt[] = {
6212 'D','S','N','=','%','s',0 };
6214 component = MSI_RecordGetString( rec, 2 );
6215 comp = msi_get_loaded_component( package, component );
6217 return ERROR_SUCCESS;
6219 comp->Action = msi_get_component_action( package, comp );
6220 if (comp->Action != INSTALLSTATE_LOCAL)
6222 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6223 return ERROR_SUCCESS;
6226 desc = MSI_RecordGetString(rec, 3);
6227 driver = MSI_RecordGetString(rec, 4);
6228 registration = MSI_RecordGetInteger(rec, 5);
6230 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6231 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6233 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6234 attrs = msi_alloc(len * sizeof(WCHAR));
6236 return ERROR_OUTOFMEMORY;
6238 len = sprintfW(attrs, attrs_fmt, desc);
6241 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6243 ERR("Failed to install SQL data source!\n");
6244 r = ERROR_FUNCTION_FAILED;
6247 uirow = MSI_CreateRecord( 5 );
6248 MSI_RecordSetStringW( uirow, 1, desc );
6249 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6250 MSI_RecordSetInteger( uirow, 3, request );
6251 msi_ui_actiondata( package, szInstallODBC, uirow );
6252 msiobj_release( &uirow->hdr );
6259 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6261 static const WCHAR driver_query[] = {
6262 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6263 'O','D','B','C','D','r','i','v','e','r',0};
6264 static const WCHAR translator_query[] = {
6265 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6266 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6267 static const WCHAR source_query[] = {
6268 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6269 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6273 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6274 if (rc == ERROR_SUCCESS)
6276 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6277 msiobj_release(&view->hdr);
6278 if (rc != ERROR_SUCCESS)
6281 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6282 if (rc == ERROR_SUCCESS)
6284 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6285 msiobj_release(&view->hdr);
6286 if (rc != ERROR_SUCCESS)
6289 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6290 if (rc == ERROR_SUCCESS)
6292 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6293 msiobj_release(&view->hdr);
6294 if (rc != ERROR_SUCCESS)
6297 return ERROR_SUCCESS;
6300 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6302 MSIPACKAGE *package = param;
6306 LPCWSTR desc, component;
6308 component = MSI_RecordGetString( rec, 2 );
6309 comp = msi_get_loaded_component( package, component );
6311 return ERROR_SUCCESS;
6313 comp->Action = msi_get_component_action( package, comp );
6314 if (comp->Action != INSTALLSTATE_ABSENT)
6316 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6317 return ERROR_SUCCESS;
6320 desc = MSI_RecordGetString( rec, 3 );
6321 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6323 WARN("Failed to remove ODBC driver\n");
6327 FIXME("Usage count reached 0\n");
6330 uirow = MSI_CreateRecord( 2 );
6331 MSI_RecordSetStringW( uirow, 1, desc );
6332 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6333 msi_ui_actiondata( package, szRemoveODBC, uirow );
6334 msiobj_release( &uirow->hdr );
6336 return ERROR_SUCCESS;
6339 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6341 MSIPACKAGE *package = param;
6345 LPCWSTR desc, component;
6347 component = MSI_RecordGetString( rec, 2 );
6348 comp = msi_get_loaded_component( package, component );
6350 return ERROR_SUCCESS;
6352 comp->Action = msi_get_component_action( package, comp );
6353 if (comp->Action != INSTALLSTATE_ABSENT)
6355 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6356 return ERROR_SUCCESS;
6359 desc = MSI_RecordGetString( rec, 3 );
6360 if (!SQLRemoveTranslatorW( desc, &usage ))
6362 WARN("Failed to remove ODBC translator\n");
6366 FIXME("Usage count reached 0\n");
6369 uirow = MSI_CreateRecord( 2 );
6370 MSI_RecordSetStringW( uirow, 1, desc );
6371 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6372 msi_ui_actiondata( package, szRemoveODBC, uirow );
6373 msiobj_release( &uirow->hdr );
6375 return ERROR_SUCCESS;
6378 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6380 MSIPACKAGE *package = param;
6384 LPCWSTR desc, driver, component;
6385 WORD request = ODBC_REMOVE_SYS_DSN;
6389 static const WCHAR attrs_fmt[] = {
6390 'D','S','N','=','%','s',0 };
6392 component = MSI_RecordGetString( rec, 2 );
6393 comp = msi_get_loaded_component( package, component );
6395 return ERROR_SUCCESS;
6397 comp->Action = msi_get_component_action( package, comp );
6398 if (comp->Action != INSTALLSTATE_ABSENT)
6400 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6401 return ERROR_SUCCESS;
6404 desc = MSI_RecordGetString( rec, 3 );
6405 driver = MSI_RecordGetString( rec, 4 );
6406 registration = MSI_RecordGetInteger( rec, 5 );
6408 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6409 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6411 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6412 attrs = msi_alloc( len * sizeof(WCHAR) );
6414 return ERROR_OUTOFMEMORY;
6416 FIXME("Use ODBCSourceAttribute table\n");
6418 len = sprintfW( attrs, attrs_fmt, desc );
6421 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6423 WARN("Failed to remove ODBC data source\n");
6427 uirow = MSI_CreateRecord( 3 );
6428 MSI_RecordSetStringW( uirow, 1, desc );
6429 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6430 MSI_RecordSetInteger( uirow, 3, request );
6431 msi_ui_actiondata( package, szRemoveODBC, uirow );
6432 msiobj_release( &uirow->hdr );
6434 return ERROR_SUCCESS;
6437 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6439 static const WCHAR driver_query[] = {
6440 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6441 'O','D','B','C','D','r','i','v','e','r',0};
6442 static const WCHAR translator_query[] = {
6443 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6444 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6445 static const WCHAR source_query[] = {
6446 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6447 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6451 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6452 if (rc == ERROR_SUCCESS)
6454 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6455 msiobj_release( &view->hdr );
6456 if (rc != ERROR_SUCCESS)
6459 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6460 if (rc == ERROR_SUCCESS)
6462 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6463 msiobj_release( &view->hdr );
6464 if (rc != ERROR_SUCCESS)
6467 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6468 if (rc == ERROR_SUCCESS)
6470 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6471 msiobj_release( &view->hdr );
6472 if (rc != ERROR_SUCCESS)
6475 return ERROR_SUCCESS;
6478 #define ENV_ACT_SETALWAYS 0x1
6479 #define ENV_ACT_SETABSENT 0x2
6480 #define ENV_ACT_REMOVE 0x4
6481 #define ENV_ACT_REMOVEMATCH 0x8
6483 #define ENV_MOD_MACHINE 0x20000000
6484 #define ENV_MOD_APPEND 0x40000000
6485 #define ENV_MOD_PREFIX 0x80000000
6486 #define ENV_MOD_MASK 0xC0000000
6488 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6490 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6492 LPCWSTR cptr = *name;
6494 static const WCHAR prefix[] = {'[','~',']',0};
6495 static const int prefix_len = 3;
6501 *flags |= ENV_ACT_SETALWAYS;
6502 else if (*cptr == '+')
6503 *flags |= ENV_ACT_SETABSENT;
6504 else if (*cptr == '-')
6505 *flags |= ENV_ACT_REMOVE;
6506 else if (*cptr == '!')
6507 *flags |= ENV_ACT_REMOVEMATCH;
6508 else if (*cptr == '*')
6509 *flags |= ENV_MOD_MACHINE;
6519 ERR("Missing environment variable\n");
6520 return ERROR_FUNCTION_FAILED;
6525 LPCWSTR ptr = *value;
6526 if (!strncmpW(ptr, prefix, prefix_len))
6528 if (ptr[prefix_len] == szSemiColon[0])
6530 *flags |= ENV_MOD_APPEND;
6531 *value += lstrlenW(prefix);
6538 else if (lstrlenW(*value) >= prefix_len)
6540 ptr += lstrlenW(ptr) - prefix_len;
6541 if (!strcmpW( ptr, prefix ))
6543 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6545 *flags |= ENV_MOD_PREFIX;
6546 /* the "[~]" will be removed by deformat_string */;
6556 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6557 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6558 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6559 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6561 ERR("Invalid flags: %08x\n", *flags);
6562 return ERROR_FUNCTION_FAILED;
6566 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6568 return ERROR_SUCCESS;
6571 static UINT open_env_key( DWORD flags, HKEY *key )
6573 static const WCHAR user_env[] =
6574 {'E','n','v','i','r','o','n','m','e','n','t',0};
6575 static const WCHAR machine_env[] =
6576 {'S','y','s','t','e','m','\\',
6577 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6578 'C','o','n','t','r','o','l','\\',
6579 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6580 'E','n','v','i','r','o','n','m','e','n','t',0};
6585 if (flags & ENV_MOD_MACHINE)
6588 root = HKEY_LOCAL_MACHINE;
6593 root = HKEY_CURRENT_USER;
6596 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6597 if (res != ERROR_SUCCESS)
6599 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6600 return ERROR_FUNCTION_FAILED;
6603 return ERROR_SUCCESS;
6606 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6608 MSIPACKAGE *package = param;
6609 LPCWSTR name, value, component;
6610 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6611 DWORD flags, type, size;
6618 component = MSI_RecordGetString(rec, 4);
6619 comp = msi_get_loaded_component(package, component);
6621 return ERROR_SUCCESS;
6623 comp->Action = msi_get_component_action( package, comp );
6624 if (comp->Action != INSTALLSTATE_LOCAL)
6626 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6627 return ERROR_SUCCESS;
6629 name = MSI_RecordGetString(rec, 2);
6630 value = MSI_RecordGetString(rec, 3);
6632 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6634 res = env_parse_flags(&name, &value, &flags);
6635 if (res != ERROR_SUCCESS || !value)
6638 if (value && !deformat_string(package, value, &deformatted))
6640 res = ERROR_OUTOFMEMORY;
6644 value = deformatted;
6646 res = open_env_key( flags, &env );
6647 if (res != ERROR_SUCCESS)
6650 if (flags & ENV_MOD_MACHINE)
6651 action |= 0x20000000;
6655 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6656 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6657 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6660 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6664 /* Nothing to do. */
6667 res = ERROR_SUCCESS;
6671 /* If we are appending but the string was empty, strip ; */
6672 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6674 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6675 newval = strdupW(value);
6678 res = ERROR_OUTOFMEMORY;
6686 /* Contrary to MSDN, +-variable to [~];path works */
6687 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6689 res = ERROR_SUCCESS;
6693 data = msi_alloc(size);
6697 return ERROR_OUTOFMEMORY;
6700 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6701 if (res != ERROR_SUCCESS)
6704 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6707 res = RegDeleteValueW(env, name);
6708 if (res != ERROR_SUCCESS)
6709 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6713 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6714 if (flags & ENV_MOD_MASK)
6718 if (flags & ENV_MOD_APPEND) multiplier++;
6719 if (flags & ENV_MOD_PREFIX) multiplier++;
6720 mod_size = lstrlenW(value) * multiplier;
6721 size += mod_size * sizeof(WCHAR);
6724 newval = msi_alloc(size);
6728 res = ERROR_OUTOFMEMORY;
6732 if (flags & ENV_MOD_PREFIX)
6734 lstrcpyW(newval, value);
6735 ptr = newval + lstrlenW(value);
6736 action |= 0x80000000;
6739 lstrcpyW(ptr, data);
6741 if (flags & ENV_MOD_APPEND)
6743 lstrcatW(newval, value);
6744 action |= 0x40000000;
6747 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6748 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6751 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6755 uirow = MSI_CreateRecord( 3 );
6756 MSI_RecordSetStringW( uirow, 1, name );
6757 MSI_RecordSetStringW( uirow, 2, newval );
6758 MSI_RecordSetInteger( uirow, 3, action );
6759 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6760 msiobj_release( &uirow->hdr );
6762 if (env) RegCloseKey(env);
6763 msi_free(deformatted);
6769 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6771 static const WCHAR query[] = {
6772 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6773 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6777 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6778 if (rc != ERROR_SUCCESS)
6779 return ERROR_SUCCESS;
6781 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6782 msiobj_release(&view->hdr);
6786 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6788 MSIPACKAGE *package = param;
6789 LPCWSTR name, value, component;
6790 LPWSTR deformatted = NULL;
6799 component = MSI_RecordGetString( rec, 4 );
6800 comp = msi_get_loaded_component( package, component );
6802 return ERROR_SUCCESS;
6804 comp->Action = msi_get_component_action( package, comp );
6805 if (comp->Action != INSTALLSTATE_ABSENT)
6807 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6808 return ERROR_SUCCESS;
6810 name = MSI_RecordGetString( rec, 2 );
6811 value = MSI_RecordGetString( rec, 3 );
6813 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6815 r = env_parse_flags( &name, &value, &flags );
6816 if (r != ERROR_SUCCESS)
6819 if (!(flags & ENV_ACT_REMOVE))
6821 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6822 return ERROR_SUCCESS;
6825 if (value && !deformat_string( package, value, &deformatted ))
6826 return ERROR_OUTOFMEMORY;
6828 value = deformatted;
6830 r = open_env_key( flags, &env );
6831 if (r != ERROR_SUCCESS)
6837 if (flags & ENV_MOD_MACHINE)
6838 action |= 0x20000000;
6840 TRACE("Removing %s\n", debugstr_w(name));
6842 res = RegDeleteValueW( env, name );
6843 if (res != ERROR_SUCCESS)
6845 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6850 uirow = MSI_CreateRecord( 3 );
6851 MSI_RecordSetStringW( uirow, 1, name );
6852 MSI_RecordSetStringW( uirow, 2, value );
6853 MSI_RecordSetInteger( uirow, 3, action );
6854 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6855 msiobj_release( &uirow->hdr );
6857 if (env) RegCloseKey( env );
6858 msi_free( deformatted );
6862 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6864 static const WCHAR query[] = {
6865 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6866 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6870 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6871 if (rc != ERROR_SUCCESS)
6872 return ERROR_SUCCESS;
6874 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6875 msiobj_release( &view->hdr );
6879 UINT msi_validate_product_id( MSIPACKAGE *package )
6881 LPWSTR key, template, id;
6882 UINT r = ERROR_SUCCESS;
6884 id = msi_dup_property( package->db, szProductID );
6888 return ERROR_SUCCESS;
6890 template = msi_dup_property( package->db, szPIDTemplate );
6891 key = msi_dup_property( package->db, szPIDKEY );
6892 if (key && template)
6894 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6895 r = msi_set_property( package->db, szProductID, key );
6897 msi_free( template );
6902 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6904 return msi_validate_product_id( package );
6907 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6910 package->need_reboot = 1;
6911 return ERROR_SUCCESS;
6914 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6916 static const WCHAR szAvailableFreeReg[] =
6917 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6919 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6921 TRACE("%p %d kilobytes\n", package, space);
6923 uirow = MSI_CreateRecord( 1 );
6924 MSI_RecordSetInteger( uirow, 1, space );
6925 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6926 msiobj_release( &uirow->hdr );
6928 return ERROR_SUCCESS;
6931 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6933 TRACE("%p\n", package);
6935 msi_set_property( package->db, szRollbackDisabled, szOne );
6936 return ERROR_SUCCESS;
6939 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6941 FIXME("%p\n", package);
6942 return ERROR_SUCCESS;
6945 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6947 static const WCHAR driver_query[] = {
6948 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6949 'O','D','B','C','D','r','i','v','e','r',0};
6950 static const WCHAR translator_query[] = {
6951 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6952 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6956 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6957 if (r == ERROR_SUCCESS)
6960 r = MSI_IterateRecords( view, &count, NULL, package );
6961 msiobj_release( &view->hdr );
6962 if (r != ERROR_SUCCESS)
6964 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6966 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6967 if (r == ERROR_SUCCESS)
6970 r = MSI_IterateRecords( view, &count, NULL, package );
6971 msiobj_release( &view->hdr );
6972 if (r != ERROR_SUCCESS)
6974 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6976 return ERROR_SUCCESS;
6979 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6981 MSIPACKAGE *package = param;
6982 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6985 if ((value = msi_dup_property( package->db, property )))
6987 FIXME("remove %s\n", debugstr_w(value));
6990 return ERROR_SUCCESS;
6993 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6995 static const WCHAR query[] = {
6996 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6997 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7001 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7002 if (r == ERROR_SUCCESS)
7004 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7005 msiobj_release( &view->hdr );
7006 if (r != ERROR_SUCCESS)
7009 return ERROR_SUCCESS;
7012 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7014 MSIPACKAGE *package = param;
7015 int attributes = MSI_RecordGetInteger( rec, 5 );
7017 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7019 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7020 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7021 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7022 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7026 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7028 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7029 if (r != ERROR_SUCCESS)
7030 return ERROR_SUCCESS;
7034 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7035 if (r != ERROR_SUCCESS)
7036 return ERROR_SUCCESS;
7038 RegCloseKey( hkey );
7040 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7041 debugstr_w(upgrade_code), debugstr_w(version_min),
7042 debugstr_w(version_max), debugstr_w(language));
7044 return ERROR_SUCCESS;
7047 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7049 static const WCHAR query[] = {
7050 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7051 'U','p','g','r','a','d','e',0};
7055 if (msi_get_property_int( package->db, szInstalled, 0 ))
7057 TRACE("product is installed, skipping action\n");
7058 return ERROR_SUCCESS;
7060 if (msi_get_property_int( package->db, szPreselected, 0 ))
7062 TRACE("Preselected property is set, not migrating feature states\n");
7063 return ERROR_SUCCESS;
7065 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7066 if (r == ERROR_SUCCESS)
7068 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7069 msiobj_release( &view->hdr );
7070 if (r != ERROR_SUCCESS)
7073 return ERROR_SUCCESS;
7076 static void bind_image( const char *filename, const char *path )
7078 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7080 WARN("failed to bind image %u\n", GetLastError());
7084 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7088 MSIPACKAGE *package = param;
7089 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7090 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7091 char *filenameA, *pathA;
7092 WCHAR *pathW, **path_list;
7094 if (!(file = msi_get_loaded_file( package, key )))
7096 WARN("file %s not found\n", debugstr_w(key));
7097 return ERROR_SUCCESS;
7099 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7100 path_list = msi_split_string( paths, ';' );
7101 if (!path_list) bind_image( filenameA, NULL );
7104 for (i = 0; path_list[i] && path_list[i][0]; i++)
7106 deformat_string( package, path_list[i], &pathW );
7107 if ((pathA = strdupWtoA( pathW )))
7109 bind_image( filenameA, pathA );
7115 msi_free( path_list );
7116 msi_free( filenameA );
7117 return ERROR_SUCCESS;
7120 static UINT ACTION_BindImage( MSIPACKAGE *package )
7122 static const WCHAR query[] = {
7123 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7124 'B','i','n','d','I','m','a','g','e',0};
7128 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7129 if (r == ERROR_SUCCESS)
7131 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7132 msiobj_release( &view->hdr );
7133 if (r != ERROR_SUCCESS)
7136 return ERROR_SUCCESS;
7139 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7141 static const WCHAR query[] = {
7142 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7147 r = MSI_OpenQuery( package->db, &view, query, table );
7148 if (r == ERROR_SUCCESS)
7150 r = MSI_IterateRecords(view, &count, NULL, package);
7151 msiobj_release(&view->hdr);
7152 if (r != ERROR_SUCCESS)
7155 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7156 return ERROR_SUCCESS;
7159 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7161 static const WCHAR table[] = {
7162 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7163 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7166 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7168 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7169 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7172 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7174 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7175 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7178 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7180 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7181 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7184 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7186 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7187 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7192 const WCHAR *action;
7193 UINT (*handler)(MSIPACKAGE *);
7194 const WCHAR *action_rollback;
7198 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7199 { szAppSearch, ACTION_AppSearch, NULL },
7200 { szBindImage, ACTION_BindImage, NULL },
7201 { szCCPSearch, ACTION_CCPSearch, NULL },
7202 { szCostFinalize, ACTION_CostFinalize, NULL },
7203 { szCostInitialize, ACTION_CostInitialize, NULL },
7204 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7205 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7206 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7207 { szDisableRollback, ACTION_DisableRollback, NULL },
7208 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7209 { szExecuteAction, ACTION_ExecuteAction, NULL },
7210 { szFileCost, ACTION_FileCost, NULL },
7211 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7212 { szForceReboot, ACTION_ForceReboot, NULL },
7213 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7214 { szInstallExecute, ACTION_InstallExecute, NULL },
7215 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7216 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7217 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7218 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7219 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7220 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7221 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7222 { szInstallValidate, ACTION_InstallValidate, NULL },
7223 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7224 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7225 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7226 { szMoveFiles, ACTION_MoveFiles, NULL },
7227 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7228 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7229 { szPatchFiles, ACTION_PatchFiles, NULL },
7230 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7231 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7232 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7233 { szPublishProduct, ACTION_PublishProduct, NULL },
7234 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7235 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7236 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7237 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7238 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7239 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7240 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7241 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7242 { szRegisterUser, ACTION_RegisterUser, NULL },
7243 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7244 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7245 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7246 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7247 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7248 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7249 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7250 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7251 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7252 { szResolveSource, ACTION_ResolveSource, NULL },
7253 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7254 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7255 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7256 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7257 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7258 { szStartServices, ACTION_StartServices, szStopServices },
7259 { szStopServices, ACTION_StopServices, szStartServices },
7260 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7261 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7262 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7263 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7264 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7265 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7266 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7267 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7268 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7269 { szValidateProductID, ACTION_ValidateProductID, NULL },
7270 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7271 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7272 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7273 { NULL, NULL, NULL }
7276 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7282 while (StandardActions[i].action != NULL)
7284 if (!strcmpW( StandardActions[i].action, action ))
7286 ui_actionstart( package, action );
7287 if (StandardActions[i].handler)
7289 ui_actioninfo( package, action, TRUE, 0 );
7290 *rc = StandardActions[i].handler( package );
7291 ui_actioninfo( package, action, FALSE, *rc );
7293 if (StandardActions[i].action_rollback && !package->need_rollback)
7295 TRACE("scheduling rollback action\n");
7296 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7301 FIXME("unhandled standard action %s\n", debugstr_w(action));
7302 *rc = ERROR_SUCCESS;
7312 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7314 UINT rc = ERROR_SUCCESS;
7317 TRACE("Performing action (%s)\n", debugstr_w(action));
7319 handled = ACTION_HandleStandardAction(package, action, &rc);
7322 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7326 WARN("unhandled msi action %s\n", debugstr_w(action));
7327 rc = ERROR_FUNCTION_NOT_CALLED;
7333 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7335 UINT rc = ERROR_SUCCESS;
7336 BOOL handled = FALSE;
7338 TRACE("Performing action (%s)\n", debugstr_w(action));
7340 handled = ACTION_HandleStandardAction(package, action, &rc);
7343 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7345 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7350 WARN("unhandled msi action %s\n", debugstr_w(action));
7351 rc = ERROR_FUNCTION_NOT_CALLED;
7357 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7359 UINT rc = ERROR_SUCCESS;
7362 static const WCHAR query[] =
7363 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7364 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7365 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7366 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7367 static const WCHAR ui_query[] =
7368 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7369 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7370 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7371 ' ', '=',' ','%','i',0};
7373 if (needs_ui_sequence(package))
7374 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7376 row = MSI_QueryGetRecord(package->db, query, seq);
7380 LPCWSTR action, cond;
7382 TRACE("Running the actions\n");
7384 /* check conditions */
7385 cond = MSI_RecordGetString(row, 2);
7387 /* this is a hack to skip errors in the condition code */
7388 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7390 msiobj_release(&row->hdr);
7391 return ERROR_SUCCESS;
7394 action = MSI_RecordGetString(row, 1);
7397 ERR("failed to fetch action\n");
7398 msiobj_release(&row->hdr);
7399 return ERROR_FUNCTION_FAILED;
7402 if (needs_ui_sequence(package))
7403 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7405 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7407 msiobj_release(&row->hdr);
7413 /****************************************************
7414 * TOP level entry points
7415 *****************************************************/
7417 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7418 LPCWSTR szCommandLine )
7420 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7421 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7422 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7423 WCHAR *reinstall = NULL;
7427 msi_set_property( package->db, szAction, szInstall );
7429 package->script->InWhatSequence = SEQUENCE_INSTALL;
7436 dir = strdupW(szPackagePath);
7437 p = strrchrW(dir, '\\');
7441 file = szPackagePath + (p - dir);
7446 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7447 GetCurrentDirectoryW(MAX_PATH, dir);
7448 lstrcatW(dir, szBackSlash);
7449 file = szPackagePath;
7452 msi_free( package->PackagePath );
7453 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7454 if (!package->PackagePath)
7457 return ERROR_OUTOFMEMORY;
7460 lstrcpyW(package->PackagePath, dir);
7461 lstrcatW(package->PackagePath, file);
7464 msi_set_sourcedir_props(package, FALSE);
7467 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7468 if (rc != ERROR_SUCCESS)
7471 msi_apply_transforms( package );
7472 msi_apply_patches( package );
7474 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7476 TRACE("setting reinstall property\n");
7477 msi_set_property( package->db, szReinstall, szAll );
7480 /* properties may have been added by a transform */
7481 msi_clone_properties( package );
7483 msi_parse_command_line( package, szCommandLine, FALSE );
7484 msi_adjust_privilege_properties( package );
7485 msi_set_context( package );
7487 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7489 TRACE("disabling rollback\n");
7490 msi_set_property( package->db, szRollbackDisabled, szOne );
7493 if (needs_ui_sequence( package))
7495 package->script->InWhatSequence |= SEQUENCE_UI;
7496 rc = ACTION_ProcessUISequence(package);
7497 ui_exists = ui_sequence_exists(package);
7498 if (rc == ERROR_SUCCESS || !ui_exists)
7500 package->script->InWhatSequence |= SEQUENCE_EXEC;
7501 rc = ACTION_ProcessExecSequence(package, ui_exists);
7505 rc = ACTION_ProcessExecSequence(package, FALSE);
7507 package->script->CurrentlyScripting = FALSE;
7509 /* process the ending type action */
7510 if (rc == ERROR_SUCCESS)
7511 ACTION_PerformActionSequence(package, -1);
7512 else if (rc == ERROR_INSTALL_USEREXIT)
7513 ACTION_PerformActionSequence(package, -2);
7514 else if (rc == ERROR_INSTALL_SUSPEND)
7515 ACTION_PerformActionSequence(package, -4);
7518 ACTION_PerformActionSequence(package, -3);
7519 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7521 package->need_rollback = TRUE;
7525 /* finish up running custom actions */
7526 ACTION_FinishCustomActions(package);
7528 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7530 WARN("installation failed, running rollback script\n");
7531 execute_script( package, SCRIPT_ROLLBACK );
7533 msi_free( reinstall );
7535 if (rc == ERROR_SUCCESS && package->need_reboot)
7536 return ERROR_SUCCESS_REBOOT_REQUIRED;