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 static UINT 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 MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1086 MSIFEATURE *feature;
1091 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1093 if ( !strcmpW( feature->Feature, name ) )
1100 static UINT load_feature(MSIRECORD * row, LPVOID param)
1102 MSIPACKAGE* package = param;
1103 MSIFEATURE* feature;
1104 static const WCHAR Query1[] =
1105 {'S','E','L','E','C','T',' ',
1106 '`','C','o','m','p','o','n','e','n','t','_','`',
1107 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1108 'C','o','m','p','o','n','e','n','t','s','`',' ',
1109 'W','H','E','R','E',' ',
1110 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1115 /* fill in the data */
1117 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1119 return ERROR_NOT_ENOUGH_MEMORY;
1121 list_init( &feature->Children );
1122 list_init( &feature->Components );
1124 feature->Feature = msi_dup_record_field( row, 1 );
1126 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1128 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1129 feature->Title = msi_dup_record_field( row, 3 );
1130 feature->Description = msi_dup_record_field( row, 4 );
1132 if (!MSI_RecordIsNull(row,5))
1133 feature->Display = MSI_RecordGetInteger(row,5);
1135 feature->Level= MSI_RecordGetInteger(row,6);
1136 feature->Directory = msi_dup_record_field( row, 7 );
1137 feature->Attributes = MSI_RecordGetInteger(row,8);
1139 feature->Installed = INSTALLSTATE_UNKNOWN;
1140 feature->Action = INSTALLSTATE_UNKNOWN;
1141 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1143 list_add_tail( &package->features, &feature->entry );
1145 /* load feature components */
1147 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1148 if (rc != ERROR_SUCCESS)
1149 return ERROR_SUCCESS;
1151 ilfs.package = package;
1152 ilfs.feature = feature;
1154 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1155 msiobj_release(&view->hdr);
1157 return ERROR_SUCCESS;
1160 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1162 MSIPACKAGE* package = param;
1163 MSIFEATURE *parent, *child;
1165 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1167 return ERROR_FUNCTION_FAILED;
1169 if (!child->Feature_Parent)
1170 return ERROR_SUCCESS;
1172 parent = find_feature_by_name( package, child->Feature_Parent );
1174 return ERROR_FUNCTION_FAILED;
1176 add_feature_child( parent, child );
1177 return ERROR_SUCCESS;
1180 static UINT load_all_features( MSIPACKAGE *package )
1182 static const WCHAR query[] = {
1183 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1184 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1185 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1189 if (!list_empty(&package->features))
1190 return ERROR_SUCCESS;
1192 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1193 if (r != ERROR_SUCCESS)
1196 r = MSI_IterateRecords( view, NULL, load_feature, package );
1197 if (r != ERROR_SUCCESS)
1200 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1201 msiobj_release( &view->hdr );
1206 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1217 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1219 static const WCHAR query[] = {
1220 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1221 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1222 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1223 MSIQUERY *view = NULL;
1224 MSIRECORD *row = NULL;
1227 TRACE("%s\n", debugstr_w(file->File));
1229 r = MSI_OpenQuery(package->db, &view, query, file->File);
1230 if (r != ERROR_SUCCESS)
1233 r = MSI_ViewExecute(view, NULL);
1234 if (r != ERROR_SUCCESS)
1237 r = MSI_ViewFetch(view, &row);
1238 if (r != ERROR_SUCCESS)
1241 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1242 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1243 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1244 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1245 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1248 if (view) msiobj_release(&view->hdr);
1249 if (row) msiobj_release(&row->hdr);
1253 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1256 static const WCHAR query[] = {
1257 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1258 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1259 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1261 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1264 WARN("query failed\n");
1265 return ERROR_FUNCTION_FAILED;
1268 file->disk_id = MSI_RecordGetInteger( row, 1 );
1269 msiobj_release( &row->hdr );
1270 return ERROR_SUCCESS;
1273 static UINT load_file(MSIRECORD *row, LPVOID param)
1275 MSIPACKAGE* package = param;
1279 /* fill in the data */
1281 file = msi_alloc_zero( sizeof (MSIFILE) );
1283 return ERROR_NOT_ENOUGH_MEMORY;
1285 file->File = msi_dup_record_field( row, 1 );
1287 component = MSI_RecordGetString( row, 2 );
1288 file->Component = msi_get_loaded_component( package, component );
1290 if (!file->Component)
1292 WARN("Component not found: %s\n", debugstr_w(component));
1293 msi_free(file->File);
1295 return ERROR_SUCCESS;
1298 file->FileName = msi_dup_record_field( row, 3 );
1299 msi_reduce_to_long_filename( file->FileName );
1301 file->ShortName = msi_dup_record_field( row, 3 );
1302 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1304 file->FileSize = MSI_RecordGetInteger( row, 4 );
1305 file->Version = msi_dup_record_field( row, 5 );
1306 file->Language = msi_dup_record_field( row, 6 );
1307 file->Attributes = MSI_RecordGetInteger( row, 7 );
1308 file->Sequence = MSI_RecordGetInteger( row, 8 );
1310 file->state = msifs_invalid;
1312 /* if the compressed bits are not set in the file attributes,
1313 * then read the information from the package word count property
1315 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1317 file->IsCompressed = FALSE;
1319 else if (file->Attributes &
1320 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1322 file->IsCompressed = TRUE;
1324 else if (file->Attributes & msidbFileAttributesNoncompressed)
1326 file->IsCompressed = FALSE;
1330 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1333 load_file_hash(package, file);
1334 load_file_disk_id(package, file);
1336 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1338 list_add_tail( &package->files, &file->entry );
1340 return ERROR_SUCCESS;
1343 static UINT load_all_files(MSIPACKAGE *package)
1347 static const WCHAR Query[] =
1348 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1349 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1350 '`','S','e','q','u','e','n','c','e','`', 0};
1352 if (!list_empty(&package->files))
1353 return ERROR_SUCCESS;
1355 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1356 if (rc != ERROR_SUCCESS)
1357 return ERROR_SUCCESS;
1359 rc = MSI_IterateRecords(view, NULL, load_file, package);
1360 msiobj_release(&view->hdr);
1362 return ERROR_SUCCESS;
1365 static UINT load_media( MSIRECORD *row, LPVOID param )
1367 MSIPACKAGE *package = param;
1368 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1369 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1371 /* FIXME: load external cabinets and directory sources too */
1372 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1373 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1374 return ERROR_SUCCESS;
1377 static UINT load_all_media( MSIPACKAGE *package )
1379 static const WCHAR query[] =
1380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
1381 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
1385 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1386 if (r != ERROR_SUCCESS) return ERROR_SUCCESS;
1388 MSI_IterateRecords( view, NULL, load_media, package );
1389 msiobj_release( &view->hdr );
1390 return ERROR_SUCCESS;
1393 static UINT load_patch(MSIRECORD *row, LPVOID param)
1395 MSIPACKAGE *package = param;
1396 MSIFILEPATCH *patch;
1399 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1401 return ERROR_NOT_ENOUGH_MEMORY;
1403 file_key = msi_dup_record_field( row, 1 );
1404 patch->File = msi_get_loaded_file( package, file_key );
1409 ERR("Failed to find target for patch in File table\n");
1411 return ERROR_FUNCTION_FAILED;
1414 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1416 /* FIXME: The database should be properly transformed */
1417 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1419 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1420 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1421 patch->IsApplied = FALSE;
1424 * Header field - for patch validation.
1425 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1428 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1430 list_add_tail( &package->filepatches, &patch->entry );
1432 return ERROR_SUCCESS;
1435 static UINT load_all_patches(MSIPACKAGE *package)
1439 static const WCHAR Query[] =
1440 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1441 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1442 '`','S','e','q','u','e','n','c','e','`',0};
1444 if (!list_empty(&package->filepatches))
1445 return ERROR_SUCCESS;
1447 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1448 if (rc != ERROR_SUCCESS)
1449 return ERROR_SUCCESS;
1451 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1452 msiobj_release(&view->hdr);
1454 return ERROR_SUCCESS;
1457 static UINT load_folder( MSIRECORD *row, LPVOID param )
1459 MSIPACKAGE *package = param;
1460 static WCHAR szEmpty[] = { 0 };
1461 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1464 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1465 list_init( &folder->children );
1466 folder->Directory = msi_dup_record_field( row, 1 );
1467 folder->Parent = msi_dup_record_field( row, 2 );
1468 p = msi_dup_record_field(row, 3);
1470 TRACE("%s\n", debugstr_w(folder->Directory));
1472 /* split src and target dir */
1474 src_short = folder_split_path( p, ':' );
1476 /* split the long and short paths */
1477 tgt_long = folder_split_path( tgt_short, '|' );
1478 src_long = folder_split_path( src_short, '|' );
1480 /* check for no-op dirs */
1481 if (tgt_short && !strcmpW( szDot, tgt_short ))
1482 tgt_short = szEmpty;
1483 if (src_short && !strcmpW( szDot, src_short ))
1484 src_short = szEmpty;
1487 tgt_long = tgt_short;
1490 src_short = tgt_short;
1491 src_long = tgt_long;
1495 src_long = src_short;
1497 /* FIXME: use the target short path too */
1498 folder->TargetDefault = strdupW(tgt_long);
1499 folder->SourceShortPath = strdupW(src_short);
1500 folder->SourceLongPath = strdupW(src_long);
1503 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1504 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1505 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1507 list_add_tail( &package->folders, &folder->entry );
1508 return ERROR_SUCCESS;
1511 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1515 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1517 list_add_tail( &parent->children, &fl->entry );
1518 return ERROR_SUCCESS;
1521 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1523 MSIPACKAGE *package = param;
1524 MSIFOLDER *parent, *child;
1526 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1527 return ERROR_FUNCTION_FAILED;
1529 if (!child->Parent) return ERROR_SUCCESS;
1531 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1532 return ERROR_FUNCTION_FAILED;
1534 return add_folder_child( parent, child );
1537 static UINT load_all_folders( MSIPACKAGE *package )
1539 static const WCHAR query[] = {
1540 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1541 '`','D','i','r','e','c','t','o','r','y','`',0 };
1545 if (!list_empty(&package->folders))
1546 return ERROR_SUCCESS;
1548 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1549 if (r != ERROR_SUCCESS)
1552 r = MSI_IterateRecords( view, NULL, load_folder, package );
1553 if (r != ERROR_SUCCESS)
1555 msiobj_release( &view->hdr );
1558 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1559 msiobj_release( &view->hdr );
1563 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1565 msi_set_property( package->db, szCostingComplete, szZero );
1566 msi_set_property( package->db, szRootDrive, szCRoot );
1568 load_all_folders( package );
1569 load_all_components( package );
1570 load_all_features( package );
1571 load_all_files( package );
1572 load_all_patches( package );
1573 load_all_media( package );
1575 return ERROR_SUCCESS;
1578 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1580 const WCHAR *action = package->script->Actions[script][index];
1581 ui_actionstart( package, action );
1582 TRACE("executing %s\n", debugstr_w(action));
1583 return ACTION_PerformAction( package, action, script );
1586 static UINT execute_script( MSIPACKAGE *package, UINT script )
1588 UINT i, rc = ERROR_SUCCESS;
1590 TRACE("executing script %u\n", script);
1592 if (!package->script)
1594 ERR("no script!\n");
1595 return ERROR_FUNCTION_FAILED;
1597 if (script == ROLLBACK_SCRIPT)
1599 for (i = package->script->ActionCount[script]; i > 0; i--)
1601 rc = execute_script_action( package, script, i - 1 );
1602 if (rc != ERROR_SUCCESS) break;
1607 for (i = 0; i < package->script->ActionCount[script]; i++)
1609 rc = execute_script_action( package, script, i );
1610 if (rc != ERROR_SUCCESS) break;
1613 msi_free_action_script(package, script);
1617 static UINT ACTION_FileCost(MSIPACKAGE *package)
1619 return ERROR_SUCCESS;
1622 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1627 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1629 if (!comp->ComponentId) continue;
1631 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1632 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1634 if (r != ERROR_SUCCESS)
1635 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1636 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1638 if (r != ERROR_SUCCESS)
1639 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1640 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1642 if (r != ERROR_SUCCESS)
1643 comp->Installed = INSTALLSTATE_ABSENT;
1647 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1649 MSIFEATURE *feature;
1651 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1653 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1655 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1656 feature->Installed = INSTALLSTATE_ABSENT;
1658 feature->Installed = state;
1662 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1664 return (feature->Level > 0 && feature->Level <= level);
1667 static BOOL process_state_property(MSIPACKAGE* package, int level,
1668 LPCWSTR property, INSTALLSTATE state)
1671 MSIFEATURE *feature;
1673 override = msi_dup_property( package->db, property );
1677 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1679 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1682 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1684 if (!strcmpiW( override, szAll ))
1686 if (feature->Installed != state)
1688 feature->Action = state;
1689 feature->ActionRequest = state;
1694 LPWSTR ptr = override;
1695 LPWSTR ptr2 = strchrW(override,',');
1699 int len = ptr2 - ptr;
1701 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1702 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1704 if (feature->Installed != state)
1706 feature->Action = state;
1707 feature->ActionRequest = state;
1714 ptr2 = strchrW(ptr,',');
1725 static BOOL process_overrides( MSIPACKAGE *package, int level )
1727 static const WCHAR szAddLocal[] =
1728 {'A','D','D','L','O','C','A','L',0};
1729 static const WCHAR szAddSource[] =
1730 {'A','D','D','S','O','U','R','C','E',0};
1731 static const WCHAR szAdvertise[] =
1732 {'A','D','V','E','R','T','I','S','E',0};
1735 /* all these activation/deactivation things happen in order and things
1736 * later on the list override things earlier on the list.
1738 * 0 INSTALLLEVEL processing
1751 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1752 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1753 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1754 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1755 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1758 msi_set_property( package->db, szPreselected, szOne );
1763 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1766 MSICOMPONENT* component;
1767 MSIFEATURE *feature;
1769 TRACE("Checking Install Level\n");
1771 level = msi_get_property_int(package->db, szInstallLevel, 1);
1773 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1775 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1777 if (!is_feature_selected( feature, level )) continue;
1779 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1781 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1783 feature->Action = INSTALLSTATE_SOURCE;
1784 feature->ActionRequest = INSTALLSTATE_SOURCE;
1786 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1788 feature->Action = INSTALLSTATE_ADVERTISED;
1789 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1793 feature->Action = INSTALLSTATE_LOCAL;
1794 feature->ActionRequest = INSTALLSTATE_LOCAL;
1798 /* disable child features of unselected parent or follow parent */
1799 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1803 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1805 if (!is_feature_selected( feature, level ))
1807 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1808 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1810 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1812 fl->feature->Action = feature->Action;
1813 fl->feature->ActionRequest = feature->ActionRequest;
1818 else /* preselected */
1820 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1822 if (!is_feature_selected( feature, level )) continue;
1824 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1826 if (feature->Installed == INSTALLSTATE_ABSENT)
1828 feature->Action = INSTALLSTATE_UNKNOWN;
1829 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1833 feature->Action = feature->Installed;
1834 feature->ActionRequest = feature->Installed;
1838 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1842 if (!is_feature_selected( feature, level )) continue;
1844 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1846 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1848 fl->feature->Action = feature->Action;
1849 fl->feature->ActionRequest = feature->ActionRequest;
1855 /* now we want to set component state based based on feature state */
1856 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1860 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1861 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1862 feature->ActionRequest, feature->Action);
1864 if (!is_feature_selected( feature, level )) continue;
1866 /* features with components that have compressed files are made local */
1867 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1869 if (cl->component->ForceLocalState &&
1870 feature->ActionRequest == INSTALLSTATE_SOURCE)
1872 feature->Action = INSTALLSTATE_LOCAL;
1873 feature->ActionRequest = INSTALLSTATE_LOCAL;
1878 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1880 component = cl->component;
1882 switch (feature->ActionRequest)
1884 case INSTALLSTATE_ABSENT:
1885 component->anyAbsent = 1;
1887 case INSTALLSTATE_ADVERTISED:
1888 component->hasAdvertiseFeature = 1;
1890 case INSTALLSTATE_SOURCE:
1891 component->hasSourceFeature = 1;
1893 case INSTALLSTATE_LOCAL:
1894 component->hasLocalFeature = 1;
1896 case INSTALLSTATE_DEFAULT:
1897 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1898 component->hasAdvertiseFeature = 1;
1899 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1900 component->hasSourceFeature = 1;
1902 component->hasLocalFeature = 1;
1910 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1912 /* check if it's local or source */
1913 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1914 (component->hasLocalFeature || component->hasSourceFeature))
1916 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1917 !component->ForceLocalState)
1919 component->Action = INSTALLSTATE_SOURCE;
1920 component->ActionRequest = INSTALLSTATE_SOURCE;
1924 component->Action = INSTALLSTATE_LOCAL;
1925 component->ActionRequest = INSTALLSTATE_LOCAL;
1930 /* if any feature is local, the component must be local too */
1931 if (component->hasLocalFeature)
1933 component->Action = INSTALLSTATE_LOCAL;
1934 component->ActionRequest = INSTALLSTATE_LOCAL;
1937 if (component->hasSourceFeature)
1939 component->Action = INSTALLSTATE_SOURCE;
1940 component->ActionRequest = INSTALLSTATE_SOURCE;
1943 if (component->hasAdvertiseFeature)
1945 component->Action = INSTALLSTATE_ADVERTISED;
1946 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1949 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1950 if (component->anyAbsent &&
1951 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1953 component->Action = INSTALLSTATE_ABSENT;
1954 component->ActionRequest = INSTALLSTATE_ABSENT;
1958 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1960 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1962 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1963 component->Action = INSTALLSTATE_LOCAL;
1964 component->ActionRequest = INSTALLSTATE_LOCAL;
1967 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1968 component->Installed == INSTALLSTATE_SOURCE &&
1969 component->hasSourceFeature)
1971 component->Action = INSTALLSTATE_UNKNOWN;
1972 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1975 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1976 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1979 return ERROR_SUCCESS;
1982 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1984 MSIPACKAGE *package = param;
1986 MSIFEATURE *feature;
1988 name = MSI_RecordGetString( row, 1 );
1990 feature = msi_get_loaded_feature( package, name );
1992 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1996 Condition = MSI_RecordGetString(row,3);
1998 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2000 int level = MSI_RecordGetInteger(row,2);
2001 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2002 feature->Level = level;
2005 return ERROR_SUCCESS;
2008 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2010 static const WCHAR name[] = {'\\',0};
2011 VS_FIXEDFILEINFO *ptr, *ret;
2013 DWORD versize, handle;
2016 versize = GetFileVersionInfoSizeW( filename, &handle );
2020 version = msi_alloc( versize );
2024 GetFileVersionInfoW( filename, 0, versize, version );
2026 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2028 msi_free( version );
2032 ret = msi_alloc( sz );
2033 memcpy( ret, ptr, sz );
2035 msi_free( version );
2039 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2043 msi_parse_version_string( version, &ms, &ls );
2045 if (fi->dwFileVersionMS > ms) return 1;
2046 else if (fi->dwFileVersionMS < ms) return -1;
2047 else if (fi->dwFileVersionLS > ls) return 1;
2048 else if (fi->dwFileVersionLS < ls) return -1;
2052 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2056 msi_parse_version_string( ver1, &ms1, NULL );
2057 msi_parse_version_string( ver2, &ms2, NULL );
2059 if (ms1 > ms2) return 1;
2060 else if (ms1 < ms2) return -1;
2064 DWORD msi_get_disk_file_size( LPCWSTR filename )
2069 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2070 if (file == INVALID_HANDLE_VALUE)
2071 return INVALID_FILE_SIZE;
2073 size = GetFileSize( file, NULL );
2074 TRACE("size is %u\n", size);
2075 CloseHandle( file );
2079 BOOL msi_file_hash_matches( MSIFILE *file )
2082 MSIFILEHASHINFO hash;
2084 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2085 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2086 if (r != ERROR_SUCCESS)
2089 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2092 static WCHAR *get_temp_dir( void )
2095 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2097 GetTempPathW( MAX_PATH, tmp );
2100 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2101 if (CreateDirectoryW( dir, NULL )) break;
2103 return strdupW( dir );
2107 * msi_build_directory_name()
2109 * This function is to save messing round with directory names
2110 * It handles adding backslashes between path segments,
2111 * and can add \ at the end of the directory name if told to.
2113 * It takes a variable number of arguments.
2114 * It always allocates a new string for the result, so make sure
2115 * to free the return value when finished with it.
2117 * The first arg is the number of path segments that follow.
2118 * The arguments following count are a list of path segments.
2119 * A path segment may be NULL.
2121 * Path segments will be added with a \ separating them.
2122 * A \ will not be added after the last segment, however if the
2123 * last segment is NULL, then the last character will be a \
2125 WCHAR *msi_build_directory_name( DWORD count, ... )
2131 va_start( va, count );
2132 for (i = 0; i < count; i++)
2134 const WCHAR *str = va_arg( va, const WCHAR * );
2135 if (str) sz += strlenW( str ) + 1;
2139 dir = msi_alloc( sz * sizeof(WCHAR) );
2142 va_start( va, count );
2143 for (i = 0; i < count; i++)
2145 const WCHAR *str = va_arg( va, const WCHAR * );
2147 strcatW( dir, str );
2148 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2154 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2156 MSIASSEMBLY *assembly = file->Component->assembly;
2158 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2160 msi_free( file->TargetPath );
2161 if (assembly && !assembly->application)
2163 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2164 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2165 msi_track_tempfile( package, file->TargetPath );
2169 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2170 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2173 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2176 static UINT calculate_file_cost( MSIPACKAGE *package )
2178 VS_FIXEDFILEINFO *file_version;
2179 WCHAR *font_version;
2182 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2184 MSICOMPONENT *comp = file->Component;
2187 if (!comp->Enabled) continue;
2189 if (file->IsCompressed)
2190 comp->ForceLocalState = TRUE;
2192 set_target_path( package, file );
2194 if ((comp->assembly && !comp->assembly->installed) ||
2195 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2197 comp->Cost += file->FileSize;
2200 file_size = msi_get_disk_file_size( file->TargetPath );
2204 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2206 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2208 comp->Cost += file->FileSize - file_size;
2210 msi_free( file_version );
2213 else if ((font_version = font_version_from_file( file->TargetPath )))
2215 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2217 comp->Cost += file->FileSize - file_size;
2219 msi_free( font_version );
2223 if (file_size != file->FileSize)
2225 comp->Cost += file->FileSize - file_size;
2228 return ERROR_SUCCESS;
2231 void msi_clean_path( WCHAR *p )
2238 /* copy until the end of the string or a space */
2239 while (*p != ' ' && (*q = *p))
2242 /* reduce many backslashes to one */
2243 if (*p != '\\' || *q != '\\')
2247 /* quit at the end of the string */
2251 /* count the number of spaces */
2256 /* if it's leading or trailing space, skip it */
2257 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2259 else /* copy n spaces */
2260 while (n && (*q++ = *p++)) n--;
2264 static WCHAR *get_target_dir_property( MSIDATABASE *db )
2267 WCHAR *path, *target_dir = msi_dup_property( db, szTargetDir );
2269 if (!target_dir) return NULL;
2271 len = strlenW( target_dir );
2272 if (target_dir[len - 1] == '\\') return target_dir;
2273 if ((path = msi_alloc( (len + 2) * sizeof(WCHAR) )))
2275 strcpyW( path, target_dir );
2279 msi_free( target_dir );
2283 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2286 MSIFOLDER *folder, *parent, *child;
2289 TRACE("resolving %s\n", debugstr_w(name));
2291 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2293 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2295 if (!load_prop || !(path = get_target_dir_property( package->db )))
2297 path = msi_dup_property( package->db, szRootDrive );
2300 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2302 parent = msi_get_loaded_folder( package, folder->Parent );
2303 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2305 msi_clean_path( path );
2306 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2308 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2312 msi_set_property( package->db, folder->Directory, path );
2313 msi_free( folder->ResolvedTarget );
2314 folder->ResolvedTarget = path;
2316 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2319 msi_resolve_target_folder( package, child->Directory, load_prop );
2321 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2324 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2326 static const WCHAR condition_query[] =
2327 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','C','o','n','d','i','t','i','o','n','`',0};
2328 static const WCHAR szOutOfDiskSpace[] =
2329 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2331 UINT rc = ERROR_SUCCESS;
2335 TRACE("Building directory properties\n");
2336 msi_resolve_target_folder( package, szTargetDir, TRUE );
2338 TRACE("Evaluating component conditions\n");
2339 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2341 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2343 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2344 comp->Enabled = FALSE;
2347 comp->Enabled = TRUE;
2350 /* read components states from the registry */
2351 ACTION_GetComponentInstallStates(package);
2352 ACTION_GetFeatureInstallStates(package);
2354 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2356 TRACE("Evaluating feature conditions\n");
2358 rc = MSI_DatabaseOpenViewW( package->db, condition_query, &view );
2359 if (rc == ERROR_SUCCESS)
2361 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2362 msiobj_release( &view->hdr );
2366 TRACE("Calculating file cost\n");
2367 calculate_file_cost( package );
2369 msi_set_property( package->db, szCostingComplete, szOne );
2370 /* set default run level if not set */
2371 level = msi_dup_property( package->db, szInstallLevel );
2373 msi_set_property( package->db, szInstallLevel, szOne );
2376 /* FIXME: check volume disk space */
2377 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2379 return MSI_SetFeatureStates(package);
2382 /* OK this value is "interpreted" and then formatted based on the
2383 first few characters */
2384 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2389 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2395 LPWSTR deformated = NULL;
2398 deformat_string(package, &value[2], &deformated);
2400 /* binary value type */
2404 *size = (strlenW(ptr)/2)+1;
2406 *size = strlenW(ptr)/2;
2408 data = msi_alloc(*size);
2414 /* if uneven pad with a zero in front */
2420 data[count] = (BYTE)strtol(byte,NULL,0);
2422 TRACE("Uneven byte count\n");
2430 data[count] = (BYTE)strtol(byte,NULL,0);
2433 msi_free(deformated);
2435 TRACE("Data %i bytes(%i)\n",*size,count);
2442 deformat_string(package, &value[1], &deformated);
2445 *size = sizeof(DWORD);
2446 data = msi_alloc(*size);
2452 if ( (*p < '0') || (*p > '9') )
2458 if (deformated[0] == '-')
2461 TRACE("DWORD %i\n",*(LPDWORD)data);
2463 msi_free(deformated);
2468 static const WCHAR szMulti[] = {'[','~',']',0};
2477 *type=REG_EXPAND_SZ;
2485 if (strstrW(value, szMulti))
2486 *type = REG_MULTI_SZ;
2488 /* remove initial delimiter */
2489 if (!strncmpW(value, szMulti, 3))
2492 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2494 /* add double NULL terminator */
2495 if (*type == REG_MULTI_SZ)
2497 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2498 data = msi_realloc_zero(data, *size);
2504 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2511 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2513 *root_key = HKEY_LOCAL_MACHINE;
2518 *root_key = HKEY_CURRENT_USER;
2523 *root_key = HKEY_CLASSES_ROOT;
2527 *root_key = HKEY_CURRENT_USER;
2531 *root_key = HKEY_LOCAL_MACHINE;
2535 *root_key = HKEY_USERS;
2539 ERR("Unknown root %i\n", root);
2546 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2548 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2549 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2551 if (is_64bit && package->platform == PLATFORM_INTEL &&
2552 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2557 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2558 if (!(path_32node = msi_alloc( size ))) return NULL;
2560 memcpy( path_32node, path, len * sizeof(WCHAR) );
2561 strcpyW( path_32node + len, szWow6432Node );
2562 strcatW( path_32node, szBackSlash );
2563 strcatW( path_32node, path + len );
2567 return strdupW( path );
2570 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2572 MSIPACKAGE *package = param;
2573 LPSTR value_data = NULL;
2574 HKEY root_key, hkey;
2576 LPWSTR deformated, uikey, keypath;
2577 LPCWSTR szRoot, component, name, key, value;
2581 BOOL check_first = FALSE;
2584 msi_ui_progress( package, 2, 0, 0, 0 );
2586 component = MSI_RecordGetString(row, 6);
2587 comp = msi_get_loaded_component(package,component);
2589 return ERROR_SUCCESS;
2591 comp->Action = msi_get_component_action( package, comp );
2592 if (comp->Action != INSTALLSTATE_LOCAL)
2594 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2595 return ERROR_SUCCESS;
2598 name = MSI_RecordGetString(row, 4);
2599 if( MSI_RecordIsNull(row,5) && name )
2601 /* null values can have special meanings */
2602 if (name[0]=='-' && name[1] == 0)
2603 return ERROR_SUCCESS;
2604 else if ((name[0]=='+' && name[1] == 0) ||
2605 (name[0] == '*' && name[1] == 0))
2610 root = MSI_RecordGetInteger(row,2);
2611 key = MSI_RecordGetString(row, 3);
2613 szRoot = get_root_key( package, root, &root_key );
2615 return ERROR_SUCCESS;
2617 deformat_string(package, key , &deformated);
2618 size = strlenW(deformated) + strlenW(szRoot) + 1;
2619 uikey = msi_alloc(size*sizeof(WCHAR));
2620 strcpyW(uikey,szRoot);
2621 strcatW(uikey,deformated);
2623 keypath = get_keypath( package, root_key, deformated );
2624 msi_free( deformated );
2625 if (RegCreateKeyW( root_key, keypath, &hkey ))
2627 ERR("Could not create key %s\n", debugstr_w(keypath));
2630 return ERROR_SUCCESS;
2633 value = MSI_RecordGetString(row,5);
2635 value_data = parse_value(package, value, &type, &size);
2638 value_data = (LPSTR)strdupW(szEmpty);
2639 size = sizeof(szEmpty);
2643 deformat_string(package, name, &deformated);
2647 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2649 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2654 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2655 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2657 TRACE("value %s of %s checked already exists\n",
2658 debugstr_w(deformated), debugstr_w(uikey));
2662 TRACE("Checked and setting value %s of %s\n",
2663 debugstr_w(deformated), debugstr_w(uikey));
2664 if (deformated || size)
2665 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2670 uirow = MSI_CreateRecord(3);
2671 MSI_RecordSetStringW(uirow,2,deformated);
2672 MSI_RecordSetStringW(uirow,1,uikey);
2673 if (type == REG_SZ || type == REG_EXPAND_SZ)
2674 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2675 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2676 msiobj_release( &uirow->hdr );
2678 msi_free(value_data);
2679 msi_free(deformated);
2683 return ERROR_SUCCESS;
2686 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2690 static const WCHAR ExecSeqQuery[] =
2691 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2692 '`','R','e','g','i','s','t','r','y','`',0 };
2694 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2695 if (rc != ERROR_SUCCESS)
2696 return ERROR_SUCCESS;
2698 /* increment progress bar each time action data is sent */
2699 msi_ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2701 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2702 msiobj_release(&view->hdr);
2706 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2710 DWORD num_subkeys, num_values;
2714 if ((res = RegDeleteTreeW( hkey_root, key )))
2716 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2721 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2723 if ((res = RegDeleteValueW( hkey, value )))
2725 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2727 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2728 NULL, NULL, NULL, NULL );
2729 RegCloseKey( hkey );
2730 if (!res && !num_subkeys && !num_values)
2732 TRACE("Removing empty key %s\n", debugstr_w(key));
2733 RegDeleteKeyW( hkey_root, key );
2737 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2741 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2743 MSIPACKAGE *package = param;
2744 LPCWSTR component, name, key_str, root_key_str;
2745 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2748 BOOL delete_key = FALSE;
2753 msi_ui_progress( package, 2, 0, 0, 0 );
2755 component = MSI_RecordGetString( row, 6 );
2756 comp = msi_get_loaded_component( package, component );
2758 return ERROR_SUCCESS;
2760 comp->Action = msi_get_component_action( package, comp );
2761 if (comp->Action != INSTALLSTATE_ABSENT)
2763 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2764 return ERROR_SUCCESS;
2767 name = MSI_RecordGetString( row, 4 );
2768 if (MSI_RecordIsNull( row, 5 ) && name )
2770 if (name[0] == '+' && !name[1])
2771 return ERROR_SUCCESS;
2772 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2779 root = MSI_RecordGetInteger( row, 2 );
2780 key_str = MSI_RecordGetString( row, 3 );
2782 root_key_str = get_root_key( package, root, &hkey_root );
2784 return ERROR_SUCCESS;
2786 deformat_string( package, key_str, &deformated_key );
2787 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2788 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2789 strcpyW( ui_key_str, root_key_str );
2790 strcatW( ui_key_str, deformated_key );
2792 deformat_string( package, name, &deformated_name );
2794 keypath = get_keypath( package, hkey_root, deformated_key );
2795 msi_free( deformated_key );
2796 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2797 msi_free( keypath );
2799 uirow = MSI_CreateRecord( 2 );
2800 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2801 MSI_RecordSetStringW( uirow, 2, deformated_name );
2803 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2804 msiobj_release( &uirow->hdr );
2806 msi_free( ui_key_str );
2807 msi_free( deformated_name );
2808 return ERROR_SUCCESS;
2811 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2813 MSIPACKAGE *package = param;
2814 LPCWSTR component, name, key_str, root_key_str;
2815 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2818 BOOL delete_key = FALSE;
2823 msi_ui_progress( package, 2, 0, 0, 0 );
2825 component = MSI_RecordGetString( row, 5 );
2826 comp = msi_get_loaded_component( package, component );
2828 return ERROR_SUCCESS;
2830 comp->Action = msi_get_component_action( package, comp );
2831 if (comp->Action != INSTALLSTATE_LOCAL)
2833 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2834 return ERROR_SUCCESS;
2837 if ((name = MSI_RecordGetString( row, 4 )))
2839 if (name[0] == '-' && !name[1])
2846 root = MSI_RecordGetInteger( row, 2 );
2847 key_str = MSI_RecordGetString( row, 3 );
2849 root_key_str = get_root_key( package, root, &hkey_root );
2851 return ERROR_SUCCESS;
2853 deformat_string( package, key_str, &deformated_key );
2854 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2855 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2856 strcpyW( ui_key_str, root_key_str );
2857 strcatW( ui_key_str, deformated_key );
2859 deformat_string( package, name, &deformated_name );
2861 keypath = get_keypath( package, hkey_root, deformated_key );
2862 msi_free( deformated_key );
2863 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2864 msi_free( keypath );
2866 uirow = MSI_CreateRecord( 2 );
2867 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2868 MSI_RecordSetStringW( uirow, 2, deformated_name );
2870 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2871 msiobj_release( &uirow->hdr );
2873 msi_free( ui_key_str );
2874 msi_free( deformated_name );
2875 return ERROR_SUCCESS;
2878 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2882 static const WCHAR registry_query[] =
2883 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2884 '`','R','e','g','i','s','t','r','y','`',0 };
2885 static const WCHAR remove_registry_query[] =
2886 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2887 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2889 /* increment progress bar each time action data is sent */
2890 msi_ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2892 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2893 if (rc == ERROR_SUCCESS)
2895 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2896 msiobj_release( &view->hdr );
2897 if (rc != ERROR_SUCCESS)
2901 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2902 if (rc == ERROR_SUCCESS)
2904 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2905 msiobj_release( &view->hdr );
2906 if (rc != ERROR_SUCCESS)
2910 return ERROR_SUCCESS;
2913 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2915 package->script->CurrentlyScripting = TRUE;
2917 return ERROR_SUCCESS;
2921 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2926 static const WCHAR q1[]=
2927 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2928 '`','R','e','g','i','s','t','r','y','`',0};
2931 MSIFEATURE *feature;
2934 TRACE("InstallValidate\n");
2936 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2937 if (rc == ERROR_SUCCESS)
2939 MSI_IterateRecords( view, &progress, NULL, package );
2940 msiobj_release( &view->hdr );
2941 total += progress * REG_PROGRESS_VALUE;
2944 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2945 total += COMPONENT_PROGRESS_VALUE;
2947 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2948 total += file->FileSize;
2950 msi_ui_progress( package, 0, total, 0, 0 );
2952 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2954 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2955 debugstr_w(feature->Feature), feature->Installed,
2956 feature->ActionRequest, feature->Action);
2959 return ERROR_SUCCESS;
2962 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2964 MSIPACKAGE* package = param;
2965 LPCWSTR cond = NULL;
2966 LPCWSTR message = NULL;
2969 static const WCHAR title[]=
2970 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2972 cond = MSI_RecordGetString(row,1);
2974 r = MSI_EvaluateConditionW(package,cond);
2975 if (r == MSICONDITION_FALSE)
2977 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2980 message = MSI_RecordGetString(row,2);
2981 deformat_string(package,message,&deformated);
2982 MessageBoxW(NULL,deformated,title,MB_OK);
2983 msi_free(deformated);
2986 return ERROR_INSTALL_FAILURE;
2989 return ERROR_SUCCESS;
2992 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2995 MSIQUERY * view = NULL;
2996 static const WCHAR ExecSeqQuery[] =
2997 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2998 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3000 TRACE("Checking launch conditions\n");
3002 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3003 if (rc != ERROR_SUCCESS)
3004 return ERROR_SUCCESS;
3006 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3007 msiobj_release(&view->hdr);
3012 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3016 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3018 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3020 MSIRECORD * row = 0;
3022 LPWSTR deformated,buffer,deformated_name;
3024 static const WCHAR ExecSeqQuery[] =
3025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3026 '`','R','e','g','i','s','t','r','y','`',' ',
3027 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3028 ' ','=',' ' ,'\'','%','s','\'',0 };
3029 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3030 static const WCHAR fmt2[]=
3031 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3033 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3037 root = MSI_RecordGetInteger(row,2);
3038 key = MSI_RecordGetString(row, 3);
3039 name = MSI_RecordGetString(row, 4);
3040 deformat_string(package, key , &deformated);
3041 deformat_string(package, name, &deformated_name);
3043 len = strlenW(deformated) + 6;
3044 if (deformated_name)
3045 len+=strlenW(deformated_name);
3047 buffer = msi_alloc( len *sizeof(WCHAR));
3049 if (deformated_name)
3050 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3052 sprintfW(buffer,fmt,root,deformated);
3054 msi_free(deformated);
3055 msi_free(deformated_name);
3056 msiobj_release(&row->hdr);
3060 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3062 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3067 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3070 return strdupW( file->TargetPath );
3075 static HKEY openSharedDLLsKey(void)
3078 static const WCHAR path[] =
3079 {'S','o','f','t','w','a','r','e','\\',
3080 'M','i','c','r','o','s','o','f','t','\\',
3081 'W','i','n','d','o','w','s','\\',
3082 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3083 'S','h','a','r','e','d','D','L','L','s',0};
3085 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3089 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3094 DWORD sz = sizeof(count);
3097 hkey = openSharedDLLsKey();
3098 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3099 if (rc != ERROR_SUCCESS)
3105 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3109 hkey = openSharedDLLsKey();
3111 msi_reg_set_val_dword( hkey, path, count );
3113 RegDeleteValueW(hkey,path);
3118 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3120 MSIFEATURE *feature;
3124 /* only refcount DLLs */
3125 if (comp->KeyPath == NULL ||
3127 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3128 comp->Attributes & msidbComponentAttributesODBCDataSource)
3132 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3133 write = (count > 0);
3135 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3139 /* increment counts */
3140 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3144 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3147 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3149 if ( cl->component == comp )
3154 /* decrement counts */
3155 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3159 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3162 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3164 if ( cl->component == comp )
3169 /* ref count all the files in the component */
3174 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3176 if (file->Component == comp)
3177 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3181 /* add a count for permanent */
3182 if (comp->Attributes & msidbComponentAttributesPermanent)
3185 comp->RefCount = count;
3188 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3191 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3193 WCHAR squished_pc[GUID_SIZE];
3194 WCHAR squished_cc[GUID_SIZE];
3201 squash_guid(package->ProductCode,squished_pc);
3202 msi_ui_progress( package, 1, COMPONENT_PROGRESS_VALUE, 1, 0 );
3204 msi_set_sourcedir_props(package, FALSE);
3206 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3210 msi_ui_progress( package, 2, 0, 0, 0 );
3211 if (!comp->ComponentId)
3214 squash_guid(comp->ComponentId,squished_cc);
3216 msi_free(comp->FullKeypath);
3219 const WCHAR prefixW[] = {'<','\\',0};
3220 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3222 comp->FullKeypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3223 if (comp->FullKeypath)
3225 strcpyW( comp->FullKeypath, prefixW );
3226 strcatW( comp->FullKeypath, comp->assembly->display_name );
3229 else comp->FullKeypath = resolve_keypath( package, comp );
3231 ACTION_RefCountComponent( package, comp );
3233 comp->Action = msi_get_component_action( package, comp );
3234 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3235 debugstr_w(comp->Component),
3236 debugstr_w(squished_cc),
3237 debugstr_w(comp->FullKeypath),
3241 if (comp->Action == INSTALLSTATE_LOCAL ||
3242 comp->Action == INSTALLSTATE_SOURCE)
3244 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3245 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3247 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3249 if (rc != ERROR_SUCCESS)
3252 if (comp->Attributes & msidbComponentAttributesPermanent)
3254 static const WCHAR szPermKey[] =
3255 { '0','0','0','0','0','0','0','0','0','0','0','0',
3256 '0','0','0','0','0','0','0','0','0','0','0','0',
3257 '0','0','0','0','0','0','0','0',0 };
3259 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3262 if (comp->Action == INSTALLSTATE_LOCAL)
3263 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3269 WCHAR source[MAX_PATH];
3270 WCHAR base[MAX_PATH];
3273 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3274 static const WCHAR query[] = {
3275 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3276 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3277 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3278 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3279 '`','D','i','s','k','I','d','`',0};
3281 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3284 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3285 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3286 ptr2 = strrchrW(source, '\\') + 1;
3287 msiobj_release(&row->hdr);
3289 lstrcpyW(base, package->PackagePath);
3290 ptr = strrchrW(base, '\\');
3293 sourcepath = msi_resolve_file_source(package, file);
3294 ptr = sourcepath + lstrlenW(base);
3295 lstrcpyW(ptr2, ptr);
3296 msi_free(sourcepath);
3298 msi_reg_set_val_str(hkey, squished_pc, source);
3302 else if (comp->Action == INSTALLSTATE_ABSENT)
3304 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3305 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3307 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3311 uirow = MSI_CreateRecord(3);
3312 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3313 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3314 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3315 msi_ui_actiondata( package, szProcessComponents, uirow );
3316 msiobj_release( &uirow->hdr );
3318 return ERROR_SUCCESS;
3329 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3330 LPWSTR lpszName, LONG_PTR lParam)
3333 typelib_struct *tl_struct = (typelib_struct*) lParam;
3334 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3338 if (!IS_INTRESOURCE(lpszName))
3340 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3344 sz = strlenW(tl_struct->source)+4;
3345 sz *= sizeof(WCHAR);
3347 if ((INT_PTR)lpszName == 1)
3348 tl_struct->path = strdupW(tl_struct->source);
3351 tl_struct->path = msi_alloc(sz);
3352 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3355 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3356 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3359 msi_free(tl_struct->path);
3360 tl_struct->path = NULL;
3365 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3366 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3368 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3372 msi_free(tl_struct->path);
3373 tl_struct->path = NULL;
3375 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3376 ITypeLib_Release(tl_struct->ptLib);
3381 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3383 MSIPACKAGE* package = param;
3387 typelib_struct tl_struct;
3392 component = MSI_RecordGetString(row,3);
3393 comp = msi_get_loaded_component(package,component);
3395 return ERROR_SUCCESS;
3397 comp->Action = msi_get_component_action( package, comp );
3398 if (comp->Action != INSTALLSTATE_LOCAL)
3400 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3401 return ERROR_SUCCESS;
3404 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3406 TRACE("component has no key path\n");
3407 return ERROR_SUCCESS;
3409 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3411 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3415 guid = MSI_RecordGetString(row,1);
3416 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3417 tl_struct.source = strdupW( file->TargetPath );
3418 tl_struct.path = NULL;
3420 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3421 (LONG_PTR)&tl_struct);
3425 LPCWSTR helpid, help_path = NULL;
3428 helpid = MSI_RecordGetString(row,6);
3430 if (helpid) help_path = msi_get_target_folder( package, helpid );
3431 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3434 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3436 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3438 ITypeLib_Release(tl_struct.ptLib);
3439 msi_free(tl_struct.path);
3441 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3443 FreeLibrary(module);
3444 msi_free(tl_struct.source);
3448 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3451 ERR("Failed to load type library: %08x\n", hr);
3452 return ERROR_INSTALL_FAILURE;
3455 ITypeLib_Release(tlib);
3458 return ERROR_SUCCESS;
3461 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3464 * OK this is a bit confusing.. I am given a _Component key and I believe
3465 * that the file that is being registered as a type library is the "key file
3466 * of that component" which I interpret to mean "The file in the KeyPath of
3471 static const WCHAR Query[] =
3472 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3473 '`','T','y','p','e','L','i','b','`',0};
3475 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3476 if (rc != ERROR_SUCCESS)
3477 return ERROR_SUCCESS;
3479 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3480 msiobj_release(&view->hdr);
3484 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3486 MSIPACKAGE *package = param;
3487 LPCWSTR component, guid;
3495 component = MSI_RecordGetString( row, 3 );
3496 comp = msi_get_loaded_component( package, component );
3498 return ERROR_SUCCESS;
3500 comp->Action = msi_get_component_action( package, comp );
3501 if (comp->Action != INSTALLSTATE_ABSENT)
3503 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3504 return ERROR_SUCCESS;
3506 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3508 guid = MSI_RecordGetString( row, 1 );
3509 CLSIDFromString( (LPCWSTR)guid, &libid );
3510 version = MSI_RecordGetInteger( row, 4 );
3511 language = MSI_RecordGetInteger( row, 2 );
3514 syskind = SYS_WIN64;
3516 syskind = SYS_WIN32;
3519 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3522 WARN("Failed to unregister typelib: %08x\n", hr);
3525 return ERROR_SUCCESS;
3528 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3532 static const WCHAR query[] =
3533 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3534 '`','T','y','p','e','L','i','b','`',0};
3536 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3537 if (rc != ERROR_SUCCESS)
3538 return ERROR_SUCCESS;
3540 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3541 msiobj_release( &view->hdr );
3545 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3547 static const WCHAR szlnk[] = {'.','l','n','k',0};
3548 LPCWSTR directory, extension, link_folder;
3549 LPWSTR link_file, filename;
3551 directory = MSI_RecordGetString( row, 2 );
3552 link_folder = msi_get_target_folder( package, directory );
3554 /* may be needed because of a bug somewhere else */
3555 msi_create_full_path( link_folder );
3557 filename = msi_dup_record_field( row, 3 );
3558 msi_reduce_to_long_filename( filename );
3560 extension = strchrW( filename, '.' );
3561 if (!extension || strcmpiW( extension, szlnk ))
3563 int len = strlenW( filename );
3564 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3565 memcpy( filename + len, szlnk, sizeof(szlnk) );
3567 link_file = msi_build_directory_name( 2, link_folder, filename );
3568 msi_free( filename );
3573 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3575 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3576 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3577 WCHAR *folder, *dest, *path;
3579 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3580 folder = msi_dup_property( package->db, szWindowsFolder );
3583 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3584 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3585 msi_free( appdata );
3587 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3588 msi_create_full_path( dest );
3589 path = msi_build_directory_name( 2, dest, icon_name );
3595 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3597 MSIPACKAGE *package = param;
3598 LPWSTR link_file, deformated, path;
3599 LPCWSTR component, target;
3601 IShellLinkW *sl = NULL;
3602 IPersistFile *pf = NULL;
3605 component = MSI_RecordGetString(row, 4);
3606 comp = msi_get_loaded_component(package, component);
3608 return ERROR_SUCCESS;
3610 comp->Action = msi_get_component_action( package, comp );
3611 if (comp->Action != INSTALLSTATE_LOCAL)
3613 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3614 return ERROR_SUCCESS;
3616 msi_ui_actiondata( package, szCreateShortcuts, row );
3618 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3619 &IID_IShellLinkW, (LPVOID *) &sl );
3623 ERR("CLSID_ShellLink not available\n");
3627 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3630 ERR("QueryInterface(IID_IPersistFile) failed\n");
3634 target = MSI_RecordGetString(row, 5);
3635 if (strchrW(target, '['))
3637 deformat_string(package, target, &deformated);
3638 IShellLinkW_SetPath(sl,deformated);
3639 msi_free(deformated);
3643 FIXME("poorly handled shortcut format, advertised shortcut\n");
3644 IShellLinkW_SetPath(sl,comp->FullKeypath);
3647 if (!MSI_RecordIsNull(row,6))
3649 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3650 deformat_string(package, arguments, &deformated);
3651 IShellLinkW_SetArguments(sl,deformated);
3652 msi_free(deformated);
3655 if (!MSI_RecordIsNull(row,7))
3657 LPCWSTR description = MSI_RecordGetString(row, 7);
3658 IShellLinkW_SetDescription(sl, description);
3661 if (!MSI_RecordIsNull(row,8))
3662 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3664 if (!MSI_RecordIsNull(row,9))
3667 LPCWSTR icon = MSI_RecordGetString(row, 9);
3669 path = msi_build_icon_path(package, icon);
3670 index = MSI_RecordGetInteger(row,10);
3672 /* no value means 0 */
3673 if (index == MSI_NULL_INTEGER)
3676 IShellLinkW_SetIconLocation(sl, path, index);
3680 if (!MSI_RecordIsNull(row,11))
3681 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3683 if (!MSI_RecordIsNull(row,12))
3685 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3686 full_path = msi_get_target_folder( package, wkdir );
3687 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3689 link_file = get_link_file(package, row);
3691 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3692 IPersistFile_Save(pf, link_file, FALSE);
3693 msi_free(link_file);
3697 IPersistFile_Release( pf );
3699 IShellLinkW_Release( sl );
3701 return ERROR_SUCCESS;
3704 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3709 static const WCHAR Query[] =
3710 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3711 '`','S','h','o','r','t','c','u','t','`',0};
3713 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3714 if (rc != ERROR_SUCCESS)
3715 return ERROR_SUCCESS;
3717 res = CoInitialize( NULL );
3719 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3720 msiobj_release(&view->hdr);
3728 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3730 MSIPACKAGE *package = param;
3735 component = MSI_RecordGetString( row, 4 );
3736 comp = msi_get_loaded_component( package, component );
3738 return ERROR_SUCCESS;
3740 comp->Action = msi_get_component_action( package, comp );
3741 if (comp->Action != INSTALLSTATE_ABSENT)
3743 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3744 return ERROR_SUCCESS;
3746 msi_ui_actiondata( package, szRemoveShortcuts, row );
3748 link_file = get_link_file( package, row );
3750 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3751 if (!DeleteFileW( link_file ))
3753 WARN("Failed to remove shortcut file %u\n", GetLastError());
3755 msi_free( link_file );
3757 return ERROR_SUCCESS;
3760 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3764 static const WCHAR query[] =
3765 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3766 '`','S','h','o','r','t','c','u','t','`',0};
3768 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3769 if (rc != ERROR_SUCCESS)
3770 return ERROR_SUCCESS;
3772 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3773 msiobj_release( &view->hdr );
3778 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3780 MSIPACKAGE* package = param;
3788 FileName = MSI_RecordGetString(row,1);
3791 ERR("Unable to get FileName\n");
3792 return ERROR_SUCCESS;
3795 FilePath = msi_build_icon_path(package, FileName);
3797 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3799 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3800 FILE_ATTRIBUTE_NORMAL, NULL);
3802 if (the_file == INVALID_HANDLE_VALUE)
3804 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3806 return ERROR_SUCCESS;
3813 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3814 if (rc != ERROR_SUCCESS)
3816 ERR("Failed to get stream\n");
3817 CloseHandle(the_file);
3818 DeleteFileW(FilePath);
3821 WriteFile(the_file,buffer,sz,&write,NULL);
3822 } while (sz == 1024);
3825 CloseHandle(the_file);
3827 return ERROR_SUCCESS;
3830 static UINT msi_publish_icons(MSIPACKAGE *package)
3835 static const WCHAR query[]= {
3836 'S','E','L','E','C','T',' ','*',' ',
3837 'F','R','O','M',' ','`','I','c','o','n','`',0};
3839 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3840 if (r == ERROR_SUCCESS)
3842 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3843 msiobj_release(&view->hdr);
3846 return ERROR_SUCCESS;
3849 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3855 MSISOURCELISTINFO *info;
3857 r = RegCreateKeyW(hkey, szSourceList, &source);
3858 if (r != ERROR_SUCCESS)
3861 RegCloseKey(source);
3863 buffer = strrchrW(package->PackagePath, '\\') + 1;
3864 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3865 package->Context, MSICODE_PRODUCT,
3866 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3867 if (r != ERROR_SUCCESS)
3870 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3871 package->Context, MSICODE_PRODUCT,
3872 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3873 if (r != ERROR_SUCCESS)
3876 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3877 package->Context, MSICODE_PRODUCT,
3878 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3879 if (r != ERROR_SUCCESS)
3882 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3884 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3885 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3886 info->options, info->value);
3888 MsiSourceListSetInfoW(package->ProductCode, NULL,
3889 info->context, info->options,
3890 info->property, info->value);
3893 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3895 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3896 disk->context, disk->options,
3897 disk->disk_id, disk->volume_label, disk->disk_prompt);
3900 return ERROR_SUCCESS;
3903 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3905 MSIHANDLE hdb, suminfo;
3906 WCHAR guids[MAX_PATH];
3907 WCHAR packcode[SQUISH_GUID_SIZE];
3914 static const WCHAR szARPProductIcon[] =
3915 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3916 static const WCHAR szAssignment[] =
3917 {'A','s','s','i','g','n','m','e','n','t',0};
3918 static const WCHAR szAdvertiseFlags[] =
3919 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3920 static const WCHAR szClients[] =
3921 {'C','l','i','e','n','t','s',0};
3922 static const WCHAR szColon[] = {':',0};
3924 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3925 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3928 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3929 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3932 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3934 buffer = msi_dup_property(package->db, szARPProductIcon);
3937 LPWSTR path = msi_build_icon_path(package, buffer);
3938 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3943 buffer = msi_dup_property(package->db, szProductVersion);
3946 DWORD verdword = msi_version_str_to_dword(buffer);
3947 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3951 msi_reg_set_val_dword(hkey, szAssignment, 0);
3952 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3953 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3954 msi_reg_set_val_str(hkey, szClients, szColon);
3956 hdb = alloc_msihandle(&package->db->hdr);
3958 return ERROR_NOT_ENOUGH_MEMORY;
3960 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3961 MsiCloseHandle(hdb);
3962 if (r != ERROR_SUCCESS)
3966 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3967 NULL, guids, &size);
3968 if (r != ERROR_SUCCESS)
3971 ptr = strchrW(guids, ';');
3973 squash_guid(guids, packcode);
3974 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3977 MsiCloseHandle(suminfo);
3978 return ERROR_SUCCESS;
3981 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3986 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3988 upgrade = msi_dup_property(package->db, szUpgradeCode);
3990 return ERROR_SUCCESS;
3992 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3993 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3995 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3997 if (r != ERROR_SUCCESS)
3999 WARN("failed to open upgrade code key\n");
4001 return ERROR_SUCCESS;
4003 squash_guid(package->ProductCode, squashed_pc);
4004 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4007 return ERROR_SUCCESS;
4010 static BOOL msi_check_publish(MSIPACKAGE *package)
4012 MSIFEATURE *feature;
4014 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4016 feature->Action = msi_get_feature_action( package, feature );
4017 if (feature->Action == INSTALLSTATE_LOCAL)
4024 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4026 MSIFEATURE *feature;
4028 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4030 feature->Action = msi_get_feature_action( package, feature );
4031 if (feature->Action != INSTALLSTATE_ABSENT)
4038 static UINT msi_publish_patches( MSIPACKAGE *package )
4040 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4041 WCHAR patch_squashed[GUID_SIZE];
4042 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4044 MSIPATCHINFO *patch;
4046 WCHAR *p, *all_patches = NULL;
4049 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4050 if (r != ERROR_SUCCESS)
4051 return ERROR_FUNCTION_FAILED;
4053 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4054 if (res != ERROR_SUCCESS)
4056 r = ERROR_FUNCTION_FAILED;
4060 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4061 if (r != ERROR_SUCCESS)
4064 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4066 squash_guid( patch->patchcode, patch_squashed );
4067 len += strlenW( patch_squashed ) + 1;
4070 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4074 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4078 squash_guid( patch->patchcode, p );
4079 p += strlenW( p ) + 1;
4081 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4082 (const BYTE *)patch->transforms,
4083 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4084 if (res != ERROR_SUCCESS)
4087 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4088 if (r != ERROR_SUCCESS)
4091 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4092 (const BYTE *)patch->localfile,
4093 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4094 RegCloseKey( patch_key );
4095 if (res != ERROR_SUCCESS)
4098 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4099 if (res != ERROR_SUCCESS)
4102 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4103 RegCloseKey( patch_key );
4104 if (res != ERROR_SUCCESS)
4108 all_patches[len] = 0;
4109 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4110 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4111 if (res != ERROR_SUCCESS)
4114 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4115 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4116 if (res != ERROR_SUCCESS)
4117 r = ERROR_FUNCTION_FAILED;
4120 RegCloseKey( product_patches_key );
4121 RegCloseKey( patches_key );
4122 RegCloseKey( product_key );
4123 msi_free( all_patches );
4127 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4130 HKEY hukey = NULL, hudkey = NULL;
4133 if (!list_empty(&package->patches))
4135 rc = msi_publish_patches(package);
4136 if (rc != ERROR_SUCCESS)
4140 /* FIXME: also need to publish if the product is in advertise mode */
4141 if (!msi_check_publish(package))
4142 return ERROR_SUCCESS;
4144 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4146 if (rc != ERROR_SUCCESS)
4149 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4150 NULL, &hudkey, TRUE);
4151 if (rc != ERROR_SUCCESS)
4154 rc = msi_publish_upgrade_code(package);
4155 if (rc != ERROR_SUCCESS)
4158 rc = msi_publish_product_properties(package, hukey);
4159 if (rc != ERROR_SUCCESS)
4162 rc = msi_publish_sourcelist(package, hukey);
4163 if (rc != ERROR_SUCCESS)
4166 rc = msi_publish_icons(package);
4169 uirow = MSI_CreateRecord( 1 );
4170 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4171 msi_ui_actiondata( package, szPublishProduct, uirow );
4172 msiobj_release( &uirow->hdr );
4175 RegCloseKey(hudkey);
4180 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4182 WCHAR *filename, *ptr, *folder, *ret;
4183 const WCHAR *dirprop;
4185 filename = msi_dup_record_field( row, 2 );
4186 if (filename && (ptr = strchrW( filename, '|' )))
4191 dirprop = MSI_RecordGetString( row, 3 );
4194 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4195 if (!folder) folder = msi_dup_property( package->db, dirprop );
4198 folder = msi_dup_property( package->db, szWindowsFolder );
4202 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4203 msi_free( filename );
4207 ret = msi_build_directory_name( 2, folder, ptr );
4209 msi_free( filename );
4214 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4216 MSIPACKAGE *package = param;
4217 LPCWSTR component, section, key, value, identifier;
4218 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4223 component = MSI_RecordGetString(row, 8);
4224 comp = msi_get_loaded_component(package,component);
4226 return ERROR_SUCCESS;
4228 comp->Action = msi_get_component_action( package, comp );
4229 if (comp->Action != INSTALLSTATE_LOCAL)
4231 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4232 return ERROR_SUCCESS;
4235 identifier = MSI_RecordGetString(row,1);
4236 section = MSI_RecordGetString(row,4);
4237 key = MSI_RecordGetString(row,5);
4238 value = MSI_RecordGetString(row,6);
4239 action = MSI_RecordGetInteger(row,7);
4241 deformat_string(package,section,&deformated_section);
4242 deformat_string(package,key,&deformated_key);
4243 deformat_string(package,value,&deformated_value);
4245 fullname = get_ini_file_name(package, row);
4249 TRACE("Adding value %s to section %s in %s\n",
4250 debugstr_w(deformated_key), debugstr_w(deformated_section),
4251 debugstr_w(fullname));
4252 WritePrivateProfileStringW(deformated_section, deformated_key,
4253 deformated_value, fullname);
4255 else if (action == 1)
4258 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4259 returned, 10, fullname);
4260 if (returned[0] == 0)
4262 TRACE("Adding value %s to section %s in %s\n",
4263 debugstr_w(deformated_key), debugstr_w(deformated_section),
4264 debugstr_w(fullname));
4266 WritePrivateProfileStringW(deformated_section, deformated_key,
4267 deformated_value, fullname);
4270 else if (action == 3)
4271 FIXME("Append to existing section not yet implemented\n");
4273 uirow = MSI_CreateRecord(4);
4274 MSI_RecordSetStringW(uirow,1,identifier);
4275 MSI_RecordSetStringW(uirow,2,deformated_section);
4276 MSI_RecordSetStringW(uirow,3,deformated_key);
4277 MSI_RecordSetStringW(uirow,4,deformated_value);
4278 msi_ui_actiondata( package, szWriteIniValues, uirow );
4279 msiobj_release( &uirow->hdr );
4282 msi_free(deformated_key);
4283 msi_free(deformated_value);
4284 msi_free(deformated_section);
4285 return ERROR_SUCCESS;
4288 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4292 static const WCHAR ExecSeqQuery[] =
4293 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4294 '`','I','n','i','F','i','l','e','`',0};
4296 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4297 if (rc != ERROR_SUCCESS)
4299 TRACE("no IniFile table\n");
4300 return ERROR_SUCCESS;
4303 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4304 msiobj_release(&view->hdr);
4308 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4310 MSIPACKAGE *package = param;
4311 LPCWSTR component, section, key, value, identifier;
4312 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4317 component = MSI_RecordGetString( row, 8 );
4318 comp = msi_get_loaded_component( package, component );
4320 return ERROR_SUCCESS;
4322 comp->Action = msi_get_component_action( package, comp );
4323 if (comp->Action != INSTALLSTATE_ABSENT)
4325 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4326 return ERROR_SUCCESS;
4329 identifier = MSI_RecordGetString( row, 1 );
4330 section = MSI_RecordGetString( row, 4 );
4331 key = MSI_RecordGetString( row, 5 );
4332 value = MSI_RecordGetString( row, 6 );
4333 action = MSI_RecordGetInteger( row, 7 );
4335 deformat_string( package, section, &deformated_section );
4336 deformat_string( package, key, &deformated_key );
4337 deformat_string( package, value, &deformated_value );
4339 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4341 filename = get_ini_file_name( package, row );
4343 TRACE("Removing key %s from section %s in %s\n",
4344 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4346 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4348 WARN("Unable to remove key %u\n", GetLastError());
4350 msi_free( filename );
4353 FIXME("Unsupported action %d\n", action);
4356 uirow = MSI_CreateRecord( 4 );
4357 MSI_RecordSetStringW( uirow, 1, identifier );
4358 MSI_RecordSetStringW( uirow, 2, deformated_section );
4359 MSI_RecordSetStringW( uirow, 3, deformated_key );
4360 MSI_RecordSetStringW( uirow, 4, deformated_value );
4361 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4362 msiobj_release( &uirow->hdr );
4364 msi_free( deformated_key );
4365 msi_free( deformated_value );
4366 msi_free( deformated_section );
4367 return ERROR_SUCCESS;
4370 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4372 MSIPACKAGE *package = param;
4373 LPCWSTR component, section, key, value, identifier;
4374 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4379 component = MSI_RecordGetString( row, 8 );
4380 comp = msi_get_loaded_component( package, component );
4382 return ERROR_SUCCESS;
4384 comp->Action = msi_get_component_action( package, comp );
4385 if (comp->Action != INSTALLSTATE_LOCAL)
4387 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4388 return ERROR_SUCCESS;
4391 identifier = MSI_RecordGetString( row, 1 );
4392 section = MSI_RecordGetString( row, 4 );
4393 key = MSI_RecordGetString( row, 5 );
4394 value = MSI_RecordGetString( row, 6 );
4395 action = MSI_RecordGetInteger( row, 7 );
4397 deformat_string( package, section, &deformated_section );
4398 deformat_string( package, key, &deformated_key );
4399 deformat_string( package, value, &deformated_value );
4401 if (action == msidbIniFileActionRemoveLine)
4403 filename = get_ini_file_name( package, row );
4405 TRACE("Removing key %s from section %s in %s\n",
4406 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4408 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4410 WARN("Unable to remove key %u\n", GetLastError());
4412 msi_free( filename );
4415 FIXME("Unsupported action %d\n", action);
4417 uirow = MSI_CreateRecord( 4 );
4418 MSI_RecordSetStringW( uirow, 1, identifier );
4419 MSI_RecordSetStringW( uirow, 2, deformated_section );
4420 MSI_RecordSetStringW( uirow, 3, deformated_key );
4421 MSI_RecordSetStringW( uirow, 4, deformated_value );
4422 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4423 msiobj_release( &uirow->hdr );
4425 msi_free( deformated_key );
4426 msi_free( deformated_value );
4427 msi_free( deformated_section );
4428 return ERROR_SUCCESS;
4431 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4435 static const WCHAR query[] =
4436 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4437 '`','I','n','i','F','i','l','e','`',0};
4438 static const WCHAR remove_query[] =
4439 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4440 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4442 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4443 if (rc == ERROR_SUCCESS)
4445 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4446 msiobj_release( &view->hdr );
4447 if (rc != ERROR_SUCCESS)
4451 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4452 if (rc == ERROR_SUCCESS)
4454 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4455 msiobj_release( &view->hdr );
4456 if (rc != ERROR_SUCCESS)
4460 return ERROR_SUCCESS;
4463 static void register_dll( const WCHAR *dll, BOOL unregister )
4467 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4470 HRESULT (WINAPI *func_ptr)( void );
4471 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4473 func_ptr = (void *)GetProcAddress( hmod, func );
4476 HRESULT hr = func_ptr();
4478 WARN("failed to register dll 0x%08x\n", hr);
4481 WARN("entry point %s not found\n", func);
4482 FreeLibrary( hmod );
4485 WARN("failed to load library %u\n", GetLastError());
4488 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4490 MSIPACKAGE *package = param;
4495 filename = MSI_RecordGetString(row,1);
4496 file = msi_get_loaded_file( package, filename );
4499 WARN("unable to find file %s\n", debugstr_w(filename));
4500 return ERROR_SUCCESS;
4502 file->Component->Action = msi_get_component_action( package, file->Component );
4503 if (file->Component->Action != INSTALLSTATE_LOCAL)
4505 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4506 return ERROR_SUCCESS;
4509 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4510 register_dll( file->TargetPath, FALSE );
4512 uirow = MSI_CreateRecord( 2 );
4513 MSI_RecordSetStringW( uirow, 1, filename );
4514 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4515 msi_ui_actiondata( package, szSelfRegModules, uirow );
4516 msiobj_release( &uirow->hdr );
4518 return ERROR_SUCCESS;
4521 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4525 static const WCHAR ExecSeqQuery[] =
4526 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4527 '`','S','e','l','f','R','e','g','`',0};
4529 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4530 if (rc != ERROR_SUCCESS)
4532 TRACE("no SelfReg table\n");
4533 return ERROR_SUCCESS;
4536 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4537 msiobj_release(&view->hdr);
4539 return ERROR_SUCCESS;
4542 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4544 MSIPACKAGE *package = param;
4549 filename = MSI_RecordGetString( row, 1 );
4550 file = msi_get_loaded_file( package, filename );
4553 WARN("unable to find file %s\n", debugstr_w(filename));
4554 return ERROR_SUCCESS;
4556 file->Component->Action = msi_get_component_action( package, file->Component );
4557 if (file->Component->Action != INSTALLSTATE_ABSENT)
4559 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4560 return ERROR_SUCCESS;
4563 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4564 register_dll( file->TargetPath, TRUE );
4566 uirow = MSI_CreateRecord( 2 );
4567 MSI_RecordSetStringW( uirow, 1, filename );
4568 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4569 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4570 msiobj_release( &uirow->hdr );
4572 return ERROR_SUCCESS;
4575 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4579 static const WCHAR query[] =
4580 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4581 '`','S','e','l','f','R','e','g','`',0};
4583 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4584 if (rc != ERROR_SUCCESS)
4586 TRACE("no SelfReg table\n");
4587 return ERROR_SUCCESS;
4590 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4591 msiobj_release( &view->hdr );
4593 return ERROR_SUCCESS;
4596 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4598 MSIFEATURE *feature;
4600 HKEY hkey = NULL, userdata = NULL;
4602 if (!msi_check_publish(package))
4603 return ERROR_SUCCESS;
4605 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4607 if (rc != ERROR_SUCCESS)
4610 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4612 if (rc != ERROR_SUCCESS)
4615 /* here the guids are base 85 encoded */
4616 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4622 BOOL absent = FALSE;
4625 if (feature->Action != INSTALLSTATE_LOCAL &&
4626 feature->Action != INSTALLSTATE_SOURCE &&
4627 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4630 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4634 if (feature->Feature_Parent)
4635 size += strlenW( feature->Feature_Parent )+2;
4637 data = msi_alloc(size * sizeof(WCHAR));
4640 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4642 MSICOMPONENT* component = cl->component;
4646 if (component->ComponentId)
4648 TRACE("From %s\n",debugstr_w(component->ComponentId));
4649 CLSIDFromString(component->ComponentId, &clsid);
4650 encode_base85_guid(&clsid,buf);
4651 TRACE("to %s\n",debugstr_w(buf));
4656 if (feature->Feature_Parent)
4658 static const WCHAR sep[] = {'\2',0};
4660 strcatW(data,feature->Feature_Parent);
4663 msi_reg_set_val_str( userdata, feature->Feature, data );
4667 if (feature->Feature_Parent)
4668 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4671 size += sizeof(WCHAR);
4672 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4673 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4677 size += 2*sizeof(WCHAR);
4678 data = msi_alloc(size);
4681 if (feature->Feature_Parent)
4682 strcpyW( &data[1], feature->Feature_Parent );
4683 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4689 uirow = MSI_CreateRecord( 1 );
4690 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4691 msi_ui_actiondata( package, szPublishFeatures, uirow );
4692 msiobj_release( &uirow->hdr );
4693 /* FIXME: call msi_ui_progress? */
4698 RegCloseKey(userdata);
4702 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4708 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4710 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4712 if (r == ERROR_SUCCESS)
4714 RegDeleteValueW(hkey, feature->Feature);
4718 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4720 if (r == ERROR_SUCCESS)
4722 RegDeleteValueW(hkey, feature->Feature);
4726 uirow = MSI_CreateRecord( 1 );
4727 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4728 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4729 msiobj_release( &uirow->hdr );
4731 return ERROR_SUCCESS;
4734 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4736 MSIFEATURE *feature;
4738 if (!msi_check_unpublish(package))
4739 return ERROR_SUCCESS;
4741 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4743 msi_unpublish_feature(package, feature);
4746 return ERROR_SUCCESS;
4749 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4753 WCHAR date[9], *val, *buffer;
4754 const WCHAR *prop, *key;
4756 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4757 static const WCHAR modpath_fmt[] =
4758 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4759 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4760 static const WCHAR szModifyPath[] =
4761 {'M','o','d','i','f','y','P','a','t','h',0};
4762 static const WCHAR szUninstallString[] =
4763 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4764 static const WCHAR szEstimatedSize[] =
4765 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4766 static const WCHAR szDisplayVersion[] =
4767 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4768 static const WCHAR szInstallSource[] =
4769 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4770 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4771 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4772 static const WCHAR szAuthorizedCDFPrefix[] =
4773 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4774 static const WCHAR szARPCONTACT[] =
4775 {'A','R','P','C','O','N','T','A','C','T',0};
4776 static const WCHAR szContact[] =
4777 {'C','o','n','t','a','c','t',0};
4778 static const WCHAR szARPCOMMENTS[] =
4779 {'A','R','P','C','O','M','M','E','N','T','S',0};
4780 static const WCHAR szComments[] =
4781 {'C','o','m','m','e','n','t','s',0};
4782 static const WCHAR szProductName[] =
4783 {'P','r','o','d','u','c','t','N','a','m','e',0};
4784 static const WCHAR szDisplayName[] =
4785 {'D','i','s','p','l','a','y','N','a','m','e',0};
4786 static const WCHAR szARPHELPLINK[] =
4787 {'A','R','P','H','E','L','P','L','I','N','K',0};
4788 static const WCHAR szHelpLink[] =
4789 {'H','e','l','p','L','i','n','k',0};
4790 static const WCHAR szARPHELPTELEPHONE[] =
4791 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4792 static const WCHAR szHelpTelephone[] =
4793 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4794 static const WCHAR szARPINSTALLLOCATION[] =
4795 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4796 static const WCHAR szInstallLocation[] =
4797 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4798 static const WCHAR szManufacturer[] =
4799 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4800 static const WCHAR szPublisher[] =
4801 {'P','u','b','l','i','s','h','e','r',0};
4802 static const WCHAR szARPREADME[] =
4803 {'A','R','P','R','E','A','D','M','E',0};
4804 static const WCHAR szReadme[] =
4805 {'R','e','a','d','M','e',0};
4806 static const WCHAR szARPSIZE[] =
4807 {'A','R','P','S','I','Z','E',0};
4808 static const WCHAR szSize[] =
4809 {'S','i','z','e',0};
4810 static const WCHAR szARPURLINFOABOUT[] =
4811 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4812 static const WCHAR szURLInfoAbout[] =
4813 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4814 static const WCHAR szARPURLUPDATEINFO[] =
4815 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4816 static const WCHAR szURLUpdateInfo[] =
4817 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4818 static const WCHAR szARPSYSTEMCOMPONENT[] =
4819 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4820 static const WCHAR szSystemComponent[] =
4821 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4823 static const WCHAR *propval[] = {
4824 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4825 szARPCONTACT, szContact,
4826 szARPCOMMENTS, szComments,
4827 szProductName, szDisplayName,
4828 szARPHELPLINK, szHelpLink,
4829 szARPHELPTELEPHONE, szHelpTelephone,
4830 szARPINSTALLLOCATION, szInstallLocation,
4831 szSourceDir, szInstallSource,
4832 szManufacturer, szPublisher,
4833 szARPREADME, szReadme,
4835 szARPURLINFOABOUT, szURLInfoAbout,
4836 szARPURLUPDATEINFO, szURLUpdateInfo,
4839 const WCHAR **p = propval;
4845 val = msi_dup_property(package->db, prop);
4846 msi_reg_set_val_str(hkey, key, val);
4850 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4851 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4853 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4855 size = deformat_string(package, modpath_fmt, &buffer);
4856 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4857 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4860 /* FIXME: Write real Estimated Size when we have it */
4861 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4863 GetLocalTime(&systime);
4864 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4865 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4867 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4868 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4870 buffer = msi_dup_property(package->db, szProductVersion);
4871 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4874 DWORD verdword = msi_version_str_to_dword(buffer);
4876 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4877 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4878 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4882 return ERROR_SUCCESS;
4885 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4887 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4889 LPWSTR upgrade_code;
4890 HKEY hkey, props, upgrade_key;
4893 /* FIXME: also need to publish if the product is in advertise mode */
4894 if (!msi_check_publish(package))
4895 return ERROR_SUCCESS;
4897 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4898 if (rc != ERROR_SUCCESS)
4901 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4902 NULL, &props, TRUE);
4903 if (rc != ERROR_SUCCESS)
4906 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4907 msi_free( package->db->localfile );
4908 package->db->localfile = NULL;
4910 rc = msi_publish_install_properties(package, hkey);
4911 if (rc != ERROR_SUCCESS)
4914 rc = msi_publish_install_properties(package, props);
4915 if (rc != ERROR_SUCCESS)
4918 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4921 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4922 if (rc == ERROR_SUCCESS)
4924 squash_guid( package->ProductCode, squashed_pc );
4925 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4926 RegCloseKey( upgrade_key );
4928 msi_free( upgrade_code );
4932 uirow = MSI_CreateRecord( 1 );
4933 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4934 msi_ui_actiondata( package, szRegisterProduct, uirow );
4935 msiobj_release( &uirow->hdr );
4938 return ERROR_SUCCESS;
4941 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4943 return execute_script(package,INSTALL_SCRIPT);
4946 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4948 WCHAR *upgrade, **features;
4949 BOOL full_uninstall = TRUE;
4950 MSIFEATURE *feature;
4951 MSIPATCHINFO *patch;
4953 static const WCHAR szUpgradeCode[] =
4954 {'U','p','g','r','a','d','e','C','o','d','e',0};
4956 features = msi_split_string(remove, ',');
4959 ERR("REMOVE feature list is empty!\n");
4960 return ERROR_FUNCTION_FAILED;
4963 if (!strcmpW( features[0], szAll ))
4964 full_uninstall = TRUE;
4967 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4969 if (feature->Action != INSTALLSTATE_ABSENT)
4970 full_uninstall = FALSE;
4975 if (!full_uninstall)
4976 return ERROR_SUCCESS;
4978 MSIREG_DeleteProductKey(package->ProductCode);
4979 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4980 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4982 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4983 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4984 MSIREG_DeleteUserProductKey(package->ProductCode);
4985 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4987 upgrade = msi_dup_property(package->db, szUpgradeCode);
4990 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4991 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4995 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4997 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5000 return ERROR_SUCCESS;
5003 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5008 /* turn off scheduling */
5009 package->script->CurrentlyScripting= FALSE;
5011 /* first do the same as an InstallExecute */
5012 rc = ACTION_InstallExecute(package);
5013 if (rc != ERROR_SUCCESS)
5016 /* then handle Commit Actions */
5017 rc = execute_script(package,COMMIT_SCRIPT);
5018 if (rc != ERROR_SUCCESS)
5021 remove = msi_dup_property(package->db, szRemove);
5023 rc = msi_unpublish_product(package, remove);
5029 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5031 static const WCHAR RunOnce[] = {
5032 'S','o','f','t','w','a','r','e','\\',
5033 'M','i','c','r','o','s','o','f','t','\\',
5034 'W','i','n','d','o','w','s','\\',
5035 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5036 'R','u','n','O','n','c','e',0};
5037 static const WCHAR InstallRunOnce[] = {
5038 'S','o','f','t','w','a','r','e','\\',
5039 'M','i','c','r','o','s','o','f','t','\\',
5040 'W','i','n','d','o','w','s','\\',
5041 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5042 'I','n','s','t','a','l','l','e','r','\\',
5043 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5045 static const WCHAR msiexec_fmt[] = {
5047 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5048 '\"','%','s','\"',0};
5049 static const WCHAR install_fmt[] = {
5050 '/','I',' ','\"','%','s','\"',' ',
5051 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5052 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5053 WCHAR buffer[256], sysdir[MAX_PATH];
5055 WCHAR squished_pc[100];
5057 squash_guid(package->ProductCode,squished_pc);
5059 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5060 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5061 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5064 msi_reg_set_val_str( hkey, squished_pc, buffer );
5067 TRACE("Reboot command %s\n",debugstr_w(buffer));
5069 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5070 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5072 msi_reg_set_val_str( hkey, squished_pc, buffer );
5075 return ERROR_INSTALL_SUSPEND;
5078 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5080 static const WCHAR query[] =
5081 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5082 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5083 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5084 MSIRECORD *rec, *row;
5090 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5092 rec = MSI_CreateRecord( count + 2 );
5093 str = MSI_RecordGetString( row, 1 );
5094 MSI_RecordSetStringW( rec, 0, str );
5095 msiobj_release( &row->hdr );
5096 MSI_RecordSetInteger( rec, 1, error );
5098 va_start( va, count );
5099 for (i = 0; i < count; i++)
5101 str = va_arg( va, const WCHAR *);
5102 MSI_RecordSetStringW( rec, i + 2, str );
5106 MSI_FormatRecordW( package, rec, NULL, &size );
5108 data = msi_alloc( size * sizeof(WCHAR) );
5109 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5111 msiobj_release( &rec->hdr );
5115 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5121 * We are currently doing what should be done here in the top level Install
5122 * however for Administrative and uninstalls this step will be needed
5124 if (!package->PackagePath)
5125 return ERROR_SUCCESS;
5127 msi_set_sourcedir_props(package, TRUE);
5129 attrib = GetFileAttributesW(package->db->path);
5130 if (attrib == INVALID_FILE_ATTRIBUTES)
5136 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5137 package->Context, MSICODE_PRODUCT,
5138 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5139 if (rc == ERROR_MORE_DATA)
5141 prompt = msi_alloc(size * sizeof(WCHAR));
5142 MsiSourceListGetInfoW(package->ProductCode, NULL,
5143 package->Context, MSICODE_PRODUCT,
5144 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5147 prompt = strdupW(package->db->path);
5149 msg = msi_build_error_string(package, 1302, 1, prompt);
5150 while(attrib == INVALID_FILE_ATTRIBUTES)
5152 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5155 rc = ERROR_INSTALL_USEREXIT;
5158 attrib = GetFileAttributesW(package->db->path);
5164 return ERROR_SUCCESS;
5169 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5172 LPWSTR buffer, productid = NULL;
5173 UINT i, rc = ERROR_SUCCESS;
5176 static const WCHAR szPropKeys[][80] =
5178 {'P','r','o','d','u','c','t','I','D',0},
5179 {'U','S','E','R','N','A','M','E',0},
5180 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5184 static const WCHAR szRegKeys[][80] =
5186 {'P','r','o','d','u','c','t','I','D',0},
5187 {'R','e','g','O','w','n','e','r',0},
5188 {'R','e','g','C','o','m','p','a','n','y',0},
5192 if (msi_check_unpublish(package))
5194 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5198 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5202 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5204 if (rc != ERROR_SUCCESS)
5207 for( i = 0; szPropKeys[i][0]; i++ )
5209 buffer = msi_dup_property( package->db, szPropKeys[i] );
5210 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5215 uirow = MSI_CreateRecord( 1 );
5216 MSI_RecordSetStringW( uirow, 1, productid );
5217 msi_ui_actiondata( package, szRegisterUser, uirow );
5218 msiobj_release( &uirow->hdr );
5220 msi_free(productid);
5226 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5230 package->script->InWhatSequence |= SEQUENCE_EXEC;
5231 rc = ACTION_ProcessExecSequence(package,FALSE);
5235 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5237 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5238 WCHAR productid_85[21], component_85[21], *ret;
5242 /* > is used if there is a component GUID and < if not. */
5244 productid_85[0] = 0;
5245 component_85[0] = 0;
5246 CLSIDFromString( package->ProductCode, &clsid );
5248 encode_base85_guid( &clsid, productid_85 );
5251 CLSIDFromString( component->ComponentId, &clsid );
5252 encode_base85_guid( &clsid, component_85 );
5255 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5256 debugstr_w(component_85));
5258 sz = 20 + strlenW( feature ) + 20 + 3;
5259 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5260 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5264 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5266 MSIPACKAGE *package = param;
5267 LPCWSTR compgroupid, component, feature, qualifier, text;
5268 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5277 feature = MSI_RecordGetString(rec, 5);
5278 feat = msi_get_loaded_feature(package, feature);
5280 return ERROR_SUCCESS;
5282 feat->Action = msi_get_feature_action( package, feat );
5283 if (feat->Action != INSTALLSTATE_LOCAL &&
5284 feat->Action != INSTALLSTATE_SOURCE &&
5285 feat->Action != INSTALLSTATE_ADVERTISED)
5287 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5288 return ERROR_SUCCESS;
5291 component = MSI_RecordGetString(rec, 3);
5292 comp = msi_get_loaded_component(package, component);
5294 return ERROR_SUCCESS;
5296 compgroupid = MSI_RecordGetString(rec,1);
5297 qualifier = MSI_RecordGetString(rec,2);
5299 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5300 if (rc != ERROR_SUCCESS)
5303 advertise = msi_create_component_advertise_string( package, comp, feature );
5304 text = MSI_RecordGetString( rec, 4 );
5307 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5308 strcpyW( p, advertise );
5310 msi_free( advertise );
5313 existing = msi_reg_get_val_str( hkey, qualifier );
5315 sz = strlenW( advertise ) + 1;
5318 for (p = existing; *p; p += len)
5320 len = strlenW( p ) + 1;
5321 if (strcmpW( advertise, p )) sz += len;
5324 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5326 rc = ERROR_OUTOFMEMORY;
5332 for (p = existing; *p; p += len)
5334 len = strlenW( p ) + 1;
5335 if (strcmpW( advertise, p ))
5337 memcpy( q, p, len * sizeof(WCHAR) );
5342 strcpyW( q, advertise );
5343 q[strlenW( q ) + 1] = 0;
5345 msi_reg_set_val_multi_str( hkey, qualifier, output );
5350 msi_free( advertise );
5351 msi_free( existing );
5354 uirow = MSI_CreateRecord( 2 );
5355 MSI_RecordSetStringW( uirow, 1, compgroupid );
5356 MSI_RecordSetStringW( uirow, 2, qualifier);
5357 msi_ui_actiondata( package, szPublishComponents, uirow );
5358 msiobj_release( &uirow->hdr );
5359 /* FIXME: call ui_progress? */
5365 * At present I am ignorning the advertised components part of this and only
5366 * focusing on the qualified component sets
5368 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5372 static const WCHAR ExecSeqQuery[] =
5373 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5374 '`','P','u','b','l','i','s','h',
5375 'C','o','m','p','o','n','e','n','t','`',0};
5377 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5378 if (rc != ERROR_SUCCESS)
5379 return ERROR_SUCCESS;
5381 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5382 msiobj_release(&view->hdr);
5387 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5389 static const WCHAR szInstallerComponents[] = {
5390 'S','o','f','t','w','a','r','e','\\',
5391 'M','i','c','r','o','s','o','f','t','\\',
5392 'I','n','s','t','a','l','l','e','r','\\',
5393 'C','o','m','p','o','n','e','n','t','s','\\',0};
5395 MSIPACKAGE *package = param;
5396 LPCWSTR compgroupid, component, feature, qualifier;
5400 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5403 feature = MSI_RecordGetString( rec, 5 );
5404 feat = msi_get_loaded_feature( package, feature );
5406 return ERROR_SUCCESS;
5408 feat->Action = msi_get_feature_action( package, feat );
5409 if (feat->Action != INSTALLSTATE_ABSENT)
5411 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5412 return ERROR_SUCCESS;
5415 component = MSI_RecordGetString( rec, 3 );
5416 comp = msi_get_loaded_component( package, component );
5418 return ERROR_SUCCESS;
5420 compgroupid = MSI_RecordGetString( rec, 1 );
5421 qualifier = MSI_RecordGetString( rec, 2 );
5423 squash_guid( compgroupid, squashed );
5424 strcpyW( keypath, szInstallerComponents );
5425 strcatW( keypath, squashed );
5427 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5428 if (res != ERROR_SUCCESS)
5430 WARN("Unable to delete component key %d\n", res);
5433 uirow = MSI_CreateRecord( 2 );
5434 MSI_RecordSetStringW( uirow, 1, compgroupid );
5435 MSI_RecordSetStringW( uirow, 2, qualifier );
5436 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5437 msiobj_release( &uirow->hdr );
5439 return ERROR_SUCCESS;
5442 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5446 static const WCHAR query[] =
5447 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5448 '`','P','u','b','l','i','s','h',
5449 'C','o','m','p','o','n','e','n','t','`',0};
5451 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5452 if (rc != ERROR_SUCCESS)
5453 return ERROR_SUCCESS;
5455 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5456 msiobj_release( &view->hdr );
5461 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5463 static const WCHAR query[] =
5464 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5465 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5466 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5467 MSIPACKAGE *package = param;
5468 MSICOMPONENT *component;
5471 SC_HANDLE hscm = NULL, service = NULL;
5473 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5474 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5475 DWORD serv_type, start_type, err_control;
5476 SERVICE_DESCRIPTIONW sd = {NULL};
5478 comp = MSI_RecordGetString( rec, 12 );
5479 component = msi_get_loaded_component( package, comp );
5482 WARN("service component not found\n");
5485 component->Action = msi_get_component_action( package, component );
5486 if (component->Action != INSTALLSTATE_LOCAL)
5488 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5491 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5494 ERR("Failed to open the SC Manager!\n");
5498 start_type = MSI_RecordGetInteger(rec, 5);
5499 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5502 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5503 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5504 serv_type = MSI_RecordGetInteger(rec, 4);
5505 err_control = MSI_RecordGetInteger(rec, 6);
5506 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5507 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5508 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5509 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5510 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5511 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5513 /* fetch the service path */
5514 row = MSI_QueryGetRecord(package->db, query, comp);
5517 ERR("Query failed\n");
5520 key = MSI_RecordGetString(row, 6);
5521 file = msi_get_loaded_file(package, key);
5522 msiobj_release(&row->hdr);
5525 ERR("Failed to load the service file\n");
5529 if (!args || !args[0]) image_path = file->TargetPath;
5532 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5533 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5534 return ERROR_OUTOFMEMORY;
5536 strcpyW(image_path, file->TargetPath);
5537 strcatW(image_path, szSpace);
5538 strcatW(image_path, args);
5540 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5541 start_type, err_control, image_path, load_order,
5542 NULL, depends, serv_name, pass);
5546 if (GetLastError() != ERROR_SERVICE_EXISTS)
5547 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5549 else if (sd.lpDescription)
5551 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5552 WARN("failed to set service description %u\n", GetLastError());
5555 if (image_path != file->TargetPath) msi_free(image_path);
5557 CloseServiceHandle(service);
5558 CloseServiceHandle(hscm);
5561 msi_free(sd.lpDescription);
5562 msi_free(load_order);
5563 msi_free(serv_name);
5568 return ERROR_SUCCESS;
5571 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5575 static const WCHAR ExecSeqQuery[] =
5576 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5577 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5579 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5580 if (rc != ERROR_SUCCESS)
5581 return ERROR_SUCCESS;
5583 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5584 msiobj_release(&view->hdr);
5589 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5590 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5592 LPCWSTR *vector, *temp_vector;
5596 static const WCHAR separator[] = {'[','~',']',0};
5599 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5604 vector = msi_alloc(sizeof(LPWSTR));
5612 vector[*numargs - 1] = p;
5614 if ((q = strstrW(p, separator)))
5618 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5624 vector = temp_vector;
5633 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5635 MSIPACKAGE *package = param;
5638 SC_HANDLE scm = NULL, service = NULL;
5639 LPCWSTR component, *vector = NULL;
5640 LPWSTR name, args, display_name = NULL;
5641 DWORD event, numargs, len;
5642 UINT r = ERROR_FUNCTION_FAILED;
5644 component = MSI_RecordGetString(rec, 6);
5645 comp = msi_get_loaded_component(package, component);
5647 return ERROR_SUCCESS;
5649 comp->Action = msi_get_component_action( package, comp );
5650 if (comp->Action != INSTALLSTATE_LOCAL)
5652 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5653 return ERROR_SUCCESS;
5656 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5657 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5658 event = MSI_RecordGetInteger(rec, 3);
5660 if (!(event & msidbServiceControlEventStart))
5666 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5669 ERR("Failed to open the service control manager\n");
5674 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5675 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5677 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5678 GetServiceDisplayNameW( scm, name, display_name, &len );
5681 service = OpenServiceW(scm, name, SERVICE_START);
5684 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5688 vector = msi_service_args_to_vector(args, &numargs);
5690 if (!StartServiceW(service, numargs, vector) &&
5691 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5693 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5700 uirow = MSI_CreateRecord( 2 );
5701 MSI_RecordSetStringW( uirow, 1, display_name );
5702 MSI_RecordSetStringW( uirow, 2, name );
5703 msi_ui_actiondata( package, szStartServices, uirow );
5704 msiobj_release( &uirow->hdr );
5706 CloseServiceHandle(service);
5707 CloseServiceHandle(scm);
5712 msi_free(display_name);
5716 static UINT ACTION_StartServices( MSIPACKAGE *package )
5721 static const WCHAR query[] = {
5722 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5723 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5725 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5726 if (rc != ERROR_SUCCESS)
5727 return ERROR_SUCCESS;
5729 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5730 msiobj_release(&view->hdr);
5735 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5737 DWORD i, needed, count;
5738 ENUM_SERVICE_STATUSW *dependencies;
5742 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5743 0, &needed, &count))
5746 if (GetLastError() != ERROR_MORE_DATA)
5749 dependencies = msi_alloc(needed);
5753 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5754 needed, &needed, &count))
5757 for (i = 0; i < count; i++)
5759 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5760 SERVICE_STOP | SERVICE_QUERY_STATUS);
5764 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5771 msi_free(dependencies);
5775 static UINT stop_service( LPCWSTR name )
5777 SC_HANDLE scm = NULL, service = NULL;
5778 SERVICE_STATUS status;
5779 SERVICE_STATUS_PROCESS ssp;
5782 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5785 WARN("Failed to open the SCM: %d\n", GetLastError());
5789 service = OpenServiceW(scm, name,
5791 SERVICE_QUERY_STATUS |
5792 SERVICE_ENUMERATE_DEPENDENTS);
5795 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5799 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5800 sizeof(SERVICE_STATUS_PROCESS), &needed))
5802 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5806 if (ssp.dwCurrentState == SERVICE_STOPPED)
5809 stop_service_dependents(scm, service);
5811 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5812 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5815 CloseServiceHandle(service);
5816 CloseServiceHandle(scm);
5818 return ERROR_SUCCESS;
5821 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5823 MSIPACKAGE *package = param;
5827 LPWSTR name = NULL, display_name = NULL;
5831 event = MSI_RecordGetInteger( rec, 3 );
5832 if (!(event & msidbServiceControlEventStop))
5833 return ERROR_SUCCESS;
5835 component = MSI_RecordGetString( rec, 6 );
5836 comp = msi_get_loaded_component( package, component );
5838 return ERROR_SUCCESS;
5840 comp->Action = msi_get_component_action( package, comp );
5841 if (comp->Action != INSTALLSTATE_ABSENT)
5843 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5844 return ERROR_SUCCESS;
5847 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5850 ERR("Failed to open the service control manager\n");
5855 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5856 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5858 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5859 GetServiceDisplayNameW( scm, name, display_name, &len );
5861 CloseServiceHandle( scm );
5863 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5864 stop_service( name );
5867 uirow = MSI_CreateRecord( 2 );
5868 MSI_RecordSetStringW( uirow, 1, display_name );
5869 MSI_RecordSetStringW( uirow, 2, name );
5870 msi_ui_actiondata( package, szStopServices, uirow );
5871 msiobj_release( &uirow->hdr );
5874 msi_free( display_name );
5875 return ERROR_SUCCESS;
5878 static UINT ACTION_StopServices( MSIPACKAGE *package )
5883 static const WCHAR query[] = {
5884 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5885 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5887 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5888 if (rc != ERROR_SUCCESS)
5889 return ERROR_SUCCESS;
5891 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5892 msiobj_release(&view->hdr);
5897 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5899 MSIPACKAGE *package = param;
5903 LPWSTR name = NULL, display_name = NULL;
5905 SC_HANDLE scm = NULL, service = NULL;
5907 event = MSI_RecordGetInteger( rec, 3 );
5908 if (!(event & msidbServiceControlEventDelete))
5909 return ERROR_SUCCESS;
5911 component = MSI_RecordGetString(rec, 6);
5912 comp = msi_get_loaded_component(package, component);
5914 return ERROR_SUCCESS;
5916 comp->Action = msi_get_component_action( package, comp );
5917 if (comp->Action != INSTALLSTATE_ABSENT)
5919 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5920 return ERROR_SUCCESS;
5923 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5924 stop_service( name );
5926 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5929 WARN("Failed to open the SCM: %d\n", GetLastError());
5934 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5935 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5937 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5938 GetServiceDisplayNameW( scm, name, display_name, &len );
5941 service = OpenServiceW( scm, name, DELETE );
5944 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5948 if (!DeleteService( service ))
5949 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5952 uirow = MSI_CreateRecord( 2 );
5953 MSI_RecordSetStringW( uirow, 1, display_name );
5954 MSI_RecordSetStringW( uirow, 2, name );
5955 msi_ui_actiondata( package, szDeleteServices, uirow );
5956 msiobj_release( &uirow->hdr );
5958 CloseServiceHandle( service );
5959 CloseServiceHandle( scm );
5961 msi_free( display_name );
5963 return ERROR_SUCCESS;
5966 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5971 static const WCHAR query[] = {
5972 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5973 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5975 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5976 if (rc != ERROR_SUCCESS)
5977 return ERROR_SUCCESS;
5979 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5980 msiobj_release( &view->hdr );
5985 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5987 MSIPACKAGE *package = param;
5988 LPWSTR driver, driver_path, ptr;
5989 WCHAR outpath[MAX_PATH];
5990 MSIFILE *driver_file = NULL, *setup_file = NULL;
5993 LPCWSTR desc, file_key, component;
5995 UINT r = ERROR_SUCCESS;
5997 static const WCHAR driver_fmt[] = {
5998 'D','r','i','v','e','r','=','%','s',0};
5999 static const WCHAR setup_fmt[] = {
6000 'S','e','t','u','p','=','%','s',0};
6001 static const WCHAR usage_fmt[] = {
6002 'F','i','l','e','U','s','a','g','e','=','1',0};
6004 component = MSI_RecordGetString( rec, 2 );
6005 comp = msi_get_loaded_component( package, component );
6007 return ERROR_SUCCESS;
6009 comp->Action = msi_get_component_action( package, comp );
6010 if (comp->Action != INSTALLSTATE_LOCAL)
6012 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6013 return ERROR_SUCCESS;
6015 desc = MSI_RecordGetString(rec, 3);
6017 file_key = MSI_RecordGetString( rec, 4 );
6018 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6020 file_key = MSI_RecordGetString( rec, 5 );
6021 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6025 ERR("ODBC Driver entry not found!\n");
6026 return ERROR_FUNCTION_FAILED;
6029 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6031 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6032 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6034 driver = msi_alloc(len * sizeof(WCHAR));
6036 return ERROR_OUTOFMEMORY;
6039 lstrcpyW(ptr, desc);
6040 ptr += lstrlenW(ptr) + 1;
6042 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6047 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6051 lstrcpyW(ptr, usage_fmt);
6052 ptr += lstrlenW(ptr) + 1;
6055 driver_path = strdupW(driver_file->TargetPath);
6056 ptr = strrchrW(driver_path, '\\');
6057 if (ptr) *ptr = '\0';
6059 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6060 NULL, ODBC_INSTALL_COMPLETE, &usage))
6062 ERR("Failed to install SQL driver!\n");
6063 r = ERROR_FUNCTION_FAILED;
6066 uirow = MSI_CreateRecord( 5 );
6067 MSI_RecordSetStringW( uirow, 1, desc );
6068 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6069 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6070 msi_ui_actiondata( package, szInstallODBC, uirow );
6071 msiobj_release( &uirow->hdr );
6074 msi_free(driver_path);
6079 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6081 MSIPACKAGE *package = param;
6082 LPWSTR translator, translator_path, ptr;
6083 WCHAR outpath[MAX_PATH];
6084 MSIFILE *translator_file = NULL, *setup_file = NULL;
6087 LPCWSTR desc, file_key, component;
6089 UINT r = ERROR_SUCCESS;
6091 static const WCHAR translator_fmt[] = {
6092 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6093 static const WCHAR setup_fmt[] = {
6094 'S','e','t','u','p','=','%','s',0};
6096 component = MSI_RecordGetString( rec, 2 );
6097 comp = msi_get_loaded_component( package, component );
6099 return ERROR_SUCCESS;
6101 comp->Action = msi_get_component_action( package, comp );
6102 if (comp->Action != INSTALLSTATE_LOCAL)
6104 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6105 return ERROR_SUCCESS;
6107 desc = MSI_RecordGetString(rec, 3);
6109 file_key = MSI_RecordGetString( rec, 4 );
6110 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6112 file_key = MSI_RecordGetString( rec, 5 );
6113 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6115 if (!translator_file)
6117 ERR("ODBC Translator entry not found!\n");
6118 return ERROR_FUNCTION_FAILED;
6121 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6123 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6125 translator = msi_alloc(len * sizeof(WCHAR));
6127 return ERROR_OUTOFMEMORY;
6130 lstrcpyW(ptr, desc);
6131 ptr += lstrlenW(ptr) + 1;
6133 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6138 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6143 translator_path = strdupW(translator_file->TargetPath);
6144 ptr = strrchrW(translator_path, '\\');
6145 if (ptr) *ptr = '\0';
6147 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6148 NULL, ODBC_INSTALL_COMPLETE, &usage))
6150 ERR("Failed to install SQL translator!\n");
6151 r = ERROR_FUNCTION_FAILED;
6154 uirow = MSI_CreateRecord( 5 );
6155 MSI_RecordSetStringW( uirow, 1, desc );
6156 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6157 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6158 msi_ui_actiondata( package, szInstallODBC, uirow );
6159 msiobj_release( &uirow->hdr );
6161 msi_free(translator);
6162 msi_free(translator_path);
6167 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6169 MSIPACKAGE *package = param;
6172 LPCWSTR desc, driver, component;
6173 WORD request = ODBC_ADD_SYS_DSN;
6176 UINT r = ERROR_SUCCESS;
6179 static const WCHAR attrs_fmt[] = {
6180 'D','S','N','=','%','s',0 };
6182 component = MSI_RecordGetString( rec, 2 );
6183 comp = msi_get_loaded_component( package, component );
6185 return ERROR_SUCCESS;
6187 comp->Action = msi_get_component_action( package, comp );
6188 if (comp->Action != INSTALLSTATE_LOCAL)
6190 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6191 return ERROR_SUCCESS;
6194 desc = MSI_RecordGetString(rec, 3);
6195 driver = MSI_RecordGetString(rec, 4);
6196 registration = MSI_RecordGetInteger(rec, 5);
6198 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6199 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6201 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6202 attrs = msi_alloc(len * sizeof(WCHAR));
6204 return ERROR_OUTOFMEMORY;
6206 len = sprintfW(attrs, attrs_fmt, desc);
6209 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6211 ERR("Failed to install SQL data source!\n");
6212 r = ERROR_FUNCTION_FAILED;
6215 uirow = MSI_CreateRecord( 5 );
6216 MSI_RecordSetStringW( uirow, 1, desc );
6217 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6218 MSI_RecordSetInteger( uirow, 3, request );
6219 msi_ui_actiondata( package, szInstallODBC, uirow );
6220 msiobj_release( &uirow->hdr );
6227 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6232 static const WCHAR driver_query[] = {
6233 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6234 'O','D','B','C','D','r','i','v','e','r',0 };
6236 static const WCHAR translator_query[] = {
6237 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6238 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6240 static const WCHAR source_query[] = {
6241 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6242 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6244 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6245 if (rc != ERROR_SUCCESS)
6246 return ERROR_SUCCESS;
6248 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6249 msiobj_release(&view->hdr);
6251 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6252 if (rc != ERROR_SUCCESS)
6253 return ERROR_SUCCESS;
6255 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6256 msiobj_release(&view->hdr);
6258 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6259 if (rc != ERROR_SUCCESS)
6260 return ERROR_SUCCESS;
6262 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6263 msiobj_release(&view->hdr);
6268 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6270 MSIPACKAGE *package = param;
6274 LPCWSTR desc, component;
6276 component = MSI_RecordGetString( rec, 2 );
6277 comp = msi_get_loaded_component( package, component );
6279 return ERROR_SUCCESS;
6281 comp->Action = msi_get_component_action( package, comp );
6282 if (comp->Action != INSTALLSTATE_ABSENT)
6284 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6285 return ERROR_SUCCESS;
6288 desc = MSI_RecordGetString( rec, 3 );
6289 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6291 WARN("Failed to remove ODBC driver\n");
6295 FIXME("Usage count reached 0\n");
6298 uirow = MSI_CreateRecord( 2 );
6299 MSI_RecordSetStringW( uirow, 1, desc );
6300 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6301 msi_ui_actiondata( package, szRemoveODBC, uirow );
6302 msiobj_release( &uirow->hdr );
6304 return ERROR_SUCCESS;
6307 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6309 MSIPACKAGE *package = param;
6313 LPCWSTR desc, component;
6315 component = MSI_RecordGetString( rec, 2 );
6316 comp = msi_get_loaded_component( package, component );
6318 return ERROR_SUCCESS;
6320 comp->Action = msi_get_component_action( package, comp );
6321 if (comp->Action != INSTALLSTATE_ABSENT)
6323 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6324 return ERROR_SUCCESS;
6327 desc = MSI_RecordGetString( rec, 3 );
6328 if (!SQLRemoveTranslatorW( desc, &usage ))
6330 WARN("Failed to remove ODBC translator\n");
6334 FIXME("Usage count reached 0\n");
6337 uirow = MSI_CreateRecord( 2 );
6338 MSI_RecordSetStringW( uirow, 1, desc );
6339 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6340 msi_ui_actiondata( package, szRemoveODBC, uirow );
6341 msiobj_release( &uirow->hdr );
6343 return ERROR_SUCCESS;
6346 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6348 MSIPACKAGE *package = param;
6352 LPCWSTR desc, driver, component;
6353 WORD request = ODBC_REMOVE_SYS_DSN;
6357 static const WCHAR attrs_fmt[] = {
6358 'D','S','N','=','%','s',0 };
6360 component = MSI_RecordGetString( rec, 2 );
6361 comp = msi_get_loaded_component( package, component );
6363 return ERROR_SUCCESS;
6365 comp->Action = msi_get_component_action( package, comp );
6366 if (comp->Action != INSTALLSTATE_ABSENT)
6368 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6369 return ERROR_SUCCESS;
6372 desc = MSI_RecordGetString( rec, 3 );
6373 driver = MSI_RecordGetString( rec, 4 );
6374 registration = MSI_RecordGetInteger( rec, 5 );
6376 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6377 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6379 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6380 attrs = msi_alloc( len * sizeof(WCHAR) );
6382 return ERROR_OUTOFMEMORY;
6384 FIXME("Use ODBCSourceAttribute table\n");
6386 len = sprintfW( attrs, attrs_fmt, desc );
6389 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6391 WARN("Failed to remove ODBC data source\n");
6395 uirow = MSI_CreateRecord( 3 );
6396 MSI_RecordSetStringW( uirow, 1, desc );
6397 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6398 MSI_RecordSetInteger( uirow, 3, request );
6399 msi_ui_actiondata( package, szRemoveODBC, uirow );
6400 msiobj_release( &uirow->hdr );
6402 return ERROR_SUCCESS;
6405 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6410 static const WCHAR driver_query[] = {
6411 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6412 'O','D','B','C','D','r','i','v','e','r',0 };
6414 static const WCHAR translator_query[] = {
6415 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6416 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6418 static const WCHAR source_query[] = {
6419 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6420 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6422 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6423 if (rc != ERROR_SUCCESS)
6424 return ERROR_SUCCESS;
6426 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6427 msiobj_release( &view->hdr );
6429 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6430 if (rc != ERROR_SUCCESS)
6431 return ERROR_SUCCESS;
6433 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6434 msiobj_release( &view->hdr );
6436 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6437 if (rc != ERROR_SUCCESS)
6438 return ERROR_SUCCESS;
6440 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6441 msiobj_release( &view->hdr );
6446 #define ENV_ACT_SETALWAYS 0x1
6447 #define ENV_ACT_SETABSENT 0x2
6448 #define ENV_ACT_REMOVE 0x4
6449 #define ENV_ACT_REMOVEMATCH 0x8
6451 #define ENV_MOD_MACHINE 0x20000000
6452 #define ENV_MOD_APPEND 0x40000000
6453 #define ENV_MOD_PREFIX 0x80000000
6454 #define ENV_MOD_MASK 0xC0000000
6456 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6458 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6460 LPCWSTR cptr = *name;
6462 static const WCHAR prefix[] = {'[','~',']',0};
6463 static const int prefix_len = 3;
6469 *flags |= ENV_ACT_SETALWAYS;
6470 else if (*cptr == '+')
6471 *flags |= ENV_ACT_SETABSENT;
6472 else if (*cptr == '-')
6473 *flags |= ENV_ACT_REMOVE;
6474 else if (*cptr == '!')
6475 *flags |= ENV_ACT_REMOVEMATCH;
6476 else if (*cptr == '*')
6477 *flags |= ENV_MOD_MACHINE;
6487 ERR("Missing environment variable\n");
6488 return ERROR_FUNCTION_FAILED;
6493 LPCWSTR ptr = *value;
6494 if (!strncmpW(ptr, prefix, prefix_len))
6496 if (ptr[prefix_len] == szSemiColon[0])
6498 *flags |= ENV_MOD_APPEND;
6499 *value += lstrlenW(prefix);
6506 else if (lstrlenW(*value) >= prefix_len)
6508 ptr += lstrlenW(ptr) - prefix_len;
6509 if (!strcmpW( ptr, prefix ))
6511 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6513 *flags |= ENV_MOD_PREFIX;
6514 /* the "[~]" will be removed by deformat_string */;
6524 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6525 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6526 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6527 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6529 ERR("Invalid flags: %08x\n", *flags);
6530 return ERROR_FUNCTION_FAILED;
6534 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6536 return ERROR_SUCCESS;
6539 static UINT open_env_key( DWORD flags, HKEY *key )
6541 static const WCHAR user_env[] =
6542 {'E','n','v','i','r','o','n','m','e','n','t',0};
6543 static const WCHAR machine_env[] =
6544 {'S','y','s','t','e','m','\\',
6545 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6546 'C','o','n','t','r','o','l','\\',
6547 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6548 'E','n','v','i','r','o','n','m','e','n','t',0};
6553 if (flags & ENV_MOD_MACHINE)
6556 root = HKEY_LOCAL_MACHINE;
6561 root = HKEY_CURRENT_USER;
6564 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6565 if (res != ERROR_SUCCESS)
6567 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6568 return ERROR_FUNCTION_FAILED;
6571 return ERROR_SUCCESS;
6574 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6576 MSIPACKAGE *package = param;
6577 LPCWSTR name, value, component;
6578 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6579 DWORD flags, type, size;
6586 component = MSI_RecordGetString(rec, 4);
6587 comp = msi_get_loaded_component(package, component);
6589 return ERROR_SUCCESS;
6591 comp->Action = msi_get_component_action( package, comp );
6592 if (comp->Action != INSTALLSTATE_LOCAL)
6594 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6595 return ERROR_SUCCESS;
6597 name = MSI_RecordGetString(rec, 2);
6598 value = MSI_RecordGetString(rec, 3);
6600 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6602 res = env_parse_flags(&name, &value, &flags);
6603 if (res != ERROR_SUCCESS || !value)
6606 if (value && !deformat_string(package, value, &deformatted))
6608 res = ERROR_OUTOFMEMORY;
6612 value = deformatted;
6614 res = open_env_key( flags, &env );
6615 if (res != ERROR_SUCCESS)
6618 if (flags & ENV_MOD_MACHINE)
6619 action |= 0x20000000;
6623 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6624 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6625 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6628 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6632 /* Nothing to do. */
6635 res = ERROR_SUCCESS;
6639 /* If we are appending but the string was empty, strip ; */
6640 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6642 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6643 newval = strdupW(value);
6646 res = ERROR_OUTOFMEMORY;
6654 /* Contrary to MSDN, +-variable to [~];path works */
6655 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6657 res = ERROR_SUCCESS;
6661 data = msi_alloc(size);
6665 return ERROR_OUTOFMEMORY;
6668 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6669 if (res != ERROR_SUCCESS)
6672 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6675 res = RegDeleteValueW(env, name);
6676 if (res != ERROR_SUCCESS)
6677 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6681 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6682 if (flags & ENV_MOD_MASK)
6686 if (flags & ENV_MOD_APPEND) multiplier++;
6687 if (flags & ENV_MOD_PREFIX) multiplier++;
6688 mod_size = lstrlenW(value) * multiplier;
6689 size += mod_size * sizeof(WCHAR);
6692 newval = msi_alloc(size);
6696 res = ERROR_OUTOFMEMORY;
6700 if (flags & ENV_MOD_PREFIX)
6702 lstrcpyW(newval, value);
6703 ptr = newval + lstrlenW(value);
6704 action |= 0x80000000;
6707 lstrcpyW(ptr, data);
6709 if (flags & ENV_MOD_APPEND)
6711 lstrcatW(newval, value);
6712 action |= 0x40000000;
6715 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6716 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6719 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6723 uirow = MSI_CreateRecord( 3 );
6724 MSI_RecordSetStringW( uirow, 1, name );
6725 MSI_RecordSetStringW( uirow, 2, newval );
6726 MSI_RecordSetInteger( uirow, 3, action );
6727 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6728 msiobj_release( &uirow->hdr );
6730 if (env) RegCloseKey(env);
6731 msi_free(deformatted);
6737 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6741 static const WCHAR ExecSeqQuery[] =
6742 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6743 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6744 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6745 if (rc != ERROR_SUCCESS)
6746 return ERROR_SUCCESS;
6748 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6749 msiobj_release(&view->hdr);
6754 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6756 MSIPACKAGE *package = param;
6757 LPCWSTR name, value, component;
6758 LPWSTR deformatted = NULL;
6767 component = MSI_RecordGetString( rec, 4 );
6768 comp = msi_get_loaded_component( package, component );
6770 return ERROR_SUCCESS;
6772 comp->Action = msi_get_component_action( package, comp );
6773 if (comp->Action != INSTALLSTATE_ABSENT)
6775 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6776 return ERROR_SUCCESS;
6778 name = MSI_RecordGetString( rec, 2 );
6779 value = MSI_RecordGetString( rec, 3 );
6781 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6783 r = env_parse_flags( &name, &value, &flags );
6784 if (r != ERROR_SUCCESS)
6787 if (!(flags & ENV_ACT_REMOVE))
6789 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6790 return ERROR_SUCCESS;
6793 if (value && !deformat_string( package, value, &deformatted ))
6794 return ERROR_OUTOFMEMORY;
6796 value = deformatted;
6798 r = open_env_key( flags, &env );
6799 if (r != ERROR_SUCCESS)
6805 if (flags & ENV_MOD_MACHINE)
6806 action |= 0x20000000;
6808 TRACE("Removing %s\n", debugstr_w(name));
6810 res = RegDeleteValueW( env, name );
6811 if (res != ERROR_SUCCESS)
6813 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6818 uirow = MSI_CreateRecord( 3 );
6819 MSI_RecordSetStringW( uirow, 1, name );
6820 MSI_RecordSetStringW( uirow, 2, value );
6821 MSI_RecordSetInteger( uirow, 3, action );
6822 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6823 msiobj_release( &uirow->hdr );
6825 if (env) RegCloseKey( env );
6826 msi_free( deformatted );
6830 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6834 static const WCHAR query[] =
6835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6836 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6838 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6839 if (rc != ERROR_SUCCESS)
6840 return ERROR_SUCCESS;
6842 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6843 msiobj_release( &view->hdr );
6848 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6850 LPWSTR key, template, id;
6851 UINT r = ERROR_SUCCESS;
6853 id = msi_dup_property( package->db, szProductID );
6857 return ERROR_SUCCESS;
6859 template = msi_dup_property( package->db, szPIDTemplate );
6860 key = msi_dup_property( package->db, szPIDKEY );
6862 if (key && template)
6864 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6865 r = msi_set_property( package->db, szProductID, key );
6867 msi_free( template );
6872 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6875 package->need_reboot = 1;
6876 return ERROR_SUCCESS;
6879 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6881 static const WCHAR szAvailableFreeReg[] =
6882 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6884 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6886 TRACE("%p %d kilobytes\n", package, space);
6888 uirow = MSI_CreateRecord( 1 );
6889 MSI_RecordSetInteger( uirow, 1, space );
6890 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6891 msiobj_release( &uirow->hdr );
6893 return ERROR_SUCCESS;
6896 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6898 TRACE("%p\n", package);
6900 msi_set_property( package->db, szRollbackDisabled, szOne );
6901 return ERROR_SUCCESS;
6904 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6906 FIXME("%p\n", package);
6907 return ERROR_SUCCESS;
6910 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6915 static const WCHAR driver_query[] = {
6916 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6917 'O','D','B','C','D','r','i','v','e','r',0 };
6919 static const WCHAR translator_query[] = {
6920 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6921 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6923 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6924 if (r == ERROR_SUCCESS)
6927 r = MSI_IterateRecords( view, &count, NULL, package );
6928 msiobj_release( &view->hdr );
6929 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6932 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6933 if (r == ERROR_SUCCESS)
6936 r = MSI_IterateRecords( view, &count, NULL, package );
6937 msiobj_release( &view->hdr );
6938 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6941 return ERROR_SUCCESS;
6944 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6946 MSIPACKAGE *package = param;
6947 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6950 if ((value = msi_dup_property( package->db, property )))
6952 FIXME("remove %s\n", debugstr_w(value));
6955 return ERROR_SUCCESS;
6958 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6963 static const WCHAR query[] =
6964 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
6965 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
6967 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6968 if (r == ERROR_SUCCESS)
6970 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6971 msiobj_release( &view->hdr );
6973 return ERROR_SUCCESS;
6976 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6978 MSIPACKAGE *package = param;
6979 int attributes = MSI_RecordGetInteger( rec, 5 );
6981 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6983 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6984 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6985 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6986 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6990 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6992 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6993 if (r != ERROR_SUCCESS)
6994 return ERROR_SUCCESS;
6998 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6999 if (r != ERROR_SUCCESS)
7000 return ERROR_SUCCESS;
7002 RegCloseKey( hkey );
7004 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7005 debugstr_w(upgrade_code), debugstr_w(version_min),
7006 debugstr_w(version_max), debugstr_w(language));
7008 return ERROR_SUCCESS;
7011 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7015 static const WCHAR query[] =
7016 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7018 if (msi_get_property_int( package->db, szInstalled, 0 ))
7020 TRACE("product is installed, skipping action\n");
7021 return ERROR_SUCCESS;
7023 if (msi_get_property_int( package->db, szPreselected, 0 ))
7025 TRACE("Preselected property is set, not migrating feature states\n");
7026 return ERROR_SUCCESS;
7029 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7030 if (r == ERROR_SUCCESS)
7032 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7033 msiobj_release( &view->hdr );
7035 return ERROR_SUCCESS;
7038 static void bind_image( const char *filename, const char *path )
7040 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7042 WARN("failed to bind image %u\n", GetLastError());
7046 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7050 MSIPACKAGE *package = param;
7051 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7052 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7053 char *filenameA, *pathA;
7054 WCHAR *pathW, **path_list;
7056 if (!(file = msi_get_loaded_file( package, key )))
7058 WARN("file %s not found\n", debugstr_w(key));
7059 return ERROR_SUCCESS;
7061 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7062 path_list = msi_split_string( paths, ';' );
7063 if (!path_list) bind_image( filenameA, NULL );
7066 for (i = 0; path_list[i] && path_list[i][0]; i++)
7068 deformat_string( package, path_list[i], &pathW );
7069 if ((pathA = strdupWtoA( pathW )))
7071 bind_image( filenameA, pathA );
7077 msi_free( path_list );
7078 msi_free( filenameA );
7079 return ERROR_SUCCESS;
7082 static UINT ACTION_BindImage( MSIPACKAGE *package )
7086 static const WCHAR query[] =
7087 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','B','i','n','d','I','m','a','g','e',0};
7089 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7090 if (r == ERROR_SUCCESS)
7092 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7093 msiobj_release( &view->hdr );
7095 return ERROR_SUCCESS;
7098 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7099 LPCSTR action, LPCWSTR table )
7101 static const WCHAR query[] = {
7102 'S','E','L','E','C','T',' ','*',' ',
7103 'F','R','O','M',' ','`','%','s','`',0 };
7104 MSIQUERY *view = NULL;
7108 r = MSI_OpenQuery( package->db, &view, query, table );
7109 if (r == ERROR_SUCCESS)
7111 r = MSI_IterateRecords(view, &count, NULL, package);
7112 msiobj_release(&view->hdr);
7116 FIXME("%s -> %u ignored %s table values\n",
7117 action, count, debugstr_w(table));
7119 return ERROR_SUCCESS;
7122 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7124 static const WCHAR table[] = {
7125 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7126 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7129 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7131 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7132 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7135 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7137 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7138 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7141 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7143 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7144 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7147 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7149 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7150 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7155 const WCHAR *action;
7156 UINT (*handler)(MSIPACKAGE *);
7157 const WCHAR *action_rollback;
7161 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7162 { szAppSearch, ACTION_AppSearch, NULL },
7163 { szBindImage, ACTION_BindImage, NULL },
7164 { szCCPSearch, ACTION_CCPSearch, NULL },
7165 { szCostFinalize, ACTION_CostFinalize, NULL },
7166 { szCostInitialize, ACTION_CostInitialize, NULL },
7167 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7168 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7169 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7170 { szDisableRollback, ACTION_DisableRollback, NULL },
7171 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7172 { szExecuteAction, ACTION_ExecuteAction, NULL },
7173 { szFileCost, ACTION_FileCost, NULL },
7174 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7175 { szForceReboot, ACTION_ForceReboot, NULL },
7176 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7177 { szInstallExecute, ACTION_InstallExecute, NULL },
7178 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7179 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7180 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7181 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7182 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7183 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7184 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7185 { szInstallValidate, ACTION_InstallValidate, NULL },
7186 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7187 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7188 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7189 { szMoveFiles, ACTION_MoveFiles, NULL },
7190 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7191 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7192 { szPatchFiles, ACTION_PatchFiles, NULL },
7193 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7194 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7195 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7196 { szPublishProduct, ACTION_PublishProduct, NULL },
7197 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7198 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7199 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7200 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7201 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7202 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7203 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7204 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7205 { szRegisterUser, ACTION_RegisterUser, NULL },
7206 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7207 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7208 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7209 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7210 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7211 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7212 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7213 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7214 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7215 { szResolveSource, ACTION_ResolveSource, NULL },
7216 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7217 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7218 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7219 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7220 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7221 { szStartServices, ACTION_StartServices, szStopServices },
7222 { szStopServices, ACTION_StopServices, szStartServices },
7223 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7224 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7225 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7226 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7227 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7228 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7229 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7230 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7231 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7232 { szValidateProductID, ACTION_ValidateProductID, NULL },
7233 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7234 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7235 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7236 { NULL, NULL, NULL }
7239 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7245 while (StandardActions[i].action != NULL)
7247 if (!strcmpW( StandardActions[i].action, action ))
7249 ui_actionstart( package, action );
7250 if (StandardActions[i].handler)
7252 ui_actioninfo( package, action, TRUE, 0 );
7253 *rc = StandardActions[i].handler( package );
7254 ui_actioninfo( package, action, FALSE, *rc );
7256 if (StandardActions[i].action_rollback && !package->need_rollback)
7258 TRACE("scheduling rollback action\n");
7259 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7264 FIXME("unhandled standard action %s\n", debugstr_w(action));
7265 *rc = ERROR_SUCCESS;
7275 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7277 UINT rc = ERROR_SUCCESS;
7280 TRACE("Performing action (%s)\n", debugstr_w(action));
7282 handled = ACTION_HandleStandardAction(package, action, &rc);
7285 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7289 WARN("unhandled msi action %s\n", debugstr_w(action));
7290 rc = ERROR_FUNCTION_NOT_CALLED;
7296 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7298 UINT rc = ERROR_SUCCESS;
7299 BOOL handled = FALSE;
7301 TRACE("Performing action (%s)\n", debugstr_w(action));
7303 handled = ACTION_HandleStandardAction(package, action, &rc);
7306 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7308 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7313 WARN("unhandled msi action %s\n", debugstr_w(action));
7314 rc = ERROR_FUNCTION_NOT_CALLED;
7320 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7322 UINT rc = ERROR_SUCCESS;
7325 static const WCHAR ExecSeqQuery[] =
7326 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7327 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7328 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7329 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7330 static const WCHAR UISeqQuery[] =
7331 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7332 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7333 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7334 ' ', '=',' ','%','i',0};
7336 if (needs_ui_sequence(package))
7337 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7339 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7343 LPCWSTR action, cond;
7345 TRACE("Running the actions\n");
7347 /* check conditions */
7348 cond = MSI_RecordGetString(row, 2);
7350 /* this is a hack to skip errors in the condition code */
7351 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7353 msiobj_release(&row->hdr);
7354 return ERROR_SUCCESS;
7357 action = MSI_RecordGetString(row, 1);
7360 ERR("failed to fetch action\n");
7361 msiobj_release(&row->hdr);
7362 return ERROR_FUNCTION_FAILED;
7365 if (needs_ui_sequence(package))
7366 rc = ACTION_PerformUIAction(package, action, -1);
7368 rc = ACTION_PerformAction(package, action, -1);
7370 msiobj_release(&row->hdr);
7376 /****************************************************
7377 * TOP level entry points
7378 *****************************************************/
7380 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7381 LPCWSTR szCommandLine )
7385 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7386 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7387 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7389 msi_set_property( package->db, szAction, szInstall );
7391 package->script->InWhatSequence = SEQUENCE_INSTALL;
7398 dir = strdupW(szPackagePath);
7399 p = strrchrW(dir, '\\');
7403 file = szPackagePath + (p - dir);
7408 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7409 GetCurrentDirectoryW(MAX_PATH, dir);
7410 lstrcatW(dir, szBackSlash);
7411 file = szPackagePath;
7414 msi_free( package->PackagePath );
7415 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7416 if (!package->PackagePath)
7419 return ERROR_OUTOFMEMORY;
7422 lstrcpyW(package->PackagePath, dir);
7423 lstrcatW(package->PackagePath, file);
7426 msi_set_sourcedir_props(package, FALSE);
7429 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7430 if (rc != ERROR_SUCCESS)
7433 msi_apply_transforms( package );
7434 msi_apply_patches( package );
7436 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7438 TRACE("setting reinstall property\n");
7439 msi_set_property( package->db, szReinstall, szAll );
7442 /* properties may have been added by a transform */
7443 msi_clone_properties( package );
7445 msi_parse_command_line( package, szCommandLine, FALSE );
7446 msi_adjust_privilege_properties( package );
7447 msi_set_context( package );
7449 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7451 TRACE("disabling rollback\n");
7452 msi_set_property( package->db, szRollbackDisabled, szOne );
7455 if (needs_ui_sequence( package))
7457 package->script->InWhatSequence |= SEQUENCE_UI;
7458 rc = ACTION_ProcessUISequence(package);
7459 ui_exists = ui_sequence_exists(package);
7460 if (rc == ERROR_SUCCESS || !ui_exists)
7462 package->script->InWhatSequence |= SEQUENCE_EXEC;
7463 rc = ACTION_ProcessExecSequence(package, ui_exists);
7467 rc = ACTION_ProcessExecSequence(package, FALSE);
7469 package->script->CurrentlyScripting = FALSE;
7471 /* process the ending type action */
7472 if (rc == ERROR_SUCCESS)
7473 ACTION_PerformActionSequence(package, -1);
7474 else if (rc == ERROR_INSTALL_USEREXIT)
7475 ACTION_PerformActionSequence(package, -2);
7476 else if (rc == ERROR_INSTALL_SUSPEND)
7477 ACTION_PerformActionSequence(package, -4);
7480 ACTION_PerformActionSequence(package, -3);
7481 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7483 package->need_rollback = TRUE;
7487 /* finish up running custom actions */
7488 ACTION_FinishCustomActions(package);
7490 if (package->need_rollback)
7492 WARN("installation failed, running rollback script\n");
7493 execute_script( package, ROLLBACK_SCRIPT );
7496 if (rc == ERROR_SUCCESS && package->need_reboot)
7497 return ERROR_SUCCESS_REBOOT_REQUIRED;