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) 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) 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 )
412 static const WCHAR ExecSeqQuery [] =
413 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
414 '`','I','n','s','t','a','l','l',
415 'U','I','S','e','q','u','e','n','c','e','`',
416 ' ','W','H','E','R','E',' ',
417 '`','S','e','q','u','e','n','c','e','`',' ',
418 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
419 '`','S','e','q','u','e','n','c','e','`',0};
421 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
422 if (rc == ERROR_SUCCESS)
424 msiobj_release(&view->hdr);
431 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
433 LPWSTR source, check;
435 if (msi_get_property_int( package->db, szInstalled, 0 ))
439 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
440 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
448 db = msi_dup_property( package->db, szOriginalDatabase );
450 return ERROR_OUTOFMEMORY;
452 p = strrchrW( db, '\\' );
455 p = strrchrW( db, '/' );
459 return ERROR_SUCCESS;
464 source = msi_alloc( len * sizeof(WCHAR) );
465 lstrcpynW( source, db, len );
469 check = msi_dup_property( package->db, szSourceDir );
470 if (!check || replace)
472 UINT r = msi_set_property( package->db, szSourceDir, source );
473 if (r == ERROR_SUCCESS)
474 msi_reset_folders( package, TRUE );
478 check = msi_dup_property( package->db, szSOURCEDIR );
479 if (!check || replace)
480 msi_set_property( package->db, szSOURCEDIR, source );
485 return ERROR_SUCCESS;
488 static BOOL needs_ui_sequence(MSIPACKAGE *package)
490 INT level = msi_get_property_int(package->db, szUILevel, 0);
491 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
494 UINT msi_set_context(MSIPACKAGE *package)
498 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
500 num = msi_get_property_int(package->db, szAllUsers, 0);
501 if (num == 1 || num == 2)
502 package->Context = MSIINSTALLCONTEXT_MACHINE;
504 return ERROR_SUCCESS;
507 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
510 LPCWSTR cond, action;
511 MSIPACKAGE *package = param;
513 action = MSI_RecordGetString(row,1);
516 ERR("Error is retrieving action name\n");
517 return ERROR_FUNCTION_FAILED;
520 /* check conditions */
521 cond = MSI_RecordGetString(row,2);
523 /* this is a hack to skip errors in the condition code */
524 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
526 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
527 return ERROR_SUCCESS;
530 if (needs_ui_sequence(package))
531 rc = ACTION_PerformUIAction(package, action, -1);
533 rc = ACTION_PerformAction(package, action, -1);
535 msi_dialog_check_messages( NULL );
537 if (package->CurrentInstallState != ERROR_SUCCESS)
538 rc = package->CurrentInstallState;
540 if (rc == ERROR_FUNCTION_NOT_CALLED)
543 if (rc != ERROR_SUCCESS)
544 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
549 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
553 static const WCHAR query[] =
554 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
556 ' ','W','H','E','R','E',' ',
557 '`','S','e','q','u','e','n','c','e','`',' ',
558 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
559 '`','S','e','q','u','e','n','c','e','`',0};
561 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
563 r = MSI_OpenQuery( package->db, &view, query, szTable );
564 if (r == ERROR_SUCCESS)
566 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
567 msiobj_release(&view->hdr);
573 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
577 static const WCHAR ExecSeqQuery[] =
578 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
579 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
580 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
581 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
582 'O','R','D','E','R',' ', 'B','Y',' ',
583 '`','S','e','q','u','e','n','c','e','`',0 };
584 static const WCHAR IVQuery[] =
585 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
586 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
587 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
588 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
589 ' ','\'', 'I','n','s','t','a','l','l',
590 'V','a','l','i','d','a','t','e','\'', 0};
593 if (package->script->ExecuteSequenceRun)
595 TRACE("Execute Sequence already Run\n");
596 return ERROR_SUCCESS;
599 package->script->ExecuteSequenceRun = TRUE;
601 /* get the sequence number */
604 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
606 return ERROR_FUNCTION_FAILED;
607 seq = MSI_RecordGetInteger(row,1);
608 msiobj_release(&row->hdr);
611 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
612 if (rc == ERROR_SUCCESS)
614 TRACE("Running the actions\n");
616 msi_set_property(package->db, szSourceDir, NULL);
618 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
619 msiobj_release(&view->hdr);
625 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
629 static const WCHAR ExecSeqQuery [] =
630 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
631 '`','I','n','s','t','a','l','l',
632 'U','I','S','e','q','u','e','n','c','e','`',
633 ' ','W','H','E','R','E',' ',
634 '`','S','e','q','u','e','n','c','e','`',' ',
635 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
636 '`','S','e','q','u','e','n','c','e','`',0};
638 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
639 if (rc == ERROR_SUCCESS)
641 TRACE("Running the actions\n");
643 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
644 msiobj_release(&view->hdr);
650 /********************************************************
651 * ACTION helper functions and functions that perform the actions
652 *******************************************************/
653 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
654 UINT* rc, UINT script, BOOL force )
659 arc = ACTION_CustomAction(package, action, script, force);
661 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
669 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
673 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
675 if (!strcmpW( Component, comp->Component )) return comp;
680 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
684 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
686 if (!strcmpW( Feature, feature->Feature )) return feature;
691 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
695 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
697 if (!strcmpW( key, file->File )) return file;
702 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
706 /* FIXME: There might be more than one patch */
707 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
709 if (!strcmpW( key, patch->File->File )) return patch;
714 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
718 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
720 if (!strcmpW( dir, folder->Directory )) return folder;
726 * Recursively create all directories in the path.
727 * shamelessly stolen from setupapi/queue.c
729 BOOL msi_create_full_path( const WCHAR *path )
735 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
736 strcpyW( new_path, path );
738 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
739 new_path[len - 1] = 0;
741 while (!CreateDirectoryW( new_path, NULL ))
744 DWORD last_error = GetLastError();
745 if (last_error == ERROR_ALREADY_EXISTS) break;
746 if (last_error != ERROR_PATH_NOT_FOUND)
751 if (!(slash = strrchrW( new_path, '\\' )))
756 len = slash - new_path;
758 if (!msi_create_full_path( new_path ))
763 new_path[len] = '\\';
765 msi_free( new_path );
769 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
773 row = MSI_CreateRecord( 4 );
774 MSI_RecordSetInteger( row, 1, a );
775 MSI_RecordSetInteger( row, 2, b );
776 MSI_RecordSetInteger( row, 3, c );
777 MSI_RecordSetInteger( row, 4, d );
778 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
779 msiobj_release( &row->hdr );
781 msi_dialog_check_messages( NULL );
784 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
786 static const WCHAR query[] =
787 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
788 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
789 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
794 if (!package->LastAction || strcmpW( package->LastAction, action ))
796 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
798 if (MSI_RecordIsNull( row, 3 ))
800 msiobj_release( &row->hdr );
803 /* update the cached action format */
804 msi_free( package->ActionFormat );
805 package->ActionFormat = msi_dup_record_field( row, 3 );
806 msi_free( package->LastAction );
807 package->LastAction = strdupW( action );
808 msiobj_release( &row->hdr );
811 MSI_RecordSetStringW( record, 0, package->ActionFormat );
812 MSI_FormatRecordW( package, record, message, &size );
813 row = MSI_CreateRecord( 1 );
814 MSI_RecordSetStringW( row, 1, message );
815 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
816 msiobj_release( &row->hdr );
819 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
823 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
824 return INSTALLSTATE_UNKNOWN;
826 if (package->need_rollback) return comp->Installed;
827 return comp->ActionRequest;
830 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
832 if (package->need_rollback) return feature->Installed;
833 return feature->ActionRequest;
836 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
838 MSIPACKAGE *package = param;
839 LPCWSTR dir, component, full_path;
844 component = MSI_RecordGetString(row, 2);
846 return ERROR_SUCCESS;
848 comp = msi_get_loaded_component(package, component);
850 return ERROR_SUCCESS;
852 comp->Action = msi_get_component_action( package, comp );
853 if (comp->Action != INSTALLSTATE_LOCAL)
855 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
856 return ERROR_SUCCESS;
859 dir = MSI_RecordGetString(row,1);
862 ERR("Unable to get folder id\n");
863 return ERROR_SUCCESS;
866 uirow = MSI_CreateRecord(1);
867 MSI_RecordSetStringW(uirow, 1, dir);
868 msi_ui_actiondata(package, szCreateFolders, uirow);
869 msiobj_release(&uirow->hdr);
871 full_path = msi_get_target_folder( package, dir );
874 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
875 return ERROR_SUCCESS;
877 TRACE("folder is %s\n", debugstr_w(full_path));
879 folder = msi_get_loaded_folder( package, dir );
880 if (folder->State == 0) msi_create_full_path( full_path );
882 return ERROR_SUCCESS;
885 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
887 static const WCHAR query[] =
888 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
889 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
893 /* create all the empty folders specified in the CreateFolder table */
894 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
895 if (rc != ERROR_SUCCESS)
896 return ERROR_SUCCESS;
898 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
899 msiobj_release(&view->hdr);
904 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
906 MSIPACKAGE *package = param;
907 LPCWSTR dir, component, full_path;
912 component = MSI_RecordGetString(row, 2);
914 return ERROR_SUCCESS;
916 comp = msi_get_loaded_component(package, component);
918 return ERROR_SUCCESS;
920 comp->Action = msi_get_component_action( package, comp );
921 if (comp->Action != INSTALLSTATE_ABSENT)
923 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
924 return ERROR_SUCCESS;
927 dir = MSI_RecordGetString( row, 1 );
930 ERR("Unable to get folder id\n");
931 return ERROR_SUCCESS;
934 full_path = msi_get_target_folder( package, dir );
937 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
938 return ERROR_SUCCESS;
940 TRACE("folder is %s\n", debugstr_w(full_path));
942 uirow = MSI_CreateRecord( 1 );
943 MSI_RecordSetStringW( uirow, 1, dir );
944 msi_ui_actiondata( package, szRemoveFolders, uirow );
945 msiobj_release( &uirow->hdr );
947 RemoveDirectoryW( full_path );
948 folder = msi_get_loaded_folder( package, dir );
950 return ERROR_SUCCESS;
953 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
955 static const WCHAR query[] =
956 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
957 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
962 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
963 if (rc != ERROR_SUCCESS)
964 return ERROR_SUCCESS;
966 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
967 msiobj_release( &view->hdr );
972 static UINT load_component( MSIRECORD *row, LPVOID param )
974 MSIPACKAGE *package = param;
977 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
979 return ERROR_FUNCTION_FAILED;
981 list_add_tail( &package->components, &comp->entry );
983 /* fill in the data */
984 comp->Component = msi_dup_record_field( row, 1 );
986 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
988 comp->ComponentId = msi_dup_record_field( row, 2 );
989 comp->Directory = msi_dup_record_field( row, 3 );
990 comp->Attributes = MSI_RecordGetInteger(row,4);
991 comp->Condition = msi_dup_record_field( row, 5 );
992 comp->KeyPath = msi_dup_record_field( row, 6 );
994 comp->Installed = INSTALLSTATE_UNKNOWN;
995 comp->Action = INSTALLSTATE_UNKNOWN;
996 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
998 comp->assembly = msi_load_assembly( package, comp );
999 return ERROR_SUCCESS;
1002 UINT msi_load_all_components( MSIPACKAGE *package )
1004 static const WCHAR query[] = {
1005 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1006 '`','C','o','m','p','o','n','e','n','t','`',0 };
1010 if (!list_empty(&package->components))
1011 return ERROR_SUCCESS;
1013 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1014 if (r != ERROR_SUCCESS)
1017 if (!msi_init_assembly_caches( package ))
1019 ERR("can't initialize assembly caches\n");
1020 msiobj_release( &view->hdr );
1021 return ERROR_FUNCTION_FAILED;
1024 r = MSI_IterateRecords(view, NULL, load_component, package);
1025 msiobj_release(&view->hdr);
1027 msi_destroy_assembly_caches( package );
1032 MSIPACKAGE *package;
1033 MSIFEATURE *feature;
1036 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1040 cl = msi_alloc( sizeof (*cl) );
1042 return ERROR_NOT_ENOUGH_MEMORY;
1043 cl->component = comp;
1044 list_add_tail( &feature->Components, &cl->entry );
1046 return ERROR_SUCCESS;
1049 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1053 fl = msi_alloc( sizeof(*fl) );
1055 return ERROR_NOT_ENOUGH_MEMORY;
1056 fl->feature = child;
1057 list_add_tail( &parent->Children, &fl->entry );
1059 return ERROR_SUCCESS;
1062 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1064 _ilfs* ilfs = param;
1068 component = MSI_RecordGetString(row,1);
1070 /* check to see if the component is already loaded */
1071 comp = msi_get_loaded_component( ilfs->package, component );
1074 ERR("unknown component %s\n", debugstr_w(component));
1075 return ERROR_FUNCTION_FAILED;
1078 add_feature_component( ilfs->feature, comp );
1079 comp->Enabled = TRUE;
1081 return ERROR_SUCCESS;
1084 static UINT load_feature(MSIRECORD * row, LPVOID param)
1086 MSIPACKAGE* package = param;
1087 MSIFEATURE* feature;
1088 static const WCHAR Query1[] =
1089 {'S','E','L','E','C','T',' ',
1090 '`','C','o','m','p','o','n','e','n','t','_','`',
1091 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1092 'C','o','m','p','o','n','e','n','t','s','`',' ',
1093 'W','H','E','R','E',' ',
1094 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1099 /* fill in the data */
1101 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1103 return ERROR_NOT_ENOUGH_MEMORY;
1105 list_init( &feature->Children );
1106 list_init( &feature->Components );
1108 feature->Feature = msi_dup_record_field( row, 1 );
1110 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1112 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1113 feature->Title = msi_dup_record_field( row, 3 );
1114 feature->Description = msi_dup_record_field( row, 4 );
1116 if (!MSI_RecordIsNull(row,5))
1117 feature->Display = MSI_RecordGetInteger(row,5);
1119 feature->Level= MSI_RecordGetInteger(row,6);
1120 feature->Directory = msi_dup_record_field( row, 7 );
1121 feature->Attributes = MSI_RecordGetInteger(row,8);
1123 feature->Installed = INSTALLSTATE_UNKNOWN;
1124 feature->Action = INSTALLSTATE_UNKNOWN;
1125 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1127 list_add_tail( &package->features, &feature->entry );
1129 /* load feature components */
1131 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1132 if (rc != ERROR_SUCCESS)
1133 return ERROR_SUCCESS;
1135 ilfs.package = package;
1136 ilfs.feature = feature;
1138 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1139 msiobj_release(&view->hdr);
1141 return ERROR_SUCCESS;
1144 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1146 MSIPACKAGE *package = param;
1147 MSIFEATURE *parent, *child;
1149 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1151 return ERROR_FUNCTION_FAILED;
1153 if (!child->Feature_Parent)
1154 return ERROR_SUCCESS;
1156 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1158 return ERROR_FUNCTION_FAILED;
1160 add_feature_child( parent, child );
1161 return ERROR_SUCCESS;
1164 UINT msi_load_all_features( MSIPACKAGE *package )
1166 static const WCHAR query[] = {
1167 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1168 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1169 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1173 if (!list_empty(&package->features))
1174 return ERROR_SUCCESS;
1176 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1177 if (r != ERROR_SUCCESS)
1180 r = MSI_IterateRecords( view, NULL, load_feature, package );
1181 if (r != ERROR_SUCCESS)
1184 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1185 msiobj_release( &view->hdr );
1190 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1201 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1203 static const WCHAR query[] = {
1204 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1205 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1206 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1207 MSIQUERY *view = NULL;
1208 MSIRECORD *row = NULL;
1211 TRACE("%s\n", debugstr_w(file->File));
1213 r = MSI_OpenQuery(package->db, &view, query, file->File);
1214 if (r != ERROR_SUCCESS)
1217 r = MSI_ViewExecute(view, NULL);
1218 if (r != ERROR_SUCCESS)
1221 r = MSI_ViewFetch(view, &row);
1222 if (r != ERROR_SUCCESS)
1225 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1226 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1227 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1228 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1229 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1232 if (view) msiobj_release(&view->hdr);
1233 if (row) msiobj_release(&row->hdr);
1237 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1240 static const WCHAR query[] = {
1241 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1242 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1243 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1245 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1248 WARN("query failed\n");
1249 return ERROR_FUNCTION_FAILED;
1252 file->disk_id = MSI_RecordGetInteger( row, 1 );
1253 msiobj_release( &row->hdr );
1254 return ERROR_SUCCESS;
1257 static UINT load_file(MSIRECORD *row, LPVOID param)
1259 MSIPACKAGE* package = param;
1263 /* fill in the data */
1265 file = msi_alloc_zero( sizeof (MSIFILE) );
1267 return ERROR_NOT_ENOUGH_MEMORY;
1269 file->File = msi_dup_record_field( row, 1 );
1271 component = MSI_RecordGetString( row, 2 );
1272 file->Component = msi_get_loaded_component( package, component );
1274 if (!file->Component)
1276 WARN("Component not found: %s\n", debugstr_w(component));
1277 msi_free(file->File);
1279 return ERROR_SUCCESS;
1282 file->FileName = msi_dup_record_field( row, 3 );
1283 msi_reduce_to_long_filename( file->FileName );
1285 file->ShortName = msi_dup_record_field( row, 3 );
1286 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1288 file->FileSize = MSI_RecordGetInteger( row, 4 );
1289 file->Version = msi_dup_record_field( row, 5 );
1290 file->Language = msi_dup_record_field( row, 6 );
1291 file->Attributes = MSI_RecordGetInteger( row, 7 );
1292 file->Sequence = MSI_RecordGetInteger( row, 8 );
1294 file->state = msifs_invalid;
1296 /* if the compressed bits are not set in the file attributes,
1297 * then read the information from the package word count property
1299 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1301 file->IsCompressed = FALSE;
1303 else if (file->Attributes &
1304 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1306 file->IsCompressed = TRUE;
1308 else if (file->Attributes & msidbFileAttributesNoncompressed)
1310 file->IsCompressed = FALSE;
1314 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1317 load_file_hash(package, file);
1318 load_file_disk_id(package, file);
1320 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1322 list_add_tail( &package->files, &file->entry );
1324 return ERROR_SUCCESS;
1327 static UINT load_all_files(MSIPACKAGE *package)
1331 static const WCHAR Query[] =
1332 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1333 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1334 '`','S','e','q','u','e','n','c','e','`', 0};
1336 if (!list_empty(&package->files))
1337 return ERROR_SUCCESS;
1339 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1340 if (rc != ERROR_SUCCESS)
1341 return ERROR_SUCCESS;
1343 rc = MSI_IterateRecords(view, NULL, load_file, package);
1344 msiobj_release(&view->hdr);
1346 return ERROR_SUCCESS;
1349 static UINT load_media( MSIRECORD *row, LPVOID param )
1351 MSIPACKAGE *package = param;
1352 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1353 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1355 /* FIXME: load external cabinets and directory sources too */
1356 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1357 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1358 return ERROR_SUCCESS;
1361 static UINT load_all_media( MSIPACKAGE *package )
1363 static const WCHAR query[] =
1364 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
1365 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
1369 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1370 if (r != ERROR_SUCCESS) return ERROR_SUCCESS;
1372 MSI_IterateRecords( view, NULL, load_media, package );
1373 msiobj_release( &view->hdr );
1374 return ERROR_SUCCESS;
1377 static UINT load_patch(MSIRECORD *row, LPVOID param)
1379 MSIPACKAGE *package = param;
1380 MSIFILEPATCH *patch;
1383 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1385 return ERROR_NOT_ENOUGH_MEMORY;
1387 file_key = msi_dup_record_field( row, 1 );
1388 patch->File = msi_get_loaded_file( package, file_key );
1393 ERR("Failed to find target for patch in File table\n");
1395 return ERROR_FUNCTION_FAILED;
1398 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1400 /* FIXME: The database should be properly transformed */
1401 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1403 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1404 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1405 patch->IsApplied = FALSE;
1408 * Header field - for patch validation.
1409 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1412 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1414 list_add_tail( &package->filepatches, &patch->entry );
1416 return ERROR_SUCCESS;
1419 static UINT load_all_patches(MSIPACKAGE *package)
1423 static const WCHAR Query[] =
1424 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1425 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1426 '`','S','e','q','u','e','n','c','e','`',0};
1428 if (!list_empty(&package->filepatches))
1429 return ERROR_SUCCESS;
1431 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1432 if (rc != ERROR_SUCCESS)
1433 return ERROR_SUCCESS;
1435 rc = MSI_IterateRecords(view, NULL, load_patch, package);
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 list_add_tail( &package->folders, &folder->entry );
1492 return ERROR_SUCCESS;
1495 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1499 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1501 list_add_tail( &parent->children, &fl->entry );
1502 return ERROR_SUCCESS;
1505 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1507 MSIPACKAGE *package = param;
1508 MSIFOLDER *parent, *child;
1510 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1511 return ERROR_FUNCTION_FAILED;
1513 if (!child->Parent) return ERROR_SUCCESS;
1515 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1516 return ERROR_FUNCTION_FAILED;
1518 return add_folder_child( parent, child );
1521 static UINT load_all_folders( MSIPACKAGE *package )
1523 static const WCHAR query[] = {
1524 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1525 '`','D','i','r','e','c','t','o','r','y','`',0 };
1529 if (!list_empty(&package->folders))
1530 return ERROR_SUCCESS;
1532 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1533 if (r != ERROR_SUCCESS)
1536 r = MSI_IterateRecords( view, NULL, load_folder, package );
1537 if (r != ERROR_SUCCESS)
1539 msiobj_release( &view->hdr );
1542 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1543 msiobj_release( &view->hdr );
1547 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1549 msi_set_property( package->db, szCostingComplete, szZero );
1550 msi_set_property( package->db, szRootDrive, szCRoot );
1552 load_all_folders( package );
1553 msi_load_all_components( package );
1554 msi_load_all_features( package );
1555 load_all_files( package );
1556 load_all_patches( package );
1557 load_all_media( package );
1559 return ERROR_SUCCESS;
1562 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1564 const WCHAR *action = package->script->Actions[script][index];
1565 ui_actionstart( package, action );
1566 TRACE("executing %s\n", debugstr_w(action));
1567 return ACTION_PerformAction( package, action, script );
1570 static UINT execute_script( MSIPACKAGE *package, UINT script )
1572 UINT i, rc = ERROR_SUCCESS;
1574 TRACE("executing script %u\n", script);
1576 if (!package->script)
1578 ERR("no script!\n");
1579 return ERROR_FUNCTION_FAILED;
1581 if (script == ROLLBACK_SCRIPT)
1583 for (i = package->script->ActionCount[script]; i > 0; i--)
1585 rc = execute_script_action( package, script, i - 1 );
1586 if (rc != ERROR_SUCCESS) break;
1591 for (i = 0; i < package->script->ActionCount[script]; i++)
1593 rc = execute_script_action( package, script, i );
1594 if (rc != ERROR_SUCCESS) break;
1597 msi_free_action_script(package, script);
1601 static UINT ACTION_FileCost(MSIPACKAGE *package)
1603 return ERROR_SUCCESS;
1606 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1611 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1613 if (!comp->ComponentId) continue;
1615 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1616 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1618 if (r != ERROR_SUCCESS)
1619 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1620 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1622 if (r != ERROR_SUCCESS)
1623 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1624 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1626 if (r != ERROR_SUCCESS)
1627 comp->Installed = INSTALLSTATE_ABSENT;
1631 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1633 MSIFEATURE *feature;
1635 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1637 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1639 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1640 feature->Installed = INSTALLSTATE_ABSENT;
1642 feature->Installed = state;
1646 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1648 return (feature->Level > 0 && feature->Level <= level);
1651 static BOOL process_state_property(MSIPACKAGE* package, int level,
1652 LPCWSTR property, INSTALLSTATE state)
1655 MSIFEATURE *feature;
1657 override = msi_dup_property( package->db, property );
1661 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1663 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1666 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1668 if (!strcmpiW( override, szAll ))
1670 if (feature->Installed != state)
1672 feature->Action = state;
1673 feature->ActionRequest = state;
1678 LPWSTR ptr = override;
1679 LPWSTR ptr2 = strchrW(override,',');
1683 int len = ptr2 - ptr;
1685 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1686 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1688 if (feature->Installed != state)
1690 feature->Action = state;
1691 feature->ActionRequest = state;
1698 ptr2 = strchrW(ptr,',');
1709 static BOOL process_overrides( MSIPACKAGE *package, int level )
1711 static const WCHAR szAddLocal[] =
1712 {'A','D','D','L','O','C','A','L',0};
1713 static const WCHAR szAddSource[] =
1714 {'A','D','D','S','O','U','R','C','E',0};
1715 static const WCHAR szAdvertise[] =
1716 {'A','D','V','E','R','T','I','S','E',0};
1719 /* all these activation/deactivation things happen in order and things
1720 * later on the list override things earlier on the list.
1722 * 0 INSTALLLEVEL processing
1735 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1736 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1737 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1738 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1739 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1742 msi_set_property( package->db, szPreselected, szOne );
1747 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1750 MSICOMPONENT* component;
1751 MSIFEATURE *feature;
1753 TRACE("Checking Install Level\n");
1755 level = msi_get_property_int(package->db, szInstallLevel, 1);
1757 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1759 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1761 if (!is_feature_selected( feature, level )) continue;
1763 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1765 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1767 feature->Action = INSTALLSTATE_SOURCE;
1768 feature->ActionRequest = INSTALLSTATE_SOURCE;
1770 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1772 feature->Action = INSTALLSTATE_ADVERTISED;
1773 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1777 feature->Action = INSTALLSTATE_LOCAL;
1778 feature->ActionRequest = INSTALLSTATE_LOCAL;
1782 /* disable child features of unselected parent or follow parent */
1783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1787 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1789 if (!is_feature_selected( feature, level ))
1791 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1792 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1794 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1796 fl->feature->Action = feature->Action;
1797 fl->feature->ActionRequest = feature->ActionRequest;
1802 else /* preselected */
1804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1806 if (!is_feature_selected( feature, level )) continue;
1808 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1810 if (feature->Installed == INSTALLSTATE_ABSENT)
1812 feature->Action = INSTALLSTATE_UNKNOWN;
1813 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1817 feature->Action = feature->Installed;
1818 feature->ActionRequest = feature->Installed;
1822 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1826 if (!is_feature_selected( feature, level )) continue;
1828 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1830 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1832 fl->feature->Action = feature->Action;
1833 fl->feature->ActionRequest = feature->ActionRequest;
1839 /* now we want to set component state based based on feature state */
1840 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1844 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1845 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1846 feature->ActionRequest, feature->Action);
1848 if (!is_feature_selected( feature, level )) continue;
1850 /* features with components that have compressed files are made local */
1851 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1853 if (cl->component->ForceLocalState &&
1854 feature->ActionRequest == INSTALLSTATE_SOURCE)
1856 feature->Action = INSTALLSTATE_LOCAL;
1857 feature->ActionRequest = INSTALLSTATE_LOCAL;
1862 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1864 component = cl->component;
1866 switch (feature->ActionRequest)
1868 case INSTALLSTATE_ABSENT:
1869 component->anyAbsent = 1;
1871 case INSTALLSTATE_ADVERTISED:
1872 component->hasAdvertiseFeature = 1;
1874 case INSTALLSTATE_SOURCE:
1875 component->hasSourceFeature = 1;
1877 case INSTALLSTATE_LOCAL:
1878 component->hasLocalFeature = 1;
1880 case INSTALLSTATE_DEFAULT:
1881 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1882 component->hasAdvertiseFeature = 1;
1883 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1884 component->hasSourceFeature = 1;
1886 component->hasLocalFeature = 1;
1894 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1896 /* check if it's local or source */
1897 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1898 (component->hasLocalFeature || component->hasSourceFeature))
1900 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1901 !component->ForceLocalState)
1903 component->Action = INSTALLSTATE_SOURCE;
1904 component->ActionRequest = INSTALLSTATE_SOURCE;
1908 component->Action = INSTALLSTATE_LOCAL;
1909 component->ActionRequest = INSTALLSTATE_LOCAL;
1914 /* if any feature is local, the component must be local too */
1915 if (component->hasLocalFeature)
1917 component->Action = INSTALLSTATE_LOCAL;
1918 component->ActionRequest = INSTALLSTATE_LOCAL;
1921 if (component->hasSourceFeature)
1923 component->Action = INSTALLSTATE_SOURCE;
1924 component->ActionRequest = INSTALLSTATE_SOURCE;
1927 if (component->hasAdvertiseFeature)
1929 component->Action = INSTALLSTATE_ADVERTISED;
1930 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1933 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1934 if (component->anyAbsent &&
1935 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1937 component->Action = INSTALLSTATE_ABSENT;
1938 component->ActionRequest = INSTALLSTATE_ABSENT;
1942 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1944 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1946 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1947 component->Action = INSTALLSTATE_LOCAL;
1948 component->ActionRequest = INSTALLSTATE_LOCAL;
1951 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1952 component->Installed == INSTALLSTATE_SOURCE &&
1953 component->hasSourceFeature)
1955 component->Action = INSTALLSTATE_UNKNOWN;
1956 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1959 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1960 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1963 return ERROR_SUCCESS;
1966 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1968 MSIPACKAGE *package = param;
1970 MSIFEATURE *feature;
1972 name = MSI_RecordGetString( row, 1 );
1974 feature = msi_get_loaded_feature( package, name );
1976 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1980 Condition = MSI_RecordGetString(row,3);
1982 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1984 int level = MSI_RecordGetInteger(row,2);
1985 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1986 feature->Level = level;
1989 return ERROR_SUCCESS;
1992 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1994 static const WCHAR name[] = {'\\',0};
1995 VS_FIXEDFILEINFO *ptr, *ret;
1997 DWORD versize, handle;
2000 versize = GetFileVersionInfoSizeW( filename, &handle );
2004 version = msi_alloc( versize );
2008 GetFileVersionInfoW( filename, 0, versize, version );
2010 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2012 msi_free( version );
2016 ret = msi_alloc( sz );
2017 memcpy( ret, ptr, sz );
2019 msi_free( version );
2023 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2027 msi_parse_version_string( version, &ms, &ls );
2029 if (fi->dwFileVersionMS > ms) return 1;
2030 else if (fi->dwFileVersionMS < ms) return -1;
2031 else if (fi->dwFileVersionLS > ls) return 1;
2032 else if (fi->dwFileVersionLS < ls) return -1;
2036 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2040 msi_parse_version_string( ver1, &ms1, NULL );
2041 msi_parse_version_string( ver2, &ms2, NULL );
2043 if (ms1 > ms2) return 1;
2044 else if (ms1 < ms2) return -1;
2048 DWORD msi_get_disk_file_size( LPCWSTR filename )
2053 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2054 if (file == INVALID_HANDLE_VALUE)
2055 return INVALID_FILE_SIZE;
2057 size = GetFileSize( file, NULL );
2058 TRACE("size is %u\n", size);
2059 CloseHandle( file );
2063 BOOL msi_file_hash_matches( MSIFILE *file )
2066 MSIFILEHASHINFO hash;
2068 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2069 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2070 if (r != ERROR_SUCCESS)
2073 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2076 static WCHAR *get_temp_dir( void )
2079 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2081 GetTempPathW( MAX_PATH, tmp );
2084 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2085 if (CreateDirectoryW( dir, NULL )) break;
2087 return strdupW( dir );
2091 * msi_build_directory_name()
2093 * This function is to save messing round with directory names
2094 * It handles adding backslashes between path segments,
2095 * and can add \ at the end of the directory name if told to.
2097 * It takes a variable number of arguments.
2098 * It always allocates a new string for the result, so make sure
2099 * to free the return value when finished with it.
2101 * The first arg is the number of path segments that follow.
2102 * The arguments following count are a list of path segments.
2103 * A path segment may be NULL.
2105 * Path segments will be added with a \ separating them.
2106 * A \ will not be added after the last segment, however if the
2107 * last segment is NULL, then the last character will be a \
2109 WCHAR *msi_build_directory_name( DWORD count, ... )
2115 va_start( va, count );
2116 for (i = 0; i < count; i++)
2118 const WCHAR *str = va_arg( va, const WCHAR * );
2119 if (str) sz += strlenW( str ) + 1;
2123 dir = msi_alloc( sz * sizeof(WCHAR) );
2126 va_start( va, count );
2127 for (i = 0; i < count; i++)
2129 const WCHAR *str = va_arg( va, const WCHAR * );
2131 strcatW( dir, str );
2132 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2138 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2140 MSIASSEMBLY *assembly = file->Component->assembly;
2142 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2144 msi_free( file->TargetPath );
2145 if (assembly && !assembly->application)
2147 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2148 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2149 msi_track_tempfile( package, file->TargetPath );
2153 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2154 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2157 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2160 static UINT calculate_file_cost( MSIPACKAGE *package )
2162 VS_FIXEDFILEINFO *file_version;
2163 WCHAR *font_version;
2166 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2168 MSICOMPONENT *comp = file->Component;
2171 if (!comp->Enabled) continue;
2173 if (file->IsCompressed)
2174 comp->ForceLocalState = TRUE;
2176 set_target_path( package, file );
2178 if ((comp->assembly && !comp->assembly->installed) ||
2179 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2181 comp->Cost += file->FileSize;
2184 file_size = msi_get_disk_file_size( file->TargetPath );
2188 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2190 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2192 comp->Cost += file->FileSize - file_size;
2194 msi_free( file_version );
2197 else if ((font_version = font_version_from_file( file->TargetPath )))
2199 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2201 comp->Cost += file->FileSize - file_size;
2203 msi_free( font_version );
2207 if (file_size != file->FileSize)
2209 comp->Cost += file->FileSize - file_size;
2212 return ERROR_SUCCESS;
2215 void msi_clean_path( WCHAR *p )
2222 /* copy until the end of the string or a space */
2223 while (*p != ' ' && (*q = *p))
2226 /* reduce many backslashes to one */
2227 if (*p != '\\' || *q != '\\')
2231 /* quit at the end of the string */
2235 /* count the number of spaces */
2240 /* if it's leading or trailing space, skip it */
2241 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2243 else /* copy n spaces */
2244 while (n && (*q++ = *p++)) n--;
2248 static WCHAR *get_target_dir_property( MSIDATABASE *db )
2251 WCHAR *path, *target_dir = msi_dup_property( db, szTargetDir );
2253 if (!target_dir) return NULL;
2255 len = strlenW( target_dir );
2256 if (target_dir[len - 1] == '\\') return target_dir;
2257 if ((path = msi_alloc( (len + 2) * sizeof(WCHAR) )))
2259 strcpyW( path, target_dir );
2263 msi_free( target_dir );
2267 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2270 MSIFOLDER *folder, *parent, *child;
2273 TRACE("resolving %s\n", debugstr_w(name));
2275 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2277 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2279 if (!load_prop || !(path = get_target_dir_property( package->db )))
2281 path = msi_dup_property( package->db, szRootDrive );
2284 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2286 parent = msi_get_loaded_folder( package, folder->Parent );
2287 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2289 msi_clean_path( path );
2290 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2292 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2296 msi_set_property( package->db, folder->Directory, path );
2297 msi_free( folder->ResolvedTarget );
2298 folder->ResolvedTarget = path;
2300 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2303 msi_resolve_target_folder( package, child->Directory, load_prop );
2305 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2308 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2310 static const WCHAR condition_query[] =
2311 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','C','o','n','d','i','t','i','o','n','`',0};
2312 static const WCHAR szOutOfDiskSpace[] =
2313 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2315 UINT rc = ERROR_SUCCESS;
2319 TRACE("Building directory properties\n");
2320 msi_resolve_target_folder( package, szTargetDir, TRUE );
2322 TRACE("Evaluating component conditions\n");
2323 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2325 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2327 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2328 comp->Enabled = FALSE;
2331 comp->Enabled = TRUE;
2334 /* read components states from the registry */
2335 ACTION_GetComponentInstallStates(package);
2336 ACTION_GetFeatureInstallStates(package);
2338 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2340 TRACE("Evaluating feature conditions\n");
2342 rc = MSI_DatabaseOpenViewW( package->db, condition_query, &view );
2343 if (rc == ERROR_SUCCESS)
2345 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2346 msiobj_release( &view->hdr );
2350 TRACE("Calculating file cost\n");
2351 calculate_file_cost( package );
2353 msi_set_property( package->db, szCostingComplete, szOne );
2354 /* set default run level if not set */
2355 level = msi_dup_property( package->db, szInstallLevel );
2357 msi_set_property( package->db, szInstallLevel, szOne );
2360 /* FIXME: check volume disk space */
2361 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2363 return MSI_SetFeatureStates(package);
2366 /* OK this value is "interpreted" and then formatted based on the
2367 first few characters */
2368 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2373 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2379 LPWSTR deformated = NULL;
2382 deformat_string(package, &value[2], &deformated);
2384 /* binary value type */
2388 *size = (strlenW(ptr)/2)+1;
2390 *size = strlenW(ptr)/2;
2392 data = msi_alloc(*size);
2398 /* if uneven pad with a zero in front */
2404 data[count] = (BYTE)strtol(byte,NULL,0);
2406 TRACE("Uneven byte count\n");
2414 data[count] = (BYTE)strtol(byte,NULL,0);
2417 msi_free(deformated);
2419 TRACE("Data %i bytes(%i)\n",*size,count);
2426 deformat_string(package, &value[1], &deformated);
2429 *size = sizeof(DWORD);
2430 data = msi_alloc(*size);
2436 if ( (*p < '0') || (*p > '9') )
2442 if (deformated[0] == '-')
2445 TRACE("DWORD %i\n",*(LPDWORD)data);
2447 msi_free(deformated);
2452 static const WCHAR szMulti[] = {'[','~',']',0};
2461 *type=REG_EXPAND_SZ;
2469 if (strstrW(value, szMulti))
2470 *type = REG_MULTI_SZ;
2472 /* remove initial delimiter */
2473 if (!strncmpW(value, szMulti, 3))
2476 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2478 /* add double NULL terminator */
2479 if (*type == REG_MULTI_SZ)
2481 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2482 data = msi_realloc_zero(data, *size);
2488 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2495 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2497 *root_key = HKEY_LOCAL_MACHINE;
2502 *root_key = HKEY_CURRENT_USER;
2507 *root_key = HKEY_CLASSES_ROOT;
2511 *root_key = HKEY_CURRENT_USER;
2515 *root_key = HKEY_LOCAL_MACHINE;
2519 *root_key = HKEY_USERS;
2523 ERR("Unknown root %i\n", root);
2530 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2532 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2533 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2535 if (is_64bit && package->platform == PLATFORM_INTEL &&
2536 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2541 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2542 if (!(path_32node = msi_alloc( size ))) return NULL;
2544 memcpy( path_32node, path, len * sizeof(WCHAR) );
2545 strcpyW( path_32node + len, szWow6432Node );
2546 strcatW( path_32node, szBackSlash );
2547 strcatW( path_32node, path + len );
2551 return strdupW( path );
2554 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2556 MSIPACKAGE *package = param;
2557 LPSTR value_data = NULL;
2558 HKEY root_key, hkey;
2560 LPWSTR deformated, uikey, keypath;
2561 LPCWSTR szRoot, component, name, key, value;
2565 BOOL check_first = FALSE;
2568 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2570 component = MSI_RecordGetString(row, 6);
2571 comp = msi_get_loaded_component(package,component);
2573 return ERROR_SUCCESS;
2575 comp->Action = msi_get_component_action( package, comp );
2576 if (comp->Action != INSTALLSTATE_LOCAL)
2578 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2579 return ERROR_SUCCESS;
2582 name = MSI_RecordGetString(row, 4);
2583 if( MSI_RecordIsNull(row,5) && name )
2585 /* null values can have special meanings */
2586 if (name[0]=='-' && name[1] == 0)
2587 return ERROR_SUCCESS;
2588 else if ((name[0]=='+' && name[1] == 0) ||
2589 (name[0] == '*' && name[1] == 0))
2594 root = MSI_RecordGetInteger(row,2);
2595 key = MSI_RecordGetString(row, 3);
2597 szRoot = get_root_key( package, root, &root_key );
2599 return ERROR_SUCCESS;
2601 deformat_string(package, key , &deformated);
2602 size = strlenW(deformated) + strlenW(szRoot) + 1;
2603 uikey = msi_alloc(size*sizeof(WCHAR));
2604 strcpyW(uikey,szRoot);
2605 strcatW(uikey,deformated);
2607 keypath = get_keypath( package, root_key, deformated );
2608 msi_free( deformated );
2609 if (RegCreateKeyW( root_key, keypath, &hkey ))
2611 ERR("Could not create key %s\n", debugstr_w(keypath));
2614 return ERROR_SUCCESS;
2617 value = MSI_RecordGetString(row,5);
2619 value_data = parse_value(package, value, &type, &size);
2622 value_data = (LPSTR)strdupW(szEmpty);
2623 size = sizeof(szEmpty);
2627 deformat_string(package, name, &deformated);
2631 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2633 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2638 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2639 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2641 TRACE("value %s of %s checked already exists\n",
2642 debugstr_w(deformated), debugstr_w(uikey));
2646 TRACE("Checked and setting value %s of %s\n",
2647 debugstr_w(deformated), debugstr_w(uikey));
2648 if (deformated || size)
2649 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2654 uirow = MSI_CreateRecord(3);
2655 MSI_RecordSetStringW(uirow,2,deformated);
2656 MSI_RecordSetStringW(uirow,1,uikey);
2657 if (type == REG_SZ || type == REG_EXPAND_SZ)
2658 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2659 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2660 msiobj_release( &uirow->hdr );
2662 msi_free(value_data);
2663 msi_free(deformated);
2667 return ERROR_SUCCESS;
2670 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2674 static const WCHAR ExecSeqQuery[] =
2675 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2676 '`','R','e','g','i','s','t','r','y','`',0 };
2678 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2679 if (rc != ERROR_SUCCESS)
2680 return ERROR_SUCCESS;
2682 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2683 msiobj_release(&view->hdr);
2687 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2691 DWORD num_subkeys, num_values;
2695 if ((res = RegDeleteTreeW( hkey_root, key )))
2697 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2702 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2704 if ((res = RegDeleteValueW( hkey, value )))
2706 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2708 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2709 NULL, NULL, NULL, NULL );
2710 RegCloseKey( hkey );
2711 if (!res && !num_subkeys && !num_values)
2713 TRACE("Removing empty key %s\n", debugstr_w(key));
2714 RegDeleteKeyW( hkey_root, key );
2718 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2722 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2724 MSIPACKAGE *package = param;
2725 LPCWSTR component, name, key_str, root_key_str;
2726 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2729 BOOL delete_key = FALSE;
2734 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2736 component = MSI_RecordGetString( row, 6 );
2737 comp = msi_get_loaded_component( package, component );
2739 return ERROR_SUCCESS;
2741 comp->Action = msi_get_component_action( package, comp );
2742 if (comp->Action != INSTALLSTATE_ABSENT)
2744 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2745 return ERROR_SUCCESS;
2748 name = MSI_RecordGetString( row, 4 );
2749 if (MSI_RecordIsNull( row, 5 ) && name )
2751 if (name[0] == '+' && !name[1])
2752 return ERROR_SUCCESS;
2753 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2760 root = MSI_RecordGetInteger( row, 2 );
2761 key_str = MSI_RecordGetString( row, 3 );
2763 root_key_str = get_root_key( package, root, &hkey_root );
2765 return ERROR_SUCCESS;
2767 deformat_string( package, key_str, &deformated_key );
2768 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2769 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2770 strcpyW( ui_key_str, root_key_str );
2771 strcatW( ui_key_str, deformated_key );
2773 deformat_string( package, name, &deformated_name );
2775 keypath = get_keypath( package, hkey_root, deformated_key );
2776 msi_free( deformated_key );
2777 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2778 msi_free( keypath );
2780 uirow = MSI_CreateRecord( 2 );
2781 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2782 MSI_RecordSetStringW( uirow, 2, deformated_name );
2783 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2784 msiobj_release( &uirow->hdr );
2786 msi_free( ui_key_str );
2787 msi_free( deformated_name );
2788 return ERROR_SUCCESS;
2791 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2793 MSIPACKAGE *package = param;
2794 LPCWSTR component, name, key_str, root_key_str;
2795 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2798 BOOL delete_key = FALSE;
2803 component = MSI_RecordGetString( row, 5 );
2804 comp = msi_get_loaded_component( package, component );
2806 return ERROR_SUCCESS;
2808 comp->Action = msi_get_component_action( package, comp );
2809 if (comp->Action != INSTALLSTATE_LOCAL)
2811 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2812 return ERROR_SUCCESS;
2815 if ((name = MSI_RecordGetString( row, 4 )))
2817 if (name[0] == '-' && !name[1])
2824 root = MSI_RecordGetInteger( row, 2 );
2825 key_str = MSI_RecordGetString( row, 3 );
2827 root_key_str = get_root_key( package, root, &hkey_root );
2829 return ERROR_SUCCESS;
2831 deformat_string( package, key_str, &deformated_key );
2832 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2833 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2834 strcpyW( ui_key_str, root_key_str );
2835 strcatW( ui_key_str, deformated_key );
2837 deformat_string( package, name, &deformated_name );
2839 keypath = get_keypath( package, hkey_root, deformated_key );
2840 msi_free( deformated_key );
2841 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2842 msi_free( keypath );
2844 uirow = MSI_CreateRecord( 2 );
2845 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2846 MSI_RecordSetStringW( uirow, 2, deformated_name );
2847 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2848 msiobj_release( &uirow->hdr );
2850 msi_free( ui_key_str );
2851 msi_free( deformated_name );
2852 return ERROR_SUCCESS;
2855 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2859 static const WCHAR registry_query[] =
2860 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2861 '`','R','e','g','i','s','t','r','y','`',0 };
2862 static const WCHAR remove_registry_query[] =
2863 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2864 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2866 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2867 if (rc == ERROR_SUCCESS)
2869 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2870 msiobj_release( &view->hdr );
2871 if (rc != ERROR_SUCCESS)
2875 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2876 if (rc == ERROR_SUCCESS)
2878 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2879 msiobj_release( &view->hdr );
2880 if (rc != ERROR_SUCCESS)
2884 return ERROR_SUCCESS;
2887 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2889 package->script->CurrentlyScripting = TRUE;
2891 return ERROR_SUCCESS;
2895 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2898 DWORD total = 0, count = 0;
2899 static const WCHAR q1[]=
2900 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2901 '`','R','e','g','i','s','t','r','y','`',0};
2904 MSIFEATURE *feature;
2907 TRACE("InstallValidate\n");
2909 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2910 if (rc == ERROR_SUCCESS)
2912 MSI_IterateRecords( view, &count, NULL, package );
2913 msiobj_release( &view->hdr );
2914 total += count * REG_PROGRESS_VALUE;
2916 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2917 total += COMPONENT_PROGRESS_VALUE;
2919 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2920 total += file->FileSize;
2922 msi_ui_progress( package, 0, total, 0, 0 );
2924 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2926 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2927 debugstr_w(feature->Feature), feature->Installed,
2928 feature->ActionRequest, feature->Action);
2931 return ERROR_SUCCESS;
2934 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2936 MSIPACKAGE* package = param;
2937 LPCWSTR cond = NULL;
2938 LPCWSTR message = NULL;
2941 static const WCHAR title[]=
2942 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2944 cond = MSI_RecordGetString(row,1);
2946 r = MSI_EvaluateConditionW(package,cond);
2947 if (r == MSICONDITION_FALSE)
2949 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2952 message = MSI_RecordGetString(row,2);
2953 deformat_string(package,message,&deformated);
2954 MessageBoxW(NULL,deformated,title,MB_OK);
2955 msi_free(deformated);
2958 return ERROR_INSTALL_FAILURE;
2961 return ERROR_SUCCESS;
2964 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2967 MSIQUERY * view = NULL;
2968 static const WCHAR ExecSeqQuery[] =
2969 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2970 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2972 TRACE("Checking launch conditions\n");
2974 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2975 if (rc != ERROR_SUCCESS)
2976 return ERROR_SUCCESS;
2978 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2979 msiobj_release(&view->hdr);
2984 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2988 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2990 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2992 MSIRECORD * row = 0;
2994 LPWSTR deformated,buffer,deformated_name;
2996 static const WCHAR ExecSeqQuery[] =
2997 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2998 '`','R','e','g','i','s','t','r','y','`',' ',
2999 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3000 ' ','=',' ' ,'\'','%','s','\'',0 };
3001 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3002 static const WCHAR fmt2[]=
3003 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3005 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3009 root = MSI_RecordGetInteger(row,2);
3010 key = MSI_RecordGetString(row, 3);
3011 name = MSI_RecordGetString(row, 4);
3012 deformat_string(package, key , &deformated);
3013 deformat_string(package, name, &deformated_name);
3015 len = strlenW(deformated) + 6;
3016 if (deformated_name)
3017 len+=strlenW(deformated_name);
3019 buffer = msi_alloc( len *sizeof(WCHAR));
3021 if (deformated_name)
3022 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3024 sprintfW(buffer,fmt,root,deformated);
3026 msi_free(deformated);
3027 msi_free(deformated_name);
3028 msiobj_release(&row->hdr);
3032 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3034 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3039 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3042 return strdupW( file->TargetPath );
3047 static HKEY openSharedDLLsKey(void)
3050 static const WCHAR path[] =
3051 {'S','o','f','t','w','a','r','e','\\',
3052 'M','i','c','r','o','s','o','f','t','\\',
3053 'W','i','n','d','o','w','s','\\',
3054 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3055 'S','h','a','r','e','d','D','L','L','s',0};
3057 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3061 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3066 DWORD sz = sizeof(count);
3069 hkey = openSharedDLLsKey();
3070 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3071 if (rc != ERROR_SUCCESS)
3077 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3081 hkey = openSharedDLLsKey();
3083 msi_reg_set_val_dword( hkey, path, count );
3085 RegDeleteValueW(hkey,path);
3090 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3092 MSIFEATURE *feature;
3096 /* only refcount DLLs */
3097 if (comp->KeyPath == NULL ||
3099 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3100 comp->Attributes & msidbComponentAttributesODBCDataSource)
3104 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3105 write = (count > 0);
3107 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3111 /* increment counts */
3112 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3116 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3119 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3121 if ( cl->component == comp )
3126 /* decrement counts */
3127 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3131 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3134 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3136 if ( cl->component == comp )
3141 /* ref count all the files in the component */
3146 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3148 if (file->Component == comp)
3149 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3153 /* add a count for permanent */
3154 if (comp->Attributes & msidbComponentAttributesPermanent)
3157 comp->RefCount = count;
3160 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3163 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3167 const WCHAR prefixW[] = {'<','\\',0};
3168 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3169 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3173 strcpyW( keypath, prefixW );
3174 strcatW( keypath, comp->assembly->display_name );
3178 return resolve_keypath( package, comp );
3181 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3183 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3190 squash_guid(package->ProductCode,squished_pc);
3191 msi_set_sourcedir_props(package, FALSE);
3193 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3196 INSTALLSTATE action;
3198 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3199 if (!comp->ComponentId)
3202 squash_guid( comp->ComponentId, squished_cc );
3203 msi_free( comp->FullKeypath );
3204 comp->FullKeypath = build_full_keypath( package, comp );
3206 ACTION_RefCountComponent( package, comp );
3208 if (package->need_rollback) action = comp->Installed;
3209 else action = comp->ActionRequest;
3211 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3212 debugstr_w(comp->Component), debugstr_w(squished_cc),
3213 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3215 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3217 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3218 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3220 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3222 if (rc != ERROR_SUCCESS)
3225 if (comp->Attributes & msidbComponentAttributesPermanent)
3227 static const WCHAR szPermKey[] =
3228 { '0','0','0','0','0','0','0','0','0','0','0','0',
3229 '0','0','0','0','0','0','0','0','0','0','0','0',
3230 '0','0','0','0','0','0','0','0',0 };
3232 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3234 if (action == INSTALLSTATE_LOCAL)
3235 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3241 WCHAR source[MAX_PATH];
3242 WCHAR base[MAX_PATH];
3245 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3246 static const WCHAR query[] = {
3247 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3248 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3249 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3250 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3251 '`','D','i','s','k','I','d','`',0};
3253 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3256 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3257 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3258 ptr2 = strrchrW(source, '\\') + 1;
3259 msiobj_release(&row->hdr);
3261 lstrcpyW(base, package->PackagePath);
3262 ptr = strrchrW(base, '\\');
3265 sourcepath = msi_resolve_file_source(package, file);
3266 ptr = sourcepath + lstrlenW(base);
3267 lstrcpyW(ptr2, ptr);
3268 msi_free(sourcepath);
3270 msi_reg_set_val_str(hkey, squished_pc, source);
3274 else if (action == INSTALLSTATE_ABSENT)
3276 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3277 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3279 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3283 uirow = MSI_CreateRecord(3);
3284 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3285 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3286 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3287 msi_ui_actiondata( package, szProcessComponents, uirow );
3288 msiobj_release( &uirow->hdr );
3290 return ERROR_SUCCESS;
3301 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3302 LPWSTR lpszName, LONG_PTR lParam)
3305 typelib_struct *tl_struct = (typelib_struct*) lParam;
3306 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3310 if (!IS_INTRESOURCE(lpszName))
3312 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3316 sz = strlenW(tl_struct->source)+4;
3317 sz *= sizeof(WCHAR);
3319 if ((INT_PTR)lpszName == 1)
3320 tl_struct->path = strdupW(tl_struct->source);
3323 tl_struct->path = msi_alloc(sz);
3324 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3327 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3328 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3331 msi_free(tl_struct->path);
3332 tl_struct->path = NULL;
3337 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3338 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3340 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3344 msi_free(tl_struct->path);
3345 tl_struct->path = NULL;
3347 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3348 ITypeLib_Release(tl_struct->ptLib);
3353 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3355 MSIPACKAGE* package = param;
3359 typelib_struct tl_struct;
3364 component = MSI_RecordGetString(row,3);
3365 comp = msi_get_loaded_component(package,component);
3367 return ERROR_SUCCESS;
3369 comp->Action = msi_get_component_action( package, comp );
3370 if (comp->Action != INSTALLSTATE_LOCAL)
3372 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3373 return ERROR_SUCCESS;
3376 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3378 TRACE("component has no key path\n");
3379 return ERROR_SUCCESS;
3381 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3383 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3387 guid = MSI_RecordGetString(row,1);
3388 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3389 tl_struct.source = strdupW( file->TargetPath );
3390 tl_struct.path = NULL;
3392 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3393 (LONG_PTR)&tl_struct);
3397 LPCWSTR helpid, help_path = NULL;
3400 helpid = MSI_RecordGetString(row,6);
3402 if (helpid) help_path = msi_get_target_folder( package, helpid );
3403 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3406 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3408 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3410 ITypeLib_Release(tl_struct.ptLib);
3411 msi_free(tl_struct.path);
3413 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3415 FreeLibrary(module);
3416 msi_free(tl_struct.source);
3420 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3423 ERR("Failed to load type library: %08x\n", hr);
3424 return ERROR_INSTALL_FAILURE;
3427 ITypeLib_Release(tlib);
3430 return ERROR_SUCCESS;
3433 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3436 * OK this is a bit confusing.. I am given a _Component key and I believe
3437 * that the file that is being registered as a type library is the "key file
3438 * of that component" which I interpret to mean "The file in the KeyPath of
3443 static const WCHAR Query[] =
3444 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3445 '`','T','y','p','e','L','i','b','`',0};
3447 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3448 if (rc != ERROR_SUCCESS)
3449 return ERROR_SUCCESS;
3451 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3452 msiobj_release(&view->hdr);
3456 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3458 MSIPACKAGE *package = param;
3459 LPCWSTR component, guid;
3467 component = MSI_RecordGetString( row, 3 );
3468 comp = msi_get_loaded_component( package, component );
3470 return ERROR_SUCCESS;
3472 comp->Action = msi_get_component_action( package, comp );
3473 if (comp->Action != INSTALLSTATE_ABSENT)
3475 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3476 return ERROR_SUCCESS;
3478 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3480 guid = MSI_RecordGetString( row, 1 );
3481 CLSIDFromString( (LPCWSTR)guid, &libid );
3482 version = MSI_RecordGetInteger( row, 4 );
3483 language = MSI_RecordGetInteger( row, 2 );
3486 syskind = SYS_WIN64;
3488 syskind = SYS_WIN32;
3491 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3494 WARN("Failed to unregister typelib: %08x\n", hr);
3497 return ERROR_SUCCESS;
3500 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3504 static const WCHAR query[] =
3505 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3506 '`','T','y','p','e','L','i','b','`',0};
3508 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3509 if (rc != ERROR_SUCCESS)
3510 return ERROR_SUCCESS;
3512 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3513 msiobj_release( &view->hdr );
3517 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3519 static const WCHAR szlnk[] = {'.','l','n','k',0};
3520 LPCWSTR directory, extension, link_folder;
3521 LPWSTR link_file, filename;
3523 directory = MSI_RecordGetString( row, 2 );
3524 link_folder = msi_get_target_folder( package, directory );
3526 /* may be needed because of a bug somewhere else */
3527 msi_create_full_path( link_folder );
3529 filename = msi_dup_record_field( row, 3 );
3530 msi_reduce_to_long_filename( filename );
3532 extension = strchrW( filename, '.' );
3533 if (!extension || strcmpiW( extension, szlnk ))
3535 int len = strlenW( filename );
3536 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3537 memcpy( filename + len, szlnk, sizeof(szlnk) );
3539 link_file = msi_build_directory_name( 2, link_folder, filename );
3540 msi_free( filename );
3545 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3547 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3548 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3549 WCHAR *folder, *dest, *path;
3551 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3552 folder = msi_dup_property( package->db, szWindowsFolder );
3555 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3556 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3557 msi_free( appdata );
3559 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3560 msi_create_full_path( dest );
3561 path = msi_build_directory_name( 2, dest, icon_name );
3567 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3569 MSIPACKAGE *package = param;
3570 LPWSTR link_file, deformated, path;
3571 LPCWSTR component, target;
3573 IShellLinkW *sl = NULL;
3574 IPersistFile *pf = NULL;
3577 component = MSI_RecordGetString(row, 4);
3578 comp = msi_get_loaded_component(package, component);
3580 return ERROR_SUCCESS;
3582 comp->Action = msi_get_component_action( package, comp );
3583 if (comp->Action != INSTALLSTATE_LOCAL)
3585 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3586 return ERROR_SUCCESS;
3588 msi_ui_actiondata( package, szCreateShortcuts, row );
3590 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3591 &IID_IShellLinkW, (LPVOID *) &sl );
3595 ERR("CLSID_ShellLink not available\n");
3599 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3602 ERR("QueryInterface(IID_IPersistFile) failed\n");
3606 target = MSI_RecordGetString(row, 5);
3607 if (strchrW(target, '['))
3609 deformat_string(package, target, &deformated);
3610 IShellLinkW_SetPath(sl,deformated);
3611 msi_free(deformated);
3615 FIXME("poorly handled shortcut format, advertised shortcut\n");
3616 IShellLinkW_SetPath(sl,comp->FullKeypath);
3619 if (!MSI_RecordIsNull(row,6))
3621 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3622 deformat_string(package, arguments, &deformated);
3623 IShellLinkW_SetArguments(sl,deformated);
3624 msi_free(deformated);
3627 if (!MSI_RecordIsNull(row,7))
3629 LPCWSTR description = MSI_RecordGetString(row, 7);
3630 IShellLinkW_SetDescription(sl, description);
3633 if (!MSI_RecordIsNull(row,8))
3634 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3636 if (!MSI_RecordIsNull(row,9))
3639 LPCWSTR icon = MSI_RecordGetString(row, 9);
3641 path = msi_build_icon_path(package, icon);
3642 index = MSI_RecordGetInteger(row,10);
3644 /* no value means 0 */
3645 if (index == MSI_NULL_INTEGER)
3648 IShellLinkW_SetIconLocation(sl, path, index);
3652 if (!MSI_RecordIsNull(row,11))
3653 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3655 if (!MSI_RecordIsNull(row,12))
3657 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3658 full_path = msi_get_target_folder( package, wkdir );
3659 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3661 link_file = get_link_file(package, row);
3663 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3664 IPersistFile_Save(pf, link_file, FALSE);
3665 msi_free(link_file);
3669 IPersistFile_Release( pf );
3671 IShellLinkW_Release( sl );
3673 return ERROR_SUCCESS;
3676 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3681 static const WCHAR Query[] =
3682 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3683 '`','S','h','o','r','t','c','u','t','`',0};
3685 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3686 if (rc != ERROR_SUCCESS)
3687 return ERROR_SUCCESS;
3689 res = CoInitialize( NULL );
3691 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3692 msiobj_release(&view->hdr);
3700 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3702 MSIPACKAGE *package = param;
3707 component = MSI_RecordGetString( row, 4 );
3708 comp = msi_get_loaded_component( package, component );
3710 return ERROR_SUCCESS;
3712 comp->Action = msi_get_component_action( package, comp );
3713 if (comp->Action != INSTALLSTATE_ABSENT)
3715 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3716 return ERROR_SUCCESS;
3718 msi_ui_actiondata( package, szRemoveShortcuts, row );
3720 link_file = get_link_file( package, row );
3722 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3723 if (!DeleteFileW( link_file ))
3725 WARN("Failed to remove shortcut file %u\n", GetLastError());
3727 msi_free( link_file );
3729 return ERROR_SUCCESS;
3732 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3736 static const WCHAR query[] =
3737 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3738 '`','S','h','o','r','t','c','u','t','`',0};
3740 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3741 if (rc != ERROR_SUCCESS)
3742 return ERROR_SUCCESS;
3744 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3745 msiobj_release( &view->hdr );
3750 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3752 MSIPACKAGE* package = param;
3760 FileName = MSI_RecordGetString(row,1);
3763 ERR("Unable to get FileName\n");
3764 return ERROR_SUCCESS;
3767 FilePath = msi_build_icon_path(package, FileName);
3769 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3771 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3772 FILE_ATTRIBUTE_NORMAL, NULL);
3774 if (the_file == INVALID_HANDLE_VALUE)
3776 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3778 return ERROR_SUCCESS;
3785 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3786 if (rc != ERROR_SUCCESS)
3788 ERR("Failed to get stream\n");
3789 CloseHandle(the_file);
3790 DeleteFileW(FilePath);
3793 WriteFile(the_file,buffer,sz,&write,NULL);
3794 } while (sz == 1024);
3797 CloseHandle(the_file);
3799 return ERROR_SUCCESS;
3802 static UINT msi_publish_icons(MSIPACKAGE *package)
3807 static const WCHAR query[]= {
3808 'S','E','L','E','C','T',' ','*',' ',
3809 'F','R','O','M',' ','`','I','c','o','n','`',0};
3811 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3812 if (r == ERROR_SUCCESS)
3814 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3815 msiobj_release(&view->hdr);
3818 return ERROR_SUCCESS;
3821 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3827 MSISOURCELISTINFO *info;
3829 r = RegCreateKeyW(hkey, szSourceList, &source);
3830 if (r != ERROR_SUCCESS)
3833 RegCloseKey(source);
3835 buffer = strrchrW(package->PackagePath, '\\') + 1;
3836 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3837 package->Context, MSICODE_PRODUCT,
3838 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3839 if (r != ERROR_SUCCESS)
3842 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3843 package->Context, MSICODE_PRODUCT,
3844 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3845 if (r != ERROR_SUCCESS)
3848 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3849 package->Context, MSICODE_PRODUCT,
3850 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3851 if (r != ERROR_SUCCESS)
3854 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3856 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3857 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3858 info->options, info->value);
3860 MsiSourceListSetInfoW(package->ProductCode, NULL,
3861 info->context, info->options,
3862 info->property, info->value);
3865 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3867 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3868 disk->context, disk->options,
3869 disk->disk_id, disk->volume_label, disk->disk_prompt);
3872 return ERROR_SUCCESS;
3875 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3877 MSIHANDLE hdb, suminfo;
3878 WCHAR guids[MAX_PATH];
3879 WCHAR packcode[SQUISH_GUID_SIZE];
3886 static const WCHAR szARPProductIcon[] =
3887 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3888 static const WCHAR szAssignment[] =
3889 {'A','s','s','i','g','n','m','e','n','t',0};
3890 static const WCHAR szAdvertiseFlags[] =
3891 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3892 static const WCHAR szClients[] =
3893 {'C','l','i','e','n','t','s',0};
3894 static const WCHAR szColon[] = {':',0};
3896 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3897 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3900 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3901 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3904 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3906 buffer = msi_dup_property(package->db, szARPProductIcon);
3909 LPWSTR path = msi_build_icon_path(package, buffer);
3910 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3915 buffer = msi_dup_property(package->db, szProductVersion);
3918 DWORD verdword = msi_version_str_to_dword(buffer);
3919 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3923 msi_reg_set_val_dword(hkey, szAssignment, 0);
3924 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3925 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3926 msi_reg_set_val_str(hkey, szClients, szColon);
3928 hdb = alloc_msihandle(&package->db->hdr);
3930 return ERROR_NOT_ENOUGH_MEMORY;
3932 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3933 MsiCloseHandle(hdb);
3934 if (r != ERROR_SUCCESS)
3938 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3939 NULL, guids, &size);
3940 if (r != ERROR_SUCCESS)
3943 ptr = strchrW(guids, ';');
3945 squash_guid(guids, packcode);
3946 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3949 MsiCloseHandle(suminfo);
3950 return ERROR_SUCCESS;
3953 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3958 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3960 upgrade = msi_dup_property(package->db, szUpgradeCode);
3962 return ERROR_SUCCESS;
3964 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3965 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3967 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3969 if (r != ERROR_SUCCESS)
3971 WARN("failed to open upgrade code key\n");
3973 return ERROR_SUCCESS;
3975 squash_guid(package->ProductCode, squashed_pc);
3976 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3979 return ERROR_SUCCESS;
3982 static BOOL msi_check_publish(MSIPACKAGE *package)
3984 MSIFEATURE *feature;
3986 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3988 feature->Action = msi_get_feature_action( package, feature );
3989 if (feature->Action == INSTALLSTATE_LOCAL)
3996 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3998 MSIFEATURE *feature;
4000 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4002 feature->Action = msi_get_feature_action( package, feature );
4003 if (feature->Action != INSTALLSTATE_ABSENT)
4010 static UINT msi_publish_patches( MSIPACKAGE *package )
4012 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4013 WCHAR patch_squashed[GUID_SIZE];
4014 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4016 MSIPATCHINFO *patch;
4018 WCHAR *p, *all_patches = NULL;
4021 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4022 if (r != ERROR_SUCCESS)
4023 return ERROR_FUNCTION_FAILED;
4025 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4026 if (res != ERROR_SUCCESS)
4028 r = ERROR_FUNCTION_FAILED;
4032 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4033 if (r != ERROR_SUCCESS)
4036 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4038 squash_guid( patch->patchcode, patch_squashed );
4039 len += strlenW( patch_squashed ) + 1;
4042 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4046 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4050 squash_guid( patch->patchcode, p );
4051 p += strlenW( p ) + 1;
4053 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4054 (const BYTE *)patch->transforms,
4055 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4056 if (res != ERROR_SUCCESS)
4059 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4060 if (r != ERROR_SUCCESS)
4063 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4064 (const BYTE *)patch->localfile,
4065 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4066 RegCloseKey( patch_key );
4067 if (res != ERROR_SUCCESS)
4070 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4071 if (res != ERROR_SUCCESS)
4074 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4075 RegCloseKey( patch_key );
4076 if (res != ERROR_SUCCESS)
4080 all_patches[len] = 0;
4081 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4082 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4083 if (res != ERROR_SUCCESS)
4086 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4087 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4088 if (res != ERROR_SUCCESS)
4089 r = ERROR_FUNCTION_FAILED;
4092 RegCloseKey( product_patches_key );
4093 RegCloseKey( patches_key );
4094 RegCloseKey( product_key );
4095 msi_free( all_patches );
4099 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4102 HKEY hukey = NULL, hudkey = NULL;
4105 if (!list_empty(&package->patches))
4107 rc = msi_publish_patches(package);
4108 if (rc != ERROR_SUCCESS)
4112 /* FIXME: also need to publish if the product is in advertise mode */
4113 if (!msi_check_publish(package))
4114 return ERROR_SUCCESS;
4116 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4118 if (rc != ERROR_SUCCESS)
4121 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4122 NULL, &hudkey, TRUE);
4123 if (rc != ERROR_SUCCESS)
4126 rc = msi_publish_upgrade_code(package);
4127 if (rc != ERROR_SUCCESS)
4130 rc = msi_publish_product_properties(package, hukey);
4131 if (rc != ERROR_SUCCESS)
4134 rc = msi_publish_sourcelist(package, hukey);
4135 if (rc != ERROR_SUCCESS)
4138 rc = msi_publish_icons(package);
4141 uirow = MSI_CreateRecord( 1 );
4142 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4143 msi_ui_actiondata( package, szPublishProduct, uirow );
4144 msiobj_release( &uirow->hdr );
4147 RegCloseKey(hudkey);
4152 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4154 WCHAR *filename, *ptr, *folder, *ret;
4155 const WCHAR *dirprop;
4157 filename = msi_dup_record_field( row, 2 );
4158 if (filename && (ptr = strchrW( filename, '|' )))
4163 dirprop = MSI_RecordGetString( row, 3 );
4166 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4167 if (!folder) folder = msi_dup_property( package->db, dirprop );
4170 folder = msi_dup_property( package->db, szWindowsFolder );
4174 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4175 msi_free( filename );
4179 ret = msi_build_directory_name( 2, folder, ptr );
4181 msi_free( filename );
4186 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4188 MSIPACKAGE *package = param;
4189 LPCWSTR component, section, key, value, identifier;
4190 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4195 component = MSI_RecordGetString(row, 8);
4196 comp = msi_get_loaded_component(package,component);
4198 return ERROR_SUCCESS;
4200 comp->Action = msi_get_component_action( package, comp );
4201 if (comp->Action != INSTALLSTATE_LOCAL)
4203 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4204 return ERROR_SUCCESS;
4207 identifier = MSI_RecordGetString(row,1);
4208 section = MSI_RecordGetString(row,4);
4209 key = MSI_RecordGetString(row,5);
4210 value = MSI_RecordGetString(row,6);
4211 action = MSI_RecordGetInteger(row,7);
4213 deformat_string(package,section,&deformated_section);
4214 deformat_string(package,key,&deformated_key);
4215 deformat_string(package,value,&deformated_value);
4217 fullname = get_ini_file_name(package, row);
4221 TRACE("Adding value %s to section %s in %s\n",
4222 debugstr_w(deformated_key), debugstr_w(deformated_section),
4223 debugstr_w(fullname));
4224 WritePrivateProfileStringW(deformated_section, deformated_key,
4225 deformated_value, fullname);
4227 else if (action == 1)
4230 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4231 returned, 10, fullname);
4232 if (returned[0] == 0)
4234 TRACE("Adding value %s to section %s in %s\n",
4235 debugstr_w(deformated_key), debugstr_w(deformated_section),
4236 debugstr_w(fullname));
4238 WritePrivateProfileStringW(deformated_section, deformated_key,
4239 deformated_value, fullname);
4242 else if (action == 3)
4243 FIXME("Append to existing section not yet implemented\n");
4245 uirow = MSI_CreateRecord(4);
4246 MSI_RecordSetStringW(uirow,1,identifier);
4247 MSI_RecordSetStringW(uirow,2,deformated_section);
4248 MSI_RecordSetStringW(uirow,3,deformated_key);
4249 MSI_RecordSetStringW(uirow,4,deformated_value);
4250 msi_ui_actiondata( package, szWriteIniValues, uirow );
4251 msiobj_release( &uirow->hdr );
4254 msi_free(deformated_key);
4255 msi_free(deformated_value);
4256 msi_free(deformated_section);
4257 return ERROR_SUCCESS;
4260 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4264 static const WCHAR ExecSeqQuery[] =
4265 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4266 '`','I','n','i','F','i','l','e','`',0};
4268 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4269 if (rc != ERROR_SUCCESS)
4271 TRACE("no IniFile table\n");
4272 return ERROR_SUCCESS;
4275 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4276 msiobj_release(&view->hdr);
4280 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4282 MSIPACKAGE *package = param;
4283 LPCWSTR component, section, key, value, identifier;
4284 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4289 component = MSI_RecordGetString( row, 8 );
4290 comp = msi_get_loaded_component( package, component );
4292 return ERROR_SUCCESS;
4294 comp->Action = msi_get_component_action( package, comp );
4295 if (comp->Action != INSTALLSTATE_ABSENT)
4297 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4298 return ERROR_SUCCESS;
4301 identifier = MSI_RecordGetString( row, 1 );
4302 section = MSI_RecordGetString( row, 4 );
4303 key = MSI_RecordGetString( row, 5 );
4304 value = MSI_RecordGetString( row, 6 );
4305 action = MSI_RecordGetInteger( row, 7 );
4307 deformat_string( package, section, &deformated_section );
4308 deformat_string( package, key, &deformated_key );
4309 deformat_string( package, value, &deformated_value );
4311 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4313 filename = get_ini_file_name( package, row );
4315 TRACE("Removing key %s from section %s in %s\n",
4316 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4318 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4320 WARN("Unable to remove key %u\n", GetLastError());
4322 msi_free( filename );
4325 FIXME("Unsupported action %d\n", action);
4328 uirow = MSI_CreateRecord( 4 );
4329 MSI_RecordSetStringW( uirow, 1, identifier );
4330 MSI_RecordSetStringW( uirow, 2, deformated_section );
4331 MSI_RecordSetStringW( uirow, 3, deformated_key );
4332 MSI_RecordSetStringW( uirow, 4, deformated_value );
4333 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4334 msiobj_release( &uirow->hdr );
4336 msi_free( deformated_key );
4337 msi_free( deformated_value );
4338 msi_free( deformated_section );
4339 return ERROR_SUCCESS;
4342 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4344 MSIPACKAGE *package = param;
4345 LPCWSTR component, section, key, value, identifier;
4346 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4351 component = MSI_RecordGetString( row, 8 );
4352 comp = msi_get_loaded_component( package, component );
4354 return ERROR_SUCCESS;
4356 comp->Action = msi_get_component_action( package, comp );
4357 if (comp->Action != INSTALLSTATE_LOCAL)
4359 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4360 return ERROR_SUCCESS;
4363 identifier = MSI_RecordGetString( row, 1 );
4364 section = MSI_RecordGetString( row, 4 );
4365 key = MSI_RecordGetString( row, 5 );
4366 value = MSI_RecordGetString( row, 6 );
4367 action = MSI_RecordGetInteger( row, 7 );
4369 deformat_string( package, section, &deformated_section );
4370 deformat_string( package, key, &deformated_key );
4371 deformat_string( package, value, &deformated_value );
4373 if (action == msidbIniFileActionRemoveLine)
4375 filename = get_ini_file_name( package, row );
4377 TRACE("Removing key %s from section %s in %s\n",
4378 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4380 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4382 WARN("Unable to remove key %u\n", GetLastError());
4384 msi_free( filename );
4387 FIXME("Unsupported action %d\n", action);
4389 uirow = MSI_CreateRecord( 4 );
4390 MSI_RecordSetStringW( uirow, 1, identifier );
4391 MSI_RecordSetStringW( uirow, 2, deformated_section );
4392 MSI_RecordSetStringW( uirow, 3, deformated_key );
4393 MSI_RecordSetStringW( uirow, 4, deformated_value );
4394 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4395 msiobj_release( &uirow->hdr );
4397 msi_free( deformated_key );
4398 msi_free( deformated_value );
4399 msi_free( deformated_section );
4400 return ERROR_SUCCESS;
4403 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4407 static const WCHAR query[] =
4408 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4409 '`','I','n','i','F','i','l','e','`',0};
4410 static const WCHAR remove_query[] =
4411 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4412 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4414 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4415 if (rc == ERROR_SUCCESS)
4417 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4418 msiobj_release( &view->hdr );
4419 if (rc != ERROR_SUCCESS)
4423 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4424 if (rc == ERROR_SUCCESS)
4426 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4427 msiobj_release( &view->hdr );
4428 if (rc != ERROR_SUCCESS)
4432 return ERROR_SUCCESS;
4435 static void register_dll( const WCHAR *dll, BOOL unregister )
4439 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4442 HRESULT (WINAPI *func_ptr)( void );
4443 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4445 func_ptr = (void *)GetProcAddress( hmod, func );
4448 HRESULT hr = func_ptr();
4450 WARN("failed to register dll 0x%08x\n", hr);
4453 WARN("entry point %s not found\n", func);
4454 FreeLibrary( hmod );
4457 WARN("failed to load library %u\n", GetLastError());
4460 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4462 MSIPACKAGE *package = param;
4467 filename = MSI_RecordGetString(row,1);
4468 file = msi_get_loaded_file( package, filename );
4471 WARN("unable to find file %s\n", debugstr_w(filename));
4472 return ERROR_SUCCESS;
4474 file->Component->Action = msi_get_component_action( package, file->Component );
4475 if (file->Component->Action != INSTALLSTATE_LOCAL)
4477 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4478 return ERROR_SUCCESS;
4481 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4482 register_dll( file->TargetPath, FALSE );
4484 uirow = MSI_CreateRecord( 2 );
4485 MSI_RecordSetStringW( uirow, 1, filename );
4486 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4487 msi_ui_actiondata( package, szSelfRegModules, uirow );
4488 msiobj_release( &uirow->hdr );
4490 return ERROR_SUCCESS;
4493 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4497 static const WCHAR ExecSeqQuery[] =
4498 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4499 '`','S','e','l','f','R','e','g','`',0};
4501 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4502 if (rc != ERROR_SUCCESS)
4504 TRACE("no SelfReg table\n");
4505 return ERROR_SUCCESS;
4508 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4509 msiobj_release(&view->hdr);
4511 return ERROR_SUCCESS;
4514 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4516 MSIPACKAGE *package = param;
4521 filename = MSI_RecordGetString( row, 1 );
4522 file = msi_get_loaded_file( package, filename );
4525 WARN("unable to find file %s\n", debugstr_w(filename));
4526 return ERROR_SUCCESS;
4528 file->Component->Action = msi_get_component_action( package, file->Component );
4529 if (file->Component->Action != INSTALLSTATE_ABSENT)
4531 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4532 return ERROR_SUCCESS;
4535 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4536 register_dll( file->TargetPath, TRUE );
4538 uirow = MSI_CreateRecord( 2 );
4539 MSI_RecordSetStringW( uirow, 1, filename );
4540 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4541 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4542 msiobj_release( &uirow->hdr );
4544 return ERROR_SUCCESS;
4547 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4551 static const WCHAR query[] =
4552 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4553 '`','S','e','l','f','R','e','g','`',0};
4555 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4556 if (rc != ERROR_SUCCESS)
4558 TRACE("no SelfReg table\n");
4559 return ERROR_SUCCESS;
4562 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4563 msiobj_release( &view->hdr );
4565 return ERROR_SUCCESS;
4568 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4570 MSIFEATURE *feature;
4572 HKEY hkey = NULL, userdata = NULL;
4574 if (!msi_check_publish(package))
4575 return ERROR_SUCCESS;
4577 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4579 if (rc != ERROR_SUCCESS)
4582 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4584 if (rc != ERROR_SUCCESS)
4587 /* here the guids are base 85 encoded */
4588 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4594 BOOL absent = FALSE;
4597 if (feature->Action != INSTALLSTATE_LOCAL &&
4598 feature->Action != INSTALLSTATE_SOURCE &&
4599 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4602 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4606 if (feature->Feature_Parent)
4607 size += strlenW( feature->Feature_Parent )+2;
4609 data = msi_alloc(size * sizeof(WCHAR));
4612 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4614 MSICOMPONENT* component = cl->component;
4618 if (component->ComponentId)
4620 TRACE("From %s\n",debugstr_w(component->ComponentId));
4621 CLSIDFromString(component->ComponentId, &clsid);
4622 encode_base85_guid(&clsid,buf);
4623 TRACE("to %s\n",debugstr_w(buf));
4628 if (feature->Feature_Parent)
4630 static const WCHAR sep[] = {'\2',0};
4632 strcatW(data,feature->Feature_Parent);
4635 msi_reg_set_val_str( userdata, feature->Feature, data );
4639 if (feature->Feature_Parent)
4640 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4643 size += sizeof(WCHAR);
4644 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4645 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4649 size += 2*sizeof(WCHAR);
4650 data = msi_alloc(size);
4653 if (feature->Feature_Parent)
4654 strcpyW( &data[1], feature->Feature_Parent );
4655 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4661 uirow = MSI_CreateRecord( 1 );
4662 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4663 msi_ui_actiondata( package, szPublishFeatures, uirow );
4664 msiobj_release( &uirow->hdr );
4665 /* FIXME: call msi_ui_progress? */
4670 RegCloseKey(userdata);
4674 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4680 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4682 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4684 if (r == ERROR_SUCCESS)
4686 RegDeleteValueW(hkey, feature->Feature);
4690 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4692 if (r == ERROR_SUCCESS)
4694 RegDeleteValueW(hkey, feature->Feature);
4698 uirow = MSI_CreateRecord( 1 );
4699 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4700 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4701 msiobj_release( &uirow->hdr );
4703 return ERROR_SUCCESS;
4706 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4708 MSIFEATURE *feature;
4710 if (!msi_check_unpublish(package))
4711 return ERROR_SUCCESS;
4713 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4715 msi_unpublish_feature(package, feature);
4718 return ERROR_SUCCESS;
4721 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4725 WCHAR date[9], *val, *buffer;
4726 const WCHAR *prop, *key;
4728 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4729 static const WCHAR modpath_fmt[] =
4730 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4731 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4732 static const WCHAR szModifyPath[] =
4733 {'M','o','d','i','f','y','P','a','t','h',0};
4734 static const WCHAR szUninstallString[] =
4735 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4736 static const WCHAR szEstimatedSize[] =
4737 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4738 static const WCHAR szDisplayVersion[] =
4739 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4740 static const WCHAR szInstallSource[] =
4741 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4742 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4743 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4744 static const WCHAR szAuthorizedCDFPrefix[] =
4745 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4746 static const WCHAR szARPCONTACT[] =
4747 {'A','R','P','C','O','N','T','A','C','T',0};
4748 static const WCHAR szContact[] =
4749 {'C','o','n','t','a','c','t',0};
4750 static const WCHAR szARPCOMMENTS[] =
4751 {'A','R','P','C','O','M','M','E','N','T','S',0};
4752 static const WCHAR szComments[] =
4753 {'C','o','m','m','e','n','t','s',0};
4754 static const WCHAR szProductName[] =
4755 {'P','r','o','d','u','c','t','N','a','m','e',0};
4756 static const WCHAR szDisplayName[] =
4757 {'D','i','s','p','l','a','y','N','a','m','e',0};
4758 static const WCHAR szARPHELPLINK[] =
4759 {'A','R','P','H','E','L','P','L','I','N','K',0};
4760 static const WCHAR szHelpLink[] =
4761 {'H','e','l','p','L','i','n','k',0};
4762 static const WCHAR szARPHELPTELEPHONE[] =
4763 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4764 static const WCHAR szHelpTelephone[] =
4765 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4766 static const WCHAR szARPINSTALLLOCATION[] =
4767 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4768 static const WCHAR szInstallLocation[] =
4769 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4770 static const WCHAR szManufacturer[] =
4771 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4772 static const WCHAR szPublisher[] =
4773 {'P','u','b','l','i','s','h','e','r',0};
4774 static const WCHAR szARPREADME[] =
4775 {'A','R','P','R','E','A','D','M','E',0};
4776 static const WCHAR szReadme[] =
4777 {'R','e','a','d','M','e',0};
4778 static const WCHAR szARPSIZE[] =
4779 {'A','R','P','S','I','Z','E',0};
4780 static const WCHAR szSize[] =
4781 {'S','i','z','e',0};
4782 static const WCHAR szARPURLINFOABOUT[] =
4783 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4784 static const WCHAR szURLInfoAbout[] =
4785 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4786 static const WCHAR szARPURLUPDATEINFO[] =
4787 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4788 static const WCHAR szURLUpdateInfo[] =
4789 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4790 static const WCHAR szARPSYSTEMCOMPONENT[] =
4791 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4792 static const WCHAR szSystemComponent[] =
4793 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4795 static const WCHAR *propval[] = {
4796 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4797 szARPCONTACT, szContact,
4798 szARPCOMMENTS, szComments,
4799 szProductName, szDisplayName,
4800 szARPHELPLINK, szHelpLink,
4801 szARPHELPTELEPHONE, szHelpTelephone,
4802 szARPINSTALLLOCATION, szInstallLocation,
4803 szSourceDir, szInstallSource,
4804 szManufacturer, szPublisher,
4805 szARPREADME, szReadme,
4807 szARPURLINFOABOUT, szURLInfoAbout,
4808 szARPURLUPDATEINFO, szURLUpdateInfo,
4811 const WCHAR **p = propval;
4817 val = msi_dup_property(package->db, prop);
4818 msi_reg_set_val_str(hkey, key, val);
4822 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4823 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4825 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4827 size = deformat_string(package, modpath_fmt, &buffer);
4828 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4829 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4832 /* FIXME: Write real Estimated Size when we have it */
4833 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4835 GetLocalTime(&systime);
4836 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4837 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4839 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4840 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4842 buffer = msi_dup_property(package->db, szProductVersion);
4843 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4846 DWORD verdword = msi_version_str_to_dword(buffer);
4848 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4849 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4850 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4854 return ERROR_SUCCESS;
4857 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4859 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4861 LPWSTR upgrade_code;
4862 HKEY hkey, props, upgrade_key;
4865 /* FIXME: also need to publish if the product is in advertise mode */
4866 if (!msi_check_publish(package))
4867 return ERROR_SUCCESS;
4869 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4870 if (rc != ERROR_SUCCESS)
4873 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4874 NULL, &props, TRUE);
4875 if (rc != ERROR_SUCCESS)
4878 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4879 msi_free( package->db->localfile );
4880 package->db->localfile = NULL;
4882 rc = msi_publish_install_properties(package, hkey);
4883 if (rc != ERROR_SUCCESS)
4886 rc = msi_publish_install_properties(package, props);
4887 if (rc != ERROR_SUCCESS)
4890 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4893 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4894 if (rc == ERROR_SUCCESS)
4896 squash_guid( package->ProductCode, squashed_pc );
4897 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4898 RegCloseKey( upgrade_key );
4900 msi_free( upgrade_code );
4904 uirow = MSI_CreateRecord( 1 );
4905 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4906 msi_ui_actiondata( package, szRegisterProduct, uirow );
4907 msiobj_release( &uirow->hdr );
4910 return ERROR_SUCCESS;
4913 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4915 return execute_script(package,INSTALL_SCRIPT);
4918 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4920 WCHAR *upgrade, **features;
4921 BOOL full_uninstall = TRUE;
4922 MSIFEATURE *feature;
4923 MSIPATCHINFO *patch;
4925 static const WCHAR szUpgradeCode[] =
4926 {'U','p','g','r','a','d','e','C','o','d','e',0};
4928 features = msi_split_string(remove, ',');
4931 ERR("REMOVE feature list is empty!\n");
4932 return ERROR_FUNCTION_FAILED;
4935 if (!strcmpW( features[0], szAll ))
4936 full_uninstall = TRUE;
4939 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4941 if (feature->Action != INSTALLSTATE_ABSENT)
4942 full_uninstall = FALSE;
4947 if (!full_uninstall)
4948 return ERROR_SUCCESS;
4950 MSIREG_DeleteProductKey(package->ProductCode);
4951 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4952 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4954 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4955 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4956 MSIREG_DeleteUserProductKey(package->ProductCode);
4957 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4959 upgrade = msi_dup_property(package->db, szUpgradeCode);
4962 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4963 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4967 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4969 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4972 return ERROR_SUCCESS;
4975 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4980 /* turn off scheduling */
4981 package->script->CurrentlyScripting= FALSE;
4983 /* first do the same as an InstallExecute */
4984 rc = ACTION_InstallExecute(package);
4985 if (rc != ERROR_SUCCESS)
4988 /* then handle Commit Actions */
4989 rc = execute_script(package,COMMIT_SCRIPT);
4990 if (rc != ERROR_SUCCESS)
4993 remove = msi_dup_property(package->db, szRemove);
4995 rc = msi_unpublish_product(package, remove);
5001 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5003 static const WCHAR RunOnce[] = {
5004 'S','o','f','t','w','a','r','e','\\',
5005 'M','i','c','r','o','s','o','f','t','\\',
5006 'W','i','n','d','o','w','s','\\',
5007 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5008 'R','u','n','O','n','c','e',0};
5009 static const WCHAR InstallRunOnce[] = {
5010 'S','o','f','t','w','a','r','e','\\',
5011 'M','i','c','r','o','s','o','f','t','\\',
5012 'W','i','n','d','o','w','s','\\',
5013 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5014 'I','n','s','t','a','l','l','e','r','\\',
5015 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5017 static const WCHAR msiexec_fmt[] = {
5019 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5020 '\"','%','s','\"',0};
5021 static const WCHAR install_fmt[] = {
5022 '/','I',' ','\"','%','s','\"',' ',
5023 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5024 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5025 WCHAR buffer[256], sysdir[MAX_PATH];
5027 WCHAR squished_pc[100];
5029 squash_guid(package->ProductCode,squished_pc);
5031 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5032 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5033 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5036 msi_reg_set_val_str( hkey, squished_pc, buffer );
5039 TRACE("Reboot command %s\n",debugstr_w(buffer));
5041 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5042 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5044 msi_reg_set_val_str( hkey, squished_pc, buffer );
5047 return ERROR_INSTALL_SUSPEND;
5050 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5052 static const WCHAR query[] =
5053 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5054 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5055 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5056 MSIRECORD *rec, *row;
5062 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5064 rec = MSI_CreateRecord( count + 2 );
5065 str = MSI_RecordGetString( row, 1 );
5066 MSI_RecordSetStringW( rec, 0, str );
5067 msiobj_release( &row->hdr );
5068 MSI_RecordSetInteger( rec, 1, error );
5070 va_start( va, count );
5071 for (i = 0; i < count; i++)
5073 str = va_arg( va, const WCHAR *);
5074 MSI_RecordSetStringW( rec, i + 2, str );
5078 MSI_FormatRecordW( package, rec, NULL, &size );
5080 data = msi_alloc( size * sizeof(WCHAR) );
5081 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5083 msiobj_release( &rec->hdr );
5087 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5093 * We are currently doing what should be done here in the top level Install
5094 * however for Administrative and uninstalls this step will be needed
5096 if (!package->PackagePath)
5097 return ERROR_SUCCESS;
5099 msi_set_sourcedir_props(package, TRUE);
5101 attrib = GetFileAttributesW(package->db->path);
5102 if (attrib == INVALID_FILE_ATTRIBUTES)
5108 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5109 package->Context, MSICODE_PRODUCT,
5110 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5111 if (rc == ERROR_MORE_DATA)
5113 prompt = msi_alloc(size * sizeof(WCHAR));
5114 MsiSourceListGetInfoW(package->ProductCode, NULL,
5115 package->Context, MSICODE_PRODUCT,
5116 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5119 prompt = strdupW(package->db->path);
5121 msg = msi_build_error_string(package, 1302, 1, prompt);
5122 while(attrib == INVALID_FILE_ATTRIBUTES)
5124 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5127 rc = ERROR_INSTALL_USEREXIT;
5130 attrib = GetFileAttributesW(package->db->path);
5136 return ERROR_SUCCESS;
5141 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5144 LPWSTR buffer, productid = NULL;
5145 UINT i, rc = ERROR_SUCCESS;
5148 static const WCHAR szPropKeys[][80] =
5150 {'P','r','o','d','u','c','t','I','D',0},
5151 {'U','S','E','R','N','A','M','E',0},
5152 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5156 static const WCHAR szRegKeys[][80] =
5158 {'P','r','o','d','u','c','t','I','D',0},
5159 {'R','e','g','O','w','n','e','r',0},
5160 {'R','e','g','C','o','m','p','a','n','y',0},
5164 if (msi_check_unpublish(package))
5166 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5170 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5174 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5176 if (rc != ERROR_SUCCESS)
5179 for( i = 0; szPropKeys[i][0]; i++ )
5181 buffer = msi_dup_property( package->db, szPropKeys[i] );
5182 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5187 uirow = MSI_CreateRecord( 1 );
5188 MSI_RecordSetStringW( uirow, 1, productid );
5189 msi_ui_actiondata( package, szRegisterUser, uirow );
5190 msiobj_release( &uirow->hdr );
5192 msi_free(productid);
5198 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5202 package->script->InWhatSequence |= SEQUENCE_EXEC;
5203 rc = ACTION_ProcessExecSequence(package,FALSE);
5207 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5209 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5210 WCHAR productid_85[21], component_85[21], *ret;
5214 /* > is used if there is a component GUID and < if not. */
5216 productid_85[0] = 0;
5217 component_85[0] = 0;
5218 CLSIDFromString( package->ProductCode, &clsid );
5220 encode_base85_guid( &clsid, productid_85 );
5223 CLSIDFromString( component->ComponentId, &clsid );
5224 encode_base85_guid( &clsid, component_85 );
5227 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5228 debugstr_w(component_85));
5230 sz = 20 + strlenW( feature ) + 20 + 3;
5231 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5232 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5236 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5238 MSIPACKAGE *package = param;
5239 LPCWSTR compgroupid, component, feature, qualifier, text;
5240 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5249 feature = MSI_RecordGetString(rec, 5);
5250 feat = msi_get_loaded_feature(package, feature);
5252 return ERROR_SUCCESS;
5254 feat->Action = msi_get_feature_action( package, feat );
5255 if (feat->Action != INSTALLSTATE_LOCAL &&
5256 feat->Action != INSTALLSTATE_SOURCE &&
5257 feat->Action != INSTALLSTATE_ADVERTISED)
5259 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5260 return ERROR_SUCCESS;
5263 component = MSI_RecordGetString(rec, 3);
5264 comp = msi_get_loaded_component(package, component);
5266 return ERROR_SUCCESS;
5268 compgroupid = MSI_RecordGetString(rec,1);
5269 qualifier = MSI_RecordGetString(rec,2);
5271 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5272 if (rc != ERROR_SUCCESS)
5275 advertise = msi_create_component_advertise_string( package, comp, feature );
5276 text = MSI_RecordGetString( rec, 4 );
5279 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5280 strcpyW( p, advertise );
5282 msi_free( advertise );
5285 existing = msi_reg_get_val_str( hkey, qualifier );
5287 sz = strlenW( advertise ) + 1;
5290 for (p = existing; *p; p += len)
5292 len = strlenW( p ) + 1;
5293 if (strcmpW( advertise, p )) sz += len;
5296 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5298 rc = ERROR_OUTOFMEMORY;
5304 for (p = existing; *p; p += len)
5306 len = strlenW( p ) + 1;
5307 if (strcmpW( advertise, p ))
5309 memcpy( q, p, len * sizeof(WCHAR) );
5314 strcpyW( q, advertise );
5315 q[strlenW( q ) + 1] = 0;
5317 msi_reg_set_val_multi_str( hkey, qualifier, output );
5322 msi_free( advertise );
5323 msi_free( existing );
5326 uirow = MSI_CreateRecord( 2 );
5327 MSI_RecordSetStringW( uirow, 1, compgroupid );
5328 MSI_RecordSetStringW( uirow, 2, qualifier);
5329 msi_ui_actiondata( package, szPublishComponents, uirow );
5330 msiobj_release( &uirow->hdr );
5331 /* FIXME: call ui_progress? */
5337 * At present I am ignorning the advertised components part of this and only
5338 * focusing on the qualified component sets
5340 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5344 static const WCHAR ExecSeqQuery[] =
5345 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5346 '`','P','u','b','l','i','s','h',
5347 'C','o','m','p','o','n','e','n','t','`',0};
5349 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5350 if (rc != ERROR_SUCCESS)
5351 return ERROR_SUCCESS;
5353 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5354 msiobj_release(&view->hdr);
5359 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5361 static const WCHAR szInstallerComponents[] = {
5362 'S','o','f','t','w','a','r','e','\\',
5363 'M','i','c','r','o','s','o','f','t','\\',
5364 'I','n','s','t','a','l','l','e','r','\\',
5365 'C','o','m','p','o','n','e','n','t','s','\\',0};
5367 MSIPACKAGE *package = param;
5368 LPCWSTR compgroupid, component, feature, qualifier;
5372 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5375 feature = MSI_RecordGetString( rec, 5 );
5376 feat = msi_get_loaded_feature( package, feature );
5378 return ERROR_SUCCESS;
5380 feat->Action = msi_get_feature_action( package, feat );
5381 if (feat->Action != INSTALLSTATE_ABSENT)
5383 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5384 return ERROR_SUCCESS;
5387 component = MSI_RecordGetString( rec, 3 );
5388 comp = msi_get_loaded_component( package, component );
5390 return ERROR_SUCCESS;
5392 compgroupid = MSI_RecordGetString( rec, 1 );
5393 qualifier = MSI_RecordGetString( rec, 2 );
5395 squash_guid( compgroupid, squashed );
5396 strcpyW( keypath, szInstallerComponents );
5397 strcatW( keypath, squashed );
5399 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5400 if (res != ERROR_SUCCESS)
5402 WARN("Unable to delete component key %d\n", res);
5405 uirow = MSI_CreateRecord( 2 );
5406 MSI_RecordSetStringW( uirow, 1, compgroupid );
5407 MSI_RecordSetStringW( uirow, 2, qualifier );
5408 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5409 msiobj_release( &uirow->hdr );
5411 return ERROR_SUCCESS;
5414 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5418 static const WCHAR query[] =
5419 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5420 '`','P','u','b','l','i','s','h',
5421 'C','o','m','p','o','n','e','n','t','`',0};
5423 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5424 if (rc != ERROR_SUCCESS)
5425 return ERROR_SUCCESS;
5427 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5428 msiobj_release( &view->hdr );
5433 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5435 static const WCHAR query[] =
5436 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5437 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5438 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5439 MSIPACKAGE *package = param;
5440 MSICOMPONENT *component;
5443 SC_HANDLE hscm = NULL, service = NULL;
5445 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5446 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5447 DWORD serv_type, start_type, err_control;
5448 SERVICE_DESCRIPTIONW sd = {NULL};
5450 comp = MSI_RecordGetString( rec, 12 );
5451 component = msi_get_loaded_component( package, comp );
5454 WARN("service component not found\n");
5457 component->Action = msi_get_component_action( package, component );
5458 if (component->Action != INSTALLSTATE_LOCAL)
5460 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5463 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5466 ERR("Failed to open the SC Manager!\n");
5470 start_type = MSI_RecordGetInteger(rec, 5);
5471 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5474 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5475 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5476 serv_type = MSI_RecordGetInteger(rec, 4);
5477 err_control = MSI_RecordGetInteger(rec, 6);
5478 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5479 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5480 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5481 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5482 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5483 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5485 /* fetch the service path */
5486 row = MSI_QueryGetRecord(package->db, query, comp);
5489 ERR("Query failed\n");
5492 key = MSI_RecordGetString(row, 6);
5493 file = msi_get_loaded_file(package, key);
5494 msiobj_release(&row->hdr);
5497 ERR("Failed to load the service file\n");
5501 if (!args || !args[0]) image_path = file->TargetPath;
5504 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5505 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5506 return ERROR_OUTOFMEMORY;
5508 strcpyW(image_path, file->TargetPath);
5509 strcatW(image_path, szSpace);
5510 strcatW(image_path, args);
5512 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5513 start_type, err_control, image_path, load_order,
5514 NULL, depends, serv_name, pass);
5518 if (GetLastError() != ERROR_SERVICE_EXISTS)
5519 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5521 else if (sd.lpDescription)
5523 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5524 WARN("failed to set service description %u\n", GetLastError());
5527 if (image_path != file->TargetPath) msi_free(image_path);
5529 CloseServiceHandle(service);
5530 CloseServiceHandle(hscm);
5533 msi_free(sd.lpDescription);
5534 msi_free(load_order);
5535 msi_free(serv_name);
5540 return ERROR_SUCCESS;
5543 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5547 static const WCHAR ExecSeqQuery[] =
5548 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5549 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5551 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5552 if (rc != ERROR_SUCCESS)
5553 return ERROR_SUCCESS;
5555 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5556 msiobj_release(&view->hdr);
5561 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5562 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5564 LPCWSTR *vector, *temp_vector;
5568 static const WCHAR separator[] = {'[','~',']',0};
5571 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5576 vector = msi_alloc(sizeof(LPWSTR));
5584 vector[*numargs - 1] = p;
5586 if ((q = strstrW(p, separator)))
5590 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5596 vector = temp_vector;
5605 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5607 MSIPACKAGE *package = param;
5610 SC_HANDLE scm = NULL, service = NULL;
5611 LPCWSTR component, *vector = NULL;
5612 LPWSTR name, args, display_name = NULL;
5613 DWORD event, numargs, len;
5614 UINT r = ERROR_FUNCTION_FAILED;
5616 component = MSI_RecordGetString(rec, 6);
5617 comp = msi_get_loaded_component(package, component);
5619 return ERROR_SUCCESS;
5621 comp->Action = msi_get_component_action( package, comp );
5622 if (comp->Action != INSTALLSTATE_LOCAL)
5624 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5625 return ERROR_SUCCESS;
5628 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5629 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5630 event = MSI_RecordGetInteger(rec, 3);
5632 if (!(event & msidbServiceControlEventStart))
5638 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5641 ERR("Failed to open the service control manager\n");
5646 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5647 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5649 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5650 GetServiceDisplayNameW( scm, name, display_name, &len );
5653 service = OpenServiceW(scm, name, SERVICE_START);
5656 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5660 vector = msi_service_args_to_vector(args, &numargs);
5662 if (!StartServiceW(service, numargs, vector) &&
5663 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5665 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5672 uirow = MSI_CreateRecord( 2 );
5673 MSI_RecordSetStringW( uirow, 1, display_name );
5674 MSI_RecordSetStringW( uirow, 2, name );
5675 msi_ui_actiondata( package, szStartServices, uirow );
5676 msiobj_release( &uirow->hdr );
5678 CloseServiceHandle(service);
5679 CloseServiceHandle(scm);
5684 msi_free(display_name);
5688 static UINT ACTION_StartServices( MSIPACKAGE *package )
5693 static const WCHAR query[] = {
5694 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5695 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5697 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5698 if (rc != ERROR_SUCCESS)
5699 return ERROR_SUCCESS;
5701 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5702 msiobj_release(&view->hdr);
5707 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5709 DWORD i, needed, count;
5710 ENUM_SERVICE_STATUSW *dependencies;
5714 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5715 0, &needed, &count))
5718 if (GetLastError() != ERROR_MORE_DATA)
5721 dependencies = msi_alloc(needed);
5725 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5726 needed, &needed, &count))
5729 for (i = 0; i < count; i++)
5731 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5732 SERVICE_STOP | SERVICE_QUERY_STATUS);
5736 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5743 msi_free(dependencies);
5747 static UINT stop_service( LPCWSTR name )
5749 SC_HANDLE scm = NULL, service = NULL;
5750 SERVICE_STATUS status;
5751 SERVICE_STATUS_PROCESS ssp;
5754 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5757 WARN("Failed to open the SCM: %d\n", GetLastError());
5761 service = OpenServiceW(scm, name,
5763 SERVICE_QUERY_STATUS |
5764 SERVICE_ENUMERATE_DEPENDENTS);
5767 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5771 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5772 sizeof(SERVICE_STATUS_PROCESS), &needed))
5774 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5778 if (ssp.dwCurrentState == SERVICE_STOPPED)
5781 stop_service_dependents(scm, service);
5783 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5784 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5787 CloseServiceHandle(service);
5788 CloseServiceHandle(scm);
5790 return ERROR_SUCCESS;
5793 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5795 MSIPACKAGE *package = param;
5799 LPWSTR name = NULL, display_name = NULL;
5803 event = MSI_RecordGetInteger( rec, 3 );
5804 if (!(event & msidbServiceControlEventStop))
5805 return ERROR_SUCCESS;
5807 component = MSI_RecordGetString( rec, 6 );
5808 comp = msi_get_loaded_component( package, component );
5810 return ERROR_SUCCESS;
5812 comp->Action = msi_get_component_action( package, comp );
5813 if (comp->Action != INSTALLSTATE_ABSENT)
5815 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5816 return ERROR_SUCCESS;
5819 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5822 ERR("Failed to open the service control manager\n");
5827 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5828 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5830 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5831 GetServiceDisplayNameW( scm, name, display_name, &len );
5833 CloseServiceHandle( scm );
5835 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5836 stop_service( name );
5839 uirow = MSI_CreateRecord( 2 );
5840 MSI_RecordSetStringW( uirow, 1, display_name );
5841 MSI_RecordSetStringW( uirow, 2, name );
5842 msi_ui_actiondata( package, szStopServices, uirow );
5843 msiobj_release( &uirow->hdr );
5846 msi_free( display_name );
5847 return ERROR_SUCCESS;
5850 static UINT ACTION_StopServices( MSIPACKAGE *package )
5855 static const WCHAR query[] = {
5856 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5857 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5859 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5860 if (rc != ERROR_SUCCESS)
5861 return ERROR_SUCCESS;
5863 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5864 msiobj_release(&view->hdr);
5869 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5871 MSIPACKAGE *package = param;
5875 LPWSTR name = NULL, display_name = NULL;
5877 SC_HANDLE scm = NULL, service = NULL;
5879 event = MSI_RecordGetInteger( rec, 3 );
5880 if (!(event & msidbServiceControlEventDelete))
5881 return ERROR_SUCCESS;
5883 component = MSI_RecordGetString(rec, 6);
5884 comp = msi_get_loaded_component(package, component);
5886 return ERROR_SUCCESS;
5888 comp->Action = msi_get_component_action( package, comp );
5889 if (comp->Action != INSTALLSTATE_ABSENT)
5891 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5892 return ERROR_SUCCESS;
5895 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5896 stop_service( name );
5898 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5901 WARN("Failed to open the SCM: %d\n", GetLastError());
5906 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5907 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5909 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5910 GetServiceDisplayNameW( scm, name, display_name, &len );
5913 service = OpenServiceW( scm, name, DELETE );
5916 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5920 if (!DeleteService( service ))
5921 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5924 uirow = MSI_CreateRecord( 2 );
5925 MSI_RecordSetStringW( uirow, 1, display_name );
5926 MSI_RecordSetStringW( uirow, 2, name );
5927 msi_ui_actiondata( package, szDeleteServices, uirow );
5928 msiobj_release( &uirow->hdr );
5930 CloseServiceHandle( service );
5931 CloseServiceHandle( scm );
5933 msi_free( display_name );
5935 return ERROR_SUCCESS;
5938 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5943 static const WCHAR query[] = {
5944 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5945 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5947 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5948 if (rc != ERROR_SUCCESS)
5949 return ERROR_SUCCESS;
5951 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5952 msiobj_release( &view->hdr );
5957 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5959 MSIPACKAGE *package = param;
5960 LPWSTR driver, driver_path, ptr;
5961 WCHAR outpath[MAX_PATH];
5962 MSIFILE *driver_file = NULL, *setup_file = NULL;
5965 LPCWSTR desc, file_key, component;
5967 UINT r = ERROR_SUCCESS;
5969 static const WCHAR driver_fmt[] = {
5970 'D','r','i','v','e','r','=','%','s',0};
5971 static const WCHAR setup_fmt[] = {
5972 'S','e','t','u','p','=','%','s',0};
5973 static const WCHAR usage_fmt[] = {
5974 'F','i','l','e','U','s','a','g','e','=','1',0};
5976 component = MSI_RecordGetString( rec, 2 );
5977 comp = msi_get_loaded_component( package, component );
5979 return ERROR_SUCCESS;
5981 comp->Action = msi_get_component_action( package, comp );
5982 if (comp->Action != INSTALLSTATE_LOCAL)
5984 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5985 return ERROR_SUCCESS;
5987 desc = MSI_RecordGetString(rec, 3);
5989 file_key = MSI_RecordGetString( rec, 4 );
5990 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
5992 file_key = MSI_RecordGetString( rec, 5 );
5993 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
5997 ERR("ODBC Driver entry not found!\n");
5998 return ERROR_FUNCTION_FAILED;
6001 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6003 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6004 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6006 driver = msi_alloc(len * sizeof(WCHAR));
6008 return ERROR_OUTOFMEMORY;
6011 lstrcpyW(ptr, desc);
6012 ptr += lstrlenW(ptr) + 1;
6014 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6019 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6023 lstrcpyW(ptr, usage_fmt);
6024 ptr += lstrlenW(ptr) + 1;
6027 driver_path = strdupW(driver_file->TargetPath);
6028 ptr = strrchrW(driver_path, '\\');
6029 if (ptr) *ptr = '\0';
6031 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6032 NULL, ODBC_INSTALL_COMPLETE, &usage))
6034 ERR("Failed to install SQL driver!\n");
6035 r = ERROR_FUNCTION_FAILED;
6038 uirow = MSI_CreateRecord( 5 );
6039 MSI_RecordSetStringW( uirow, 1, desc );
6040 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6041 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6042 msi_ui_actiondata( package, szInstallODBC, uirow );
6043 msiobj_release( &uirow->hdr );
6046 msi_free(driver_path);
6051 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6053 MSIPACKAGE *package = param;
6054 LPWSTR translator, translator_path, ptr;
6055 WCHAR outpath[MAX_PATH];
6056 MSIFILE *translator_file = NULL, *setup_file = NULL;
6059 LPCWSTR desc, file_key, component;
6061 UINT r = ERROR_SUCCESS;
6063 static const WCHAR translator_fmt[] = {
6064 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6065 static const WCHAR setup_fmt[] = {
6066 'S','e','t','u','p','=','%','s',0};
6068 component = MSI_RecordGetString( rec, 2 );
6069 comp = msi_get_loaded_component( package, component );
6071 return ERROR_SUCCESS;
6073 comp->Action = msi_get_component_action( package, comp );
6074 if (comp->Action != INSTALLSTATE_LOCAL)
6076 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6077 return ERROR_SUCCESS;
6079 desc = MSI_RecordGetString(rec, 3);
6081 file_key = MSI_RecordGetString( rec, 4 );
6082 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6084 file_key = MSI_RecordGetString( rec, 5 );
6085 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6087 if (!translator_file)
6089 ERR("ODBC Translator entry not found!\n");
6090 return ERROR_FUNCTION_FAILED;
6093 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6095 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6097 translator = msi_alloc(len * sizeof(WCHAR));
6099 return ERROR_OUTOFMEMORY;
6102 lstrcpyW(ptr, desc);
6103 ptr += lstrlenW(ptr) + 1;
6105 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6110 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6115 translator_path = strdupW(translator_file->TargetPath);
6116 ptr = strrchrW(translator_path, '\\');
6117 if (ptr) *ptr = '\0';
6119 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6120 NULL, ODBC_INSTALL_COMPLETE, &usage))
6122 ERR("Failed to install SQL translator!\n");
6123 r = ERROR_FUNCTION_FAILED;
6126 uirow = MSI_CreateRecord( 5 );
6127 MSI_RecordSetStringW( uirow, 1, desc );
6128 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6129 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6130 msi_ui_actiondata( package, szInstallODBC, uirow );
6131 msiobj_release( &uirow->hdr );
6133 msi_free(translator);
6134 msi_free(translator_path);
6139 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6141 MSIPACKAGE *package = param;
6144 LPCWSTR desc, driver, component;
6145 WORD request = ODBC_ADD_SYS_DSN;
6148 UINT r = ERROR_SUCCESS;
6151 static const WCHAR attrs_fmt[] = {
6152 'D','S','N','=','%','s',0 };
6154 component = MSI_RecordGetString( rec, 2 );
6155 comp = msi_get_loaded_component( package, component );
6157 return ERROR_SUCCESS;
6159 comp->Action = msi_get_component_action( package, comp );
6160 if (comp->Action != INSTALLSTATE_LOCAL)
6162 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6163 return ERROR_SUCCESS;
6166 desc = MSI_RecordGetString(rec, 3);
6167 driver = MSI_RecordGetString(rec, 4);
6168 registration = MSI_RecordGetInteger(rec, 5);
6170 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6171 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6173 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6174 attrs = msi_alloc(len * sizeof(WCHAR));
6176 return ERROR_OUTOFMEMORY;
6178 len = sprintfW(attrs, attrs_fmt, desc);
6181 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6183 ERR("Failed to install SQL data source!\n");
6184 r = ERROR_FUNCTION_FAILED;
6187 uirow = MSI_CreateRecord( 5 );
6188 MSI_RecordSetStringW( uirow, 1, desc );
6189 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6190 MSI_RecordSetInteger( uirow, 3, request );
6191 msi_ui_actiondata( package, szInstallODBC, uirow );
6192 msiobj_release( &uirow->hdr );
6199 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6204 static const WCHAR driver_query[] = {
6205 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6206 'O','D','B','C','D','r','i','v','e','r',0 };
6208 static const WCHAR translator_query[] = {
6209 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6210 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6212 static const WCHAR source_query[] = {
6213 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6214 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6216 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6217 if (rc != ERROR_SUCCESS)
6218 return ERROR_SUCCESS;
6220 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6221 msiobj_release(&view->hdr);
6223 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6224 if (rc != ERROR_SUCCESS)
6225 return ERROR_SUCCESS;
6227 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6228 msiobj_release(&view->hdr);
6230 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6231 if (rc != ERROR_SUCCESS)
6232 return ERROR_SUCCESS;
6234 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6235 msiobj_release(&view->hdr);
6240 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6242 MSIPACKAGE *package = param;
6246 LPCWSTR desc, component;
6248 component = MSI_RecordGetString( rec, 2 );
6249 comp = msi_get_loaded_component( package, component );
6251 return ERROR_SUCCESS;
6253 comp->Action = msi_get_component_action( package, comp );
6254 if (comp->Action != INSTALLSTATE_ABSENT)
6256 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6257 return ERROR_SUCCESS;
6260 desc = MSI_RecordGetString( rec, 3 );
6261 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6263 WARN("Failed to remove ODBC driver\n");
6267 FIXME("Usage count reached 0\n");
6270 uirow = MSI_CreateRecord( 2 );
6271 MSI_RecordSetStringW( uirow, 1, desc );
6272 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6273 msi_ui_actiondata( package, szRemoveODBC, uirow );
6274 msiobj_release( &uirow->hdr );
6276 return ERROR_SUCCESS;
6279 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6281 MSIPACKAGE *package = param;
6285 LPCWSTR desc, component;
6287 component = MSI_RecordGetString( rec, 2 );
6288 comp = msi_get_loaded_component( package, component );
6290 return ERROR_SUCCESS;
6292 comp->Action = msi_get_component_action( package, comp );
6293 if (comp->Action != INSTALLSTATE_ABSENT)
6295 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6296 return ERROR_SUCCESS;
6299 desc = MSI_RecordGetString( rec, 3 );
6300 if (!SQLRemoveTranslatorW( desc, &usage ))
6302 WARN("Failed to remove ODBC translator\n");
6306 FIXME("Usage count reached 0\n");
6309 uirow = MSI_CreateRecord( 2 );
6310 MSI_RecordSetStringW( uirow, 1, desc );
6311 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6312 msi_ui_actiondata( package, szRemoveODBC, uirow );
6313 msiobj_release( &uirow->hdr );
6315 return ERROR_SUCCESS;
6318 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6320 MSIPACKAGE *package = param;
6324 LPCWSTR desc, driver, component;
6325 WORD request = ODBC_REMOVE_SYS_DSN;
6329 static const WCHAR attrs_fmt[] = {
6330 'D','S','N','=','%','s',0 };
6332 component = MSI_RecordGetString( rec, 2 );
6333 comp = msi_get_loaded_component( package, component );
6335 return ERROR_SUCCESS;
6337 comp->Action = msi_get_component_action( package, comp );
6338 if (comp->Action != INSTALLSTATE_ABSENT)
6340 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6341 return ERROR_SUCCESS;
6344 desc = MSI_RecordGetString( rec, 3 );
6345 driver = MSI_RecordGetString( rec, 4 );
6346 registration = MSI_RecordGetInteger( rec, 5 );
6348 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6349 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6351 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6352 attrs = msi_alloc( len * sizeof(WCHAR) );
6354 return ERROR_OUTOFMEMORY;
6356 FIXME("Use ODBCSourceAttribute table\n");
6358 len = sprintfW( attrs, attrs_fmt, desc );
6361 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6363 WARN("Failed to remove ODBC data source\n");
6367 uirow = MSI_CreateRecord( 3 );
6368 MSI_RecordSetStringW( uirow, 1, desc );
6369 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6370 MSI_RecordSetInteger( uirow, 3, request );
6371 msi_ui_actiondata( package, szRemoveODBC, uirow );
6372 msiobj_release( &uirow->hdr );
6374 return ERROR_SUCCESS;
6377 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6382 static const WCHAR driver_query[] = {
6383 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6384 'O','D','B','C','D','r','i','v','e','r',0 };
6386 static const WCHAR translator_query[] = {
6387 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6388 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6390 static const WCHAR source_query[] = {
6391 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6392 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6394 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6395 if (rc != ERROR_SUCCESS)
6396 return ERROR_SUCCESS;
6398 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6399 msiobj_release( &view->hdr );
6401 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6402 if (rc != ERROR_SUCCESS)
6403 return ERROR_SUCCESS;
6405 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6406 msiobj_release( &view->hdr );
6408 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6409 if (rc != ERROR_SUCCESS)
6410 return ERROR_SUCCESS;
6412 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6413 msiobj_release( &view->hdr );
6418 #define ENV_ACT_SETALWAYS 0x1
6419 #define ENV_ACT_SETABSENT 0x2
6420 #define ENV_ACT_REMOVE 0x4
6421 #define ENV_ACT_REMOVEMATCH 0x8
6423 #define ENV_MOD_MACHINE 0x20000000
6424 #define ENV_MOD_APPEND 0x40000000
6425 #define ENV_MOD_PREFIX 0x80000000
6426 #define ENV_MOD_MASK 0xC0000000
6428 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6430 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6432 LPCWSTR cptr = *name;
6434 static const WCHAR prefix[] = {'[','~',']',0};
6435 static const int prefix_len = 3;
6441 *flags |= ENV_ACT_SETALWAYS;
6442 else if (*cptr == '+')
6443 *flags |= ENV_ACT_SETABSENT;
6444 else if (*cptr == '-')
6445 *flags |= ENV_ACT_REMOVE;
6446 else if (*cptr == '!')
6447 *flags |= ENV_ACT_REMOVEMATCH;
6448 else if (*cptr == '*')
6449 *flags |= ENV_MOD_MACHINE;
6459 ERR("Missing environment variable\n");
6460 return ERROR_FUNCTION_FAILED;
6465 LPCWSTR ptr = *value;
6466 if (!strncmpW(ptr, prefix, prefix_len))
6468 if (ptr[prefix_len] == szSemiColon[0])
6470 *flags |= ENV_MOD_APPEND;
6471 *value += lstrlenW(prefix);
6478 else if (lstrlenW(*value) >= prefix_len)
6480 ptr += lstrlenW(ptr) - prefix_len;
6481 if (!strcmpW( ptr, prefix ))
6483 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6485 *flags |= ENV_MOD_PREFIX;
6486 /* the "[~]" will be removed by deformat_string */;
6496 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6497 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6498 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6499 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6501 ERR("Invalid flags: %08x\n", *flags);
6502 return ERROR_FUNCTION_FAILED;
6506 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6508 return ERROR_SUCCESS;
6511 static UINT open_env_key( DWORD flags, HKEY *key )
6513 static const WCHAR user_env[] =
6514 {'E','n','v','i','r','o','n','m','e','n','t',0};
6515 static const WCHAR machine_env[] =
6516 {'S','y','s','t','e','m','\\',
6517 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6518 'C','o','n','t','r','o','l','\\',
6519 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6520 'E','n','v','i','r','o','n','m','e','n','t',0};
6525 if (flags & ENV_MOD_MACHINE)
6528 root = HKEY_LOCAL_MACHINE;
6533 root = HKEY_CURRENT_USER;
6536 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6537 if (res != ERROR_SUCCESS)
6539 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6540 return ERROR_FUNCTION_FAILED;
6543 return ERROR_SUCCESS;
6546 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6548 MSIPACKAGE *package = param;
6549 LPCWSTR name, value, component;
6550 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6551 DWORD flags, type, size;
6558 component = MSI_RecordGetString(rec, 4);
6559 comp = msi_get_loaded_component(package, component);
6561 return ERROR_SUCCESS;
6563 comp->Action = msi_get_component_action( package, comp );
6564 if (comp->Action != INSTALLSTATE_LOCAL)
6566 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6567 return ERROR_SUCCESS;
6569 name = MSI_RecordGetString(rec, 2);
6570 value = MSI_RecordGetString(rec, 3);
6572 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6574 res = env_parse_flags(&name, &value, &flags);
6575 if (res != ERROR_SUCCESS || !value)
6578 if (value && !deformat_string(package, value, &deformatted))
6580 res = ERROR_OUTOFMEMORY;
6584 value = deformatted;
6586 res = open_env_key( flags, &env );
6587 if (res != ERROR_SUCCESS)
6590 if (flags & ENV_MOD_MACHINE)
6591 action |= 0x20000000;
6595 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6596 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6597 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6600 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6604 /* Nothing to do. */
6607 res = ERROR_SUCCESS;
6611 /* If we are appending but the string was empty, strip ; */
6612 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6614 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6615 newval = strdupW(value);
6618 res = ERROR_OUTOFMEMORY;
6626 /* Contrary to MSDN, +-variable to [~];path works */
6627 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6629 res = ERROR_SUCCESS;
6633 data = msi_alloc(size);
6637 return ERROR_OUTOFMEMORY;
6640 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6641 if (res != ERROR_SUCCESS)
6644 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6647 res = RegDeleteValueW(env, name);
6648 if (res != ERROR_SUCCESS)
6649 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6653 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6654 if (flags & ENV_MOD_MASK)
6658 if (flags & ENV_MOD_APPEND) multiplier++;
6659 if (flags & ENV_MOD_PREFIX) multiplier++;
6660 mod_size = lstrlenW(value) * multiplier;
6661 size += mod_size * sizeof(WCHAR);
6664 newval = msi_alloc(size);
6668 res = ERROR_OUTOFMEMORY;
6672 if (flags & ENV_MOD_PREFIX)
6674 lstrcpyW(newval, value);
6675 ptr = newval + lstrlenW(value);
6676 action |= 0x80000000;
6679 lstrcpyW(ptr, data);
6681 if (flags & ENV_MOD_APPEND)
6683 lstrcatW(newval, value);
6684 action |= 0x40000000;
6687 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6688 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6691 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6695 uirow = MSI_CreateRecord( 3 );
6696 MSI_RecordSetStringW( uirow, 1, name );
6697 MSI_RecordSetStringW( uirow, 2, newval );
6698 MSI_RecordSetInteger( uirow, 3, action );
6699 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6700 msiobj_release( &uirow->hdr );
6702 if (env) RegCloseKey(env);
6703 msi_free(deformatted);
6709 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6713 static const WCHAR ExecSeqQuery[] =
6714 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6715 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6716 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6717 if (rc != ERROR_SUCCESS)
6718 return ERROR_SUCCESS;
6720 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6721 msiobj_release(&view->hdr);
6726 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6728 MSIPACKAGE *package = param;
6729 LPCWSTR name, value, component;
6730 LPWSTR deformatted = NULL;
6739 component = MSI_RecordGetString( rec, 4 );
6740 comp = msi_get_loaded_component( package, component );
6742 return ERROR_SUCCESS;
6744 comp->Action = msi_get_component_action( package, comp );
6745 if (comp->Action != INSTALLSTATE_ABSENT)
6747 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6748 return ERROR_SUCCESS;
6750 name = MSI_RecordGetString( rec, 2 );
6751 value = MSI_RecordGetString( rec, 3 );
6753 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6755 r = env_parse_flags( &name, &value, &flags );
6756 if (r != ERROR_SUCCESS)
6759 if (!(flags & ENV_ACT_REMOVE))
6761 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6762 return ERROR_SUCCESS;
6765 if (value && !deformat_string( package, value, &deformatted ))
6766 return ERROR_OUTOFMEMORY;
6768 value = deformatted;
6770 r = open_env_key( flags, &env );
6771 if (r != ERROR_SUCCESS)
6777 if (flags & ENV_MOD_MACHINE)
6778 action |= 0x20000000;
6780 TRACE("Removing %s\n", debugstr_w(name));
6782 res = RegDeleteValueW( env, name );
6783 if (res != ERROR_SUCCESS)
6785 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6790 uirow = MSI_CreateRecord( 3 );
6791 MSI_RecordSetStringW( uirow, 1, name );
6792 MSI_RecordSetStringW( uirow, 2, value );
6793 MSI_RecordSetInteger( uirow, 3, action );
6794 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6795 msiobj_release( &uirow->hdr );
6797 if (env) RegCloseKey( env );
6798 msi_free( deformatted );
6802 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6806 static const WCHAR query[] =
6807 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6808 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6810 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6811 if (rc != ERROR_SUCCESS)
6812 return ERROR_SUCCESS;
6814 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6815 msiobj_release( &view->hdr );
6820 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6822 LPWSTR key, template, id;
6823 UINT r = ERROR_SUCCESS;
6825 id = msi_dup_property( package->db, szProductID );
6829 return ERROR_SUCCESS;
6831 template = msi_dup_property( package->db, szPIDTemplate );
6832 key = msi_dup_property( package->db, szPIDKEY );
6834 if (key && template)
6836 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6837 r = msi_set_property( package->db, szProductID, key );
6839 msi_free( template );
6844 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6847 package->need_reboot = 1;
6848 return ERROR_SUCCESS;
6851 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6853 static const WCHAR szAvailableFreeReg[] =
6854 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6856 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6858 TRACE("%p %d kilobytes\n", package, space);
6860 uirow = MSI_CreateRecord( 1 );
6861 MSI_RecordSetInteger( uirow, 1, space );
6862 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6863 msiobj_release( &uirow->hdr );
6865 return ERROR_SUCCESS;
6868 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6870 TRACE("%p\n", package);
6872 msi_set_property( package->db, szRollbackDisabled, szOne );
6873 return ERROR_SUCCESS;
6876 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6878 FIXME("%p\n", package);
6879 return ERROR_SUCCESS;
6882 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6887 static const WCHAR driver_query[] = {
6888 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6889 'O','D','B','C','D','r','i','v','e','r',0 };
6891 static const WCHAR translator_query[] = {
6892 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6893 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6895 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6896 if (r == ERROR_SUCCESS)
6899 r = MSI_IterateRecords( view, &count, NULL, package );
6900 msiobj_release( &view->hdr );
6901 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6904 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6905 if (r == ERROR_SUCCESS)
6908 r = MSI_IterateRecords( view, &count, NULL, package );
6909 msiobj_release( &view->hdr );
6910 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6913 return ERROR_SUCCESS;
6916 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6918 MSIPACKAGE *package = param;
6919 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6922 if ((value = msi_dup_property( package->db, property )))
6924 FIXME("remove %s\n", debugstr_w(value));
6927 return ERROR_SUCCESS;
6930 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6935 static const WCHAR query[] =
6936 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
6937 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
6939 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6940 if (r == ERROR_SUCCESS)
6942 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6943 msiobj_release( &view->hdr );
6945 return ERROR_SUCCESS;
6948 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6950 MSIPACKAGE *package = param;
6951 int attributes = MSI_RecordGetInteger( rec, 5 );
6953 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6955 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6956 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6957 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6958 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6962 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6964 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6965 if (r != ERROR_SUCCESS)
6966 return ERROR_SUCCESS;
6970 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6971 if (r != ERROR_SUCCESS)
6972 return ERROR_SUCCESS;
6974 RegCloseKey( hkey );
6976 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6977 debugstr_w(upgrade_code), debugstr_w(version_min),
6978 debugstr_w(version_max), debugstr_w(language));
6980 return ERROR_SUCCESS;
6983 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6987 static const WCHAR query[] =
6988 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
6990 if (msi_get_property_int( package->db, szInstalled, 0 ))
6992 TRACE("product is installed, skipping action\n");
6993 return ERROR_SUCCESS;
6995 if (msi_get_property_int( package->db, szPreselected, 0 ))
6997 TRACE("Preselected property is set, not migrating feature states\n");
6998 return ERROR_SUCCESS;
7001 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7002 if (r == ERROR_SUCCESS)
7004 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7005 msiobj_release( &view->hdr );
7007 return ERROR_SUCCESS;
7010 static void bind_image( const char *filename, const char *path )
7012 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7014 WARN("failed to bind image %u\n", GetLastError());
7018 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7022 MSIPACKAGE *package = param;
7023 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7024 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7025 char *filenameA, *pathA;
7026 WCHAR *pathW, **path_list;
7028 if (!(file = msi_get_loaded_file( package, key )))
7030 WARN("file %s not found\n", debugstr_w(key));
7031 return ERROR_SUCCESS;
7033 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7034 path_list = msi_split_string( paths, ';' );
7035 if (!path_list) bind_image( filenameA, NULL );
7038 for (i = 0; path_list[i] && path_list[i][0]; i++)
7040 deformat_string( package, path_list[i], &pathW );
7041 if ((pathA = strdupWtoA( pathW )))
7043 bind_image( filenameA, pathA );
7049 msi_free( path_list );
7050 msi_free( filenameA );
7051 return ERROR_SUCCESS;
7054 static UINT ACTION_BindImage( MSIPACKAGE *package )
7058 static const WCHAR query[] =
7059 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','B','i','n','d','I','m','a','g','e',0};
7061 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7062 if (r == ERROR_SUCCESS)
7064 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7065 msiobj_release( &view->hdr );
7067 return ERROR_SUCCESS;
7070 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7071 LPCSTR action, LPCWSTR table )
7073 static const WCHAR query[] = {
7074 'S','E','L','E','C','T',' ','*',' ',
7075 'F','R','O','M',' ','`','%','s','`',0 };
7076 MSIQUERY *view = NULL;
7080 r = MSI_OpenQuery( package->db, &view, query, table );
7081 if (r == ERROR_SUCCESS)
7083 r = MSI_IterateRecords(view, &count, NULL, package);
7084 msiobj_release(&view->hdr);
7088 FIXME("%s -> %u ignored %s table values\n",
7089 action, count, debugstr_w(table));
7091 return ERROR_SUCCESS;
7094 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7096 static const WCHAR table[] = {
7097 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7098 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7101 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7103 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7104 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7107 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7109 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7110 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7113 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7115 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7116 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7119 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7121 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7122 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7127 const WCHAR *action;
7128 UINT (*handler)(MSIPACKAGE *);
7129 const WCHAR *action_rollback;
7133 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7134 { szAppSearch, ACTION_AppSearch, NULL },
7135 { szBindImage, ACTION_BindImage, NULL },
7136 { szCCPSearch, ACTION_CCPSearch, NULL },
7137 { szCostFinalize, ACTION_CostFinalize, NULL },
7138 { szCostInitialize, ACTION_CostInitialize, NULL },
7139 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7140 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7141 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7142 { szDisableRollback, ACTION_DisableRollback, NULL },
7143 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7144 { szExecuteAction, ACTION_ExecuteAction, NULL },
7145 { szFileCost, ACTION_FileCost, NULL },
7146 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7147 { szForceReboot, ACTION_ForceReboot, NULL },
7148 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7149 { szInstallExecute, ACTION_InstallExecute, NULL },
7150 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7151 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7152 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7153 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7154 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7155 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7156 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7157 { szInstallValidate, ACTION_InstallValidate, NULL },
7158 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7159 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7160 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7161 { szMoveFiles, ACTION_MoveFiles, NULL },
7162 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7163 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7164 { szPatchFiles, ACTION_PatchFiles, NULL },
7165 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7166 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7167 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7168 { szPublishProduct, ACTION_PublishProduct, NULL },
7169 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7170 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7171 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7172 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7173 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7174 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7175 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7176 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7177 { szRegisterUser, ACTION_RegisterUser, NULL },
7178 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7179 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7180 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7181 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7182 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7183 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7184 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7185 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7186 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7187 { szResolveSource, ACTION_ResolveSource, NULL },
7188 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7189 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7190 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7191 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7192 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7193 { szStartServices, ACTION_StartServices, szStopServices },
7194 { szStopServices, ACTION_StopServices, szStartServices },
7195 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7196 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7197 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7198 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7199 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7200 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7201 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7202 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7203 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7204 { szValidateProductID, ACTION_ValidateProductID, NULL },
7205 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7206 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7207 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7208 { NULL, NULL, NULL }
7211 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7217 while (StandardActions[i].action != NULL)
7219 if (!strcmpW( StandardActions[i].action, action ))
7221 ui_actionstart( package, action );
7222 if (StandardActions[i].handler)
7224 ui_actioninfo( package, action, TRUE, 0 );
7225 *rc = StandardActions[i].handler( package );
7226 ui_actioninfo( package, action, FALSE, *rc );
7228 if (StandardActions[i].action_rollback && !package->need_rollback)
7230 TRACE("scheduling rollback action\n");
7231 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7236 FIXME("unhandled standard action %s\n", debugstr_w(action));
7237 *rc = ERROR_SUCCESS;
7247 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7249 UINT rc = ERROR_SUCCESS;
7252 TRACE("Performing action (%s)\n", debugstr_w(action));
7254 handled = ACTION_HandleStandardAction(package, action, &rc);
7257 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7261 WARN("unhandled msi action %s\n", debugstr_w(action));
7262 rc = ERROR_FUNCTION_NOT_CALLED;
7268 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7270 UINT rc = ERROR_SUCCESS;
7271 BOOL handled = FALSE;
7273 TRACE("Performing action (%s)\n", debugstr_w(action));
7275 handled = ACTION_HandleStandardAction(package, action, &rc);
7278 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7280 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7285 WARN("unhandled msi action %s\n", debugstr_w(action));
7286 rc = ERROR_FUNCTION_NOT_CALLED;
7292 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7294 UINT rc = ERROR_SUCCESS;
7297 static const WCHAR ExecSeqQuery[] =
7298 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7299 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7300 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7301 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7302 static const WCHAR UISeqQuery[] =
7303 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7304 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7305 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7306 ' ', '=',' ','%','i',0};
7308 if (needs_ui_sequence(package))
7309 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7311 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7315 LPCWSTR action, cond;
7317 TRACE("Running the actions\n");
7319 /* check conditions */
7320 cond = MSI_RecordGetString(row, 2);
7322 /* this is a hack to skip errors in the condition code */
7323 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7325 msiobj_release(&row->hdr);
7326 return ERROR_SUCCESS;
7329 action = MSI_RecordGetString(row, 1);
7332 ERR("failed to fetch action\n");
7333 msiobj_release(&row->hdr);
7334 return ERROR_FUNCTION_FAILED;
7337 if (needs_ui_sequence(package))
7338 rc = ACTION_PerformUIAction(package, action, -1);
7340 rc = ACTION_PerformAction(package, action, -1);
7342 msiobj_release(&row->hdr);
7348 /****************************************************
7349 * TOP level entry points
7350 *****************************************************/
7352 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7353 LPCWSTR szCommandLine )
7357 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7358 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7359 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7361 msi_set_property( package->db, szAction, szInstall );
7363 package->script->InWhatSequence = SEQUENCE_INSTALL;
7370 dir = strdupW(szPackagePath);
7371 p = strrchrW(dir, '\\');
7375 file = szPackagePath + (p - dir);
7380 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7381 GetCurrentDirectoryW(MAX_PATH, dir);
7382 lstrcatW(dir, szBackSlash);
7383 file = szPackagePath;
7386 msi_free( package->PackagePath );
7387 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7388 if (!package->PackagePath)
7391 return ERROR_OUTOFMEMORY;
7394 lstrcpyW(package->PackagePath, dir);
7395 lstrcatW(package->PackagePath, file);
7398 msi_set_sourcedir_props(package, FALSE);
7401 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7402 if (rc != ERROR_SUCCESS)
7405 msi_apply_transforms( package );
7406 msi_apply_patches( package );
7408 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7410 TRACE("setting reinstall property\n");
7411 msi_set_property( package->db, szReinstall, szAll );
7414 /* properties may have been added by a transform */
7415 msi_clone_properties( package );
7417 msi_parse_command_line( package, szCommandLine, FALSE );
7418 msi_adjust_privilege_properties( package );
7419 msi_set_context( package );
7421 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7423 TRACE("disabling rollback\n");
7424 msi_set_property( package->db, szRollbackDisabled, szOne );
7427 if (needs_ui_sequence( package))
7429 package->script->InWhatSequence |= SEQUENCE_UI;
7430 rc = ACTION_ProcessUISequence(package);
7431 ui_exists = ui_sequence_exists(package);
7432 if (rc == ERROR_SUCCESS || !ui_exists)
7434 package->script->InWhatSequence |= SEQUENCE_EXEC;
7435 rc = ACTION_ProcessExecSequence(package, ui_exists);
7439 rc = ACTION_ProcessExecSequence(package, FALSE);
7441 package->script->CurrentlyScripting = FALSE;
7443 /* process the ending type action */
7444 if (rc == ERROR_SUCCESS)
7445 ACTION_PerformActionSequence(package, -1);
7446 else if (rc == ERROR_INSTALL_USEREXIT)
7447 ACTION_PerformActionSequence(package, -2);
7448 else if (rc == ERROR_INSTALL_SUSPEND)
7449 ACTION_PerformActionSequence(package, -4);
7452 ACTION_PerformActionSequence(package, -3);
7453 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7455 package->need_rollback = TRUE;
7459 /* finish up running custom actions */
7460 ACTION_FinishCustomActions(package);
7462 if (package->need_rollback)
7464 WARN("installation failed, running rollback script\n");
7465 execute_script( package, ROLLBACK_SCRIPT );
7468 if (rc == ERROR_SUCCESS && package->need_reboot)
7469 return ERROR_SUCCESS_REBOOT_REQUIRED;