2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
191 sprintfW(message,template_s,timet,action);
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
221 case state_whitespace:
225 if (!count) goto done;
232 if (in_quotes && p[1] != '\"') count--;
237 if (!count) in_quotes = 0;
249 if (in_quotes) count--;
253 state = state_whitespace;
254 if (!count) goto done;
259 if (!count) in_quotes = 0;
270 if (in_quotes && p[1] != '\"') count--;
274 state = state_whitespace;
275 if (!count || (count > 1 && !len)) goto done;
281 if (!count) in_quotes = 0;
290 if (!ignore) *out++ = *p;
294 if (!len) *value = 0;
301 static void remove_quotes( WCHAR *str )
304 int len = strlenW( str );
306 while ((p = strchrW( p, '"' )))
308 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
313 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
323 return ERROR_SUCCESS;
328 while (*ptr == ' ') ptr++;
331 ptr2 = strchrW( ptr, '=' );
332 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
335 if (!len) return ERROR_INVALID_COMMAND_LINE;
337 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
338 memcpy( prop, ptr, len * sizeof(WCHAR) );
340 if (!preserve_case) struprW( prop );
343 while (*ptr2 == ' ') ptr2++;
346 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
347 len = parse_prop( ptr2, val, &num_quotes );
350 WARN("unbalanced quotes\n");
353 return ERROR_INVALID_COMMAND_LINE;
355 remove_quotes( val );
356 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
358 r = msi_set_property( package->db, prop, val );
359 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
360 msi_reset_folders( package, TRUE );
368 return ERROR_SUCCESS;
371 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
374 LPWSTR p, *ret = NULL;
380 /* count the number of substrings */
381 for ( pc = str, count = 0; pc; count++ )
383 pc = strchrW( pc, sep );
388 /* allocate space for an array of substring pointers and the substrings */
389 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
390 (lstrlenW(str)+1) * sizeof(WCHAR) );
394 /* copy the string and set the pointers */
395 p = (LPWSTR) &ret[count+1];
397 for( count = 0; (ret[count] = p); count++ )
399 p = strchrW( p, sep );
407 static BOOL ui_sequence_exists( MSIPACKAGE *package )
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 == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
881 folder->State = FOLDER_STATE_CREATED;
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 );
949 folder->State = FOLDER_STATE_REMOVED;
950 return ERROR_SUCCESS;
953 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
955 static const WCHAR query[] =
956 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
957 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
962 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
963 if (rc != ERROR_SUCCESS)
964 return ERROR_SUCCESS;
966 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
967 msiobj_release( &view->hdr );
972 static UINT load_component( MSIRECORD *row, LPVOID param )
974 MSIPACKAGE *package = param;
977 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
979 return ERROR_FUNCTION_FAILED;
981 list_add_tail( &package->components, &comp->entry );
983 /* fill in the data */
984 comp->Component = msi_dup_record_field( row, 1 );
986 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
988 comp->ComponentId = msi_dup_record_field( row, 2 );
989 comp->Directory = msi_dup_record_field( row, 3 );
990 comp->Attributes = MSI_RecordGetInteger(row,4);
991 comp->Condition = msi_dup_record_field( row, 5 );
992 comp->KeyPath = msi_dup_record_field( row, 6 );
994 comp->Installed = INSTALLSTATE_UNKNOWN;
995 comp->Action = INSTALLSTATE_UNKNOWN;
996 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
998 comp->assembly = msi_load_assembly( package, comp );
999 return ERROR_SUCCESS;
1002 UINT msi_load_all_components( MSIPACKAGE *package )
1004 static const WCHAR query[] = {
1005 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1006 '`','C','o','m','p','o','n','e','n','t','`',0 };
1010 if (!list_empty(&package->components))
1011 return ERROR_SUCCESS;
1013 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1014 if (r != ERROR_SUCCESS)
1017 if (!msi_init_assembly_caches( package ))
1019 ERR("can't initialize assembly caches\n");
1020 msiobj_release( &view->hdr );
1021 return ERROR_FUNCTION_FAILED;
1024 r = MSI_IterateRecords(view, NULL, load_component, package);
1025 msiobj_release(&view->hdr);
1027 msi_destroy_assembly_caches( package );
1032 MSIPACKAGE *package;
1033 MSIFEATURE *feature;
1036 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1040 cl = msi_alloc( sizeof (*cl) );
1042 return ERROR_NOT_ENOUGH_MEMORY;
1043 cl->component = comp;
1044 list_add_tail( &feature->Components, &cl->entry );
1046 return ERROR_SUCCESS;
1049 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1053 fl = msi_alloc( sizeof(*fl) );
1055 return ERROR_NOT_ENOUGH_MEMORY;
1056 fl->feature = child;
1057 list_add_tail( &parent->Children, &fl->entry );
1059 return ERROR_SUCCESS;
1062 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1064 _ilfs* ilfs = param;
1068 component = MSI_RecordGetString(row,1);
1070 /* check to see if the component is already loaded */
1071 comp = msi_get_loaded_component( ilfs->package, component );
1074 ERR("unknown component %s\n", debugstr_w(component));
1075 return ERROR_FUNCTION_FAILED;
1078 add_feature_component( ilfs->feature, comp );
1079 comp->Enabled = TRUE;
1081 return ERROR_SUCCESS;
1084 static UINT load_feature(MSIRECORD * row, LPVOID param)
1086 MSIPACKAGE* package = param;
1087 MSIFEATURE* feature;
1088 static const WCHAR Query1[] =
1089 {'S','E','L','E','C','T',' ',
1090 '`','C','o','m','p','o','n','e','n','t','_','`',
1091 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1092 'C','o','m','p','o','n','e','n','t','s','`',' ',
1093 'W','H','E','R','E',' ',
1094 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1099 /* fill in the data */
1101 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1103 return ERROR_NOT_ENOUGH_MEMORY;
1105 list_init( &feature->Children );
1106 list_init( &feature->Components );
1108 feature->Feature = msi_dup_record_field( row, 1 );
1110 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1112 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1113 feature->Title = msi_dup_record_field( row, 3 );
1114 feature->Description = msi_dup_record_field( row, 4 );
1116 if (!MSI_RecordIsNull(row,5))
1117 feature->Display = MSI_RecordGetInteger(row,5);
1119 feature->Level= MSI_RecordGetInteger(row,6);
1120 feature->Directory = msi_dup_record_field( row, 7 );
1121 feature->Attributes = MSI_RecordGetInteger(row,8);
1123 feature->Installed = INSTALLSTATE_UNKNOWN;
1124 feature->Action = INSTALLSTATE_UNKNOWN;
1125 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1127 list_add_tail( &package->features, &feature->entry );
1129 /* load feature components */
1131 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1132 if (rc != ERROR_SUCCESS)
1133 return ERROR_SUCCESS;
1135 ilfs.package = package;
1136 ilfs.feature = feature;
1138 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1139 msiobj_release(&view->hdr);
1141 return ERROR_SUCCESS;
1144 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1146 MSIPACKAGE *package = param;
1147 MSIFEATURE *parent, *child;
1149 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1151 return ERROR_FUNCTION_FAILED;
1153 if (!child->Feature_Parent)
1154 return ERROR_SUCCESS;
1156 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1158 return ERROR_FUNCTION_FAILED;
1160 add_feature_child( parent, child );
1161 return ERROR_SUCCESS;
1164 UINT msi_load_all_features( MSIPACKAGE *package )
1166 static const WCHAR query[] = {
1167 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1168 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1169 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1173 if (!list_empty(&package->features))
1174 return ERROR_SUCCESS;
1176 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1177 if (r != ERROR_SUCCESS)
1180 r = MSI_IterateRecords( view, NULL, load_feature, package );
1181 if (r != ERROR_SUCCESS)
1184 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1185 msiobj_release( &view->hdr );
1190 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1201 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1203 static const WCHAR query[] = {
1204 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1205 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1206 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1207 MSIQUERY *view = NULL;
1208 MSIRECORD *row = NULL;
1211 TRACE("%s\n", debugstr_w(file->File));
1213 r = MSI_OpenQuery(package->db, &view, query, file->File);
1214 if (r != ERROR_SUCCESS)
1217 r = MSI_ViewExecute(view, NULL);
1218 if (r != ERROR_SUCCESS)
1221 r = MSI_ViewFetch(view, &row);
1222 if (r != ERROR_SUCCESS)
1225 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1226 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1227 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1228 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1229 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1232 if (view) msiobj_release(&view->hdr);
1233 if (row) msiobj_release(&row->hdr);
1237 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1240 static const WCHAR query[] = {
1241 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1242 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1243 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1245 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1248 WARN("query failed\n");
1249 return ERROR_FUNCTION_FAILED;
1252 file->disk_id = MSI_RecordGetInteger( row, 1 );
1253 msiobj_release( &row->hdr );
1254 return ERROR_SUCCESS;
1257 static UINT load_file(MSIRECORD *row, LPVOID param)
1259 MSIPACKAGE* package = param;
1263 /* fill in the data */
1265 file = msi_alloc_zero( sizeof (MSIFILE) );
1267 return ERROR_NOT_ENOUGH_MEMORY;
1269 file->File = msi_dup_record_field( row, 1 );
1271 component = MSI_RecordGetString( row, 2 );
1272 file->Component = msi_get_loaded_component( package, component );
1274 if (!file->Component)
1276 WARN("Component not found: %s\n", debugstr_w(component));
1277 msi_free(file->File);
1279 return ERROR_SUCCESS;
1282 file->FileName = msi_dup_record_field( row, 3 );
1283 msi_reduce_to_long_filename( file->FileName );
1285 file->ShortName = msi_dup_record_field( row, 3 );
1286 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1288 file->FileSize = MSI_RecordGetInteger( row, 4 );
1289 file->Version = msi_dup_record_field( row, 5 );
1290 file->Language = msi_dup_record_field( row, 6 );
1291 file->Attributes = MSI_RecordGetInteger( row, 7 );
1292 file->Sequence = MSI_RecordGetInteger( row, 8 );
1294 file->state = msifs_invalid;
1296 /* if the compressed bits are not set in the file attributes,
1297 * then read the information from the package word count property
1299 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1301 file->IsCompressed = FALSE;
1303 else if (file->Attributes &
1304 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1306 file->IsCompressed = TRUE;
1308 else if (file->Attributes & msidbFileAttributesNoncompressed)
1310 file->IsCompressed = FALSE;
1314 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1317 load_file_hash(package, file);
1318 load_file_disk_id(package, file);
1320 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1322 list_add_tail( &package->files, &file->entry );
1324 return ERROR_SUCCESS;
1327 static UINT load_all_files(MSIPACKAGE *package)
1331 static const WCHAR Query[] =
1332 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1333 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1334 '`','S','e','q','u','e','n','c','e','`', 0};
1336 if (!list_empty(&package->files))
1337 return ERROR_SUCCESS;
1339 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1340 if (rc != ERROR_SUCCESS)
1341 return ERROR_SUCCESS;
1343 rc = MSI_IterateRecords(view, NULL, load_file, package);
1344 msiobj_release(&view->hdr);
1346 return ERROR_SUCCESS;
1349 static UINT load_media( MSIRECORD *row, LPVOID param )
1351 MSIPACKAGE *package = param;
1352 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1353 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1355 /* FIXME: load external cabinets and directory sources too */
1356 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1357 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1358 return ERROR_SUCCESS;
1361 static UINT load_all_media( MSIPACKAGE *package )
1363 static const WCHAR query[] =
1364 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
1365 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
1369 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1370 if (r != ERROR_SUCCESS) return ERROR_SUCCESS;
1372 MSI_IterateRecords( view, NULL, load_media, package );
1373 msiobj_release( &view->hdr );
1374 return ERROR_SUCCESS;
1377 static UINT load_patch(MSIRECORD *row, LPVOID param)
1379 MSIPACKAGE *package = param;
1380 MSIFILEPATCH *patch;
1383 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1385 return ERROR_NOT_ENOUGH_MEMORY;
1387 file_key = msi_dup_record_field( row, 1 );
1388 patch->File = msi_get_loaded_file( package, file_key );
1393 ERR("Failed to find target for patch in File table\n");
1395 return ERROR_FUNCTION_FAILED;
1398 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1400 /* FIXME: The database should be properly transformed */
1401 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1403 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1404 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1405 patch->IsApplied = FALSE;
1408 * Header field - for patch validation.
1409 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1412 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1414 list_add_tail( &package->filepatches, &patch->entry );
1416 return ERROR_SUCCESS;
1419 static UINT load_all_patches(MSIPACKAGE *package)
1423 static const WCHAR Query[] =
1424 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1425 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1426 '`','S','e','q','u','e','n','c','e','`',0};
1428 if (!list_empty(&package->filepatches))
1429 return ERROR_SUCCESS;
1431 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1432 if (rc != ERROR_SUCCESS)
1433 return ERROR_SUCCESS;
1435 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1436 msiobj_release(&view->hdr);
1438 return ERROR_SUCCESS;
1441 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1443 static const WCHAR query[] = {
1444 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1445 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1446 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1449 folder->persistent = FALSE;
1450 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1452 if (!MSI_ViewExecute( view, NULL ))
1455 if (!MSI_ViewFetch( view, &rec ))
1457 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1458 folder->persistent = TRUE;
1459 msiobj_release( &rec->hdr );
1462 msiobj_release( &view->hdr );
1464 return ERROR_SUCCESS;
1467 static UINT load_folder( MSIRECORD *row, LPVOID param )
1469 MSIPACKAGE *package = param;
1470 static WCHAR szEmpty[] = { 0 };
1471 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1474 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1475 list_init( &folder->children );
1476 folder->Directory = msi_dup_record_field( row, 1 );
1477 folder->Parent = msi_dup_record_field( row, 2 );
1478 p = msi_dup_record_field(row, 3);
1480 TRACE("%s\n", debugstr_w(folder->Directory));
1482 /* split src and target dir */
1484 src_short = folder_split_path( p, ':' );
1486 /* split the long and short paths */
1487 tgt_long = folder_split_path( tgt_short, '|' );
1488 src_long = folder_split_path( src_short, '|' );
1490 /* check for no-op dirs */
1491 if (tgt_short && !strcmpW( szDot, tgt_short ))
1492 tgt_short = szEmpty;
1493 if (src_short && !strcmpW( szDot, src_short ))
1494 src_short = szEmpty;
1497 tgt_long = tgt_short;
1500 src_short = tgt_short;
1501 src_long = tgt_long;
1505 src_long = src_short;
1507 /* FIXME: use the target short path too */
1508 folder->TargetDefault = strdupW(tgt_long);
1509 folder->SourceShortPath = strdupW(src_short);
1510 folder->SourceLongPath = strdupW(src_long);
1513 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1514 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1515 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1517 load_folder_persistence( package, folder );
1519 list_add_tail( &package->folders, &folder->entry );
1520 return ERROR_SUCCESS;
1523 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1527 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1529 list_add_tail( &parent->children, &fl->entry );
1530 return ERROR_SUCCESS;
1533 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1535 MSIPACKAGE *package = param;
1536 MSIFOLDER *parent, *child;
1538 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1539 return ERROR_FUNCTION_FAILED;
1541 if (!child->Parent) return ERROR_SUCCESS;
1543 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1544 return ERROR_FUNCTION_FAILED;
1546 return add_folder_child( parent, child );
1549 static UINT load_all_folders( MSIPACKAGE *package )
1551 static const WCHAR query[] = {
1552 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1553 '`','D','i','r','e','c','t','o','r','y','`',0 };
1557 if (!list_empty(&package->folders))
1558 return ERROR_SUCCESS;
1560 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1561 if (r != ERROR_SUCCESS)
1564 r = MSI_IterateRecords( view, NULL, load_folder, package );
1565 if (r != ERROR_SUCCESS)
1567 msiobj_release( &view->hdr );
1570 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1571 msiobj_release( &view->hdr );
1575 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1577 msi_set_property( package->db, szCostingComplete, szZero );
1578 msi_set_property( package->db, szRootDrive, szCRoot );
1580 load_all_folders( package );
1581 msi_load_all_components( package );
1582 msi_load_all_features( package );
1583 load_all_files( package );
1584 load_all_patches( package );
1585 load_all_media( package );
1587 return ERROR_SUCCESS;
1590 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1592 const WCHAR *action = package->script->Actions[script][index];
1593 ui_actionstart( package, action );
1594 TRACE("executing %s\n", debugstr_w(action));
1595 return ACTION_PerformAction( package, action, script );
1598 static UINT execute_script( MSIPACKAGE *package, UINT script )
1600 UINT i, rc = ERROR_SUCCESS;
1602 TRACE("executing script %u\n", script);
1604 if (!package->script)
1606 ERR("no script!\n");
1607 return ERROR_FUNCTION_FAILED;
1609 if (script == ROLLBACK_SCRIPT)
1611 for (i = package->script->ActionCount[script]; i > 0; i--)
1613 rc = execute_script_action( package, script, i - 1 );
1614 if (rc != ERROR_SUCCESS) break;
1619 for (i = 0; i < package->script->ActionCount[script]; i++)
1621 rc = execute_script_action( package, script, i );
1622 if (rc != ERROR_SUCCESS) break;
1625 msi_free_action_script(package, script);
1629 static UINT ACTION_FileCost(MSIPACKAGE *package)
1631 return ERROR_SUCCESS;
1634 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1639 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1641 if (!comp->ComponentId) continue;
1643 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1644 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1646 if (r != ERROR_SUCCESS)
1647 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1648 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1650 if (r != ERROR_SUCCESS)
1651 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1652 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1654 if (r != ERROR_SUCCESS)
1655 comp->Installed = INSTALLSTATE_ABSENT;
1659 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1661 MSIFEATURE *feature;
1663 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1665 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1667 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1668 feature->Installed = INSTALLSTATE_ABSENT;
1670 feature->Installed = state;
1674 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1676 return (feature->Level > 0 && feature->Level <= level);
1679 static BOOL process_state_property(MSIPACKAGE* package, int level,
1680 LPCWSTR property, INSTALLSTATE state)
1683 MSIFEATURE *feature;
1685 override = msi_dup_property( package->db, property );
1689 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1691 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1694 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1696 if (!strcmpiW( override, szAll ))
1698 if (feature->Installed != state)
1700 feature->Action = state;
1701 feature->ActionRequest = state;
1706 LPWSTR ptr = override;
1707 LPWSTR ptr2 = strchrW(override,',');
1711 int len = ptr2 - ptr;
1713 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1714 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1716 if (feature->Installed != state)
1718 feature->Action = state;
1719 feature->ActionRequest = state;
1726 ptr2 = strchrW(ptr,',');
1737 static BOOL process_overrides( MSIPACKAGE *package, int level )
1739 static const WCHAR szAddLocal[] =
1740 {'A','D','D','L','O','C','A','L',0};
1741 static const WCHAR szAddSource[] =
1742 {'A','D','D','S','O','U','R','C','E',0};
1743 static const WCHAR szAdvertise[] =
1744 {'A','D','V','E','R','T','I','S','E',0};
1747 /* all these activation/deactivation things happen in order and things
1748 * later on the list override things earlier on the list.
1750 * 0 INSTALLLEVEL processing
1763 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1764 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1765 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1766 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1767 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1770 msi_set_property( package->db, szPreselected, szOne );
1775 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1778 MSICOMPONENT* component;
1779 MSIFEATURE *feature;
1781 TRACE("Checking Install Level\n");
1783 level = msi_get_property_int(package->db, szInstallLevel, 1);
1785 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1787 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1789 if (!is_feature_selected( feature, level )) continue;
1791 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1793 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1795 feature->Action = INSTALLSTATE_SOURCE;
1796 feature->ActionRequest = INSTALLSTATE_SOURCE;
1798 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1800 feature->Action = INSTALLSTATE_ADVERTISED;
1801 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1805 feature->Action = INSTALLSTATE_LOCAL;
1806 feature->ActionRequest = INSTALLSTATE_LOCAL;
1810 /* disable child features of unselected parent or follow parent */
1811 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1815 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1817 if (!is_feature_selected( feature, level ))
1819 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1820 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1822 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1824 fl->feature->Action = feature->Action;
1825 fl->feature->ActionRequest = feature->ActionRequest;
1830 else /* preselected */
1832 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1834 if (!is_feature_selected( feature, level )) continue;
1836 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1838 if (feature->Installed == INSTALLSTATE_ABSENT)
1840 feature->Action = INSTALLSTATE_UNKNOWN;
1841 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1845 feature->Action = feature->Installed;
1846 feature->ActionRequest = feature->Installed;
1850 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1854 if (!is_feature_selected( feature, level )) continue;
1856 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1858 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1860 fl->feature->Action = feature->Action;
1861 fl->feature->ActionRequest = feature->ActionRequest;
1867 /* now we want to set component state based based on feature state */
1868 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1872 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1873 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1874 feature->ActionRequest, feature->Action);
1876 if (!is_feature_selected( feature, level )) continue;
1878 /* features with components that have compressed files are made local */
1879 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1881 if (cl->component->ForceLocalState &&
1882 feature->ActionRequest == INSTALLSTATE_SOURCE)
1884 feature->Action = INSTALLSTATE_LOCAL;
1885 feature->ActionRequest = INSTALLSTATE_LOCAL;
1890 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1892 component = cl->component;
1894 switch (feature->ActionRequest)
1896 case INSTALLSTATE_ABSENT:
1897 component->anyAbsent = 1;
1899 case INSTALLSTATE_ADVERTISED:
1900 component->hasAdvertiseFeature = 1;
1902 case INSTALLSTATE_SOURCE:
1903 component->hasSourceFeature = 1;
1905 case INSTALLSTATE_LOCAL:
1906 component->hasLocalFeature = 1;
1908 case INSTALLSTATE_DEFAULT:
1909 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1910 component->hasAdvertiseFeature = 1;
1911 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1912 component->hasSourceFeature = 1;
1914 component->hasLocalFeature = 1;
1922 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1924 /* check if it's local or source */
1925 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1926 (component->hasLocalFeature || component->hasSourceFeature))
1928 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1929 !component->ForceLocalState)
1931 component->Action = INSTALLSTATE_SOURCE;
1932 component->ActionRequest = INSTALLSTATE_SOURCE;
1936 component->Action = INSTALLSTATE_LOCAL;
1937 component->ActionRequest = INSTALLSTATE_LOCAL;
1942 /* if any feature is local, the component must be local too */
1943 if (component->hasLocalFeature)
1945 component->Action = INSTALLSTATE_LOCAL;
1946 component->ActionRequest = INSTALLSTATE_LOCAL;
1949 if (component->hasSourceFeature)
1951 component->Action = INSTALLSTATE_SOURCE;
1952 component->ActionRequest = INSTALLSTATE_SOURCE;
1955 if (component->hasAdvertiseFeature)
1957 component->Action = INSTALLSTATE_ADVERTISED;
1958 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1961 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1962 if (component->anyAbsent &&
1963 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1965 component->Action = INSTALLSTATE_ABSENT;
1966 component->ActionRequest = INSTALLSTATE_ABSENT;
1970 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1972 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1974 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1975 component->Action = INSTALLSTATE_LOCAL;
1976 component->ActionRequest = INSTALLSTATE_LOCAL;
1979 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1980 component->Installed == INSTALLSTATE_SOURCE &&
1981 component->hasSourceFeature)
1983 component->Action = INSTALLSTATE_UNKNOWN;
1984 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1987 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1988 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1991 return ERROR_SUCCESS;
1994 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1996 MSIPACKAGE *package = param;
1998 MSIFEATURE *feature;
2000 name = MSI_RecordGetString( row, 1 );
2002 feature = msi_get_loaded_feature( package, name );
2004 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2008 Condition = MSI_RecordGetString(row,3);
2010 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2012 int level = MSI_RecordGetInteger(row,2);
2013 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2014 feature->Level = level;
2017 return ERROR_SUCCESS;
2020 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2022 static const WCHAR name[] = {'\\',0};
2023 VS_FIXEDFILEINFO *ptr, *ret;
2025 DWORD versize, handle;
2028 versize = GetFileVersionInfoSizeW( filename, &handle );
2032 version = msi_alloc( versize );
2036 GetFileVersionInfoW( filename, 0, versize, version );
2038 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2040 msi_free( version );
2044 ret = msi_alloc( sz );
2045 memcpy( ret, ptr, sz );
2047 msi_free( version );
2051 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2055 msi_parse_version_string( version, &ms, &ls );
2057 if (fi->dwFileVersionMS > ms) return 1;
2058 else if (fi->dwFileVersionMS < ms) return -1;
2059 else if (fi->dwFileVersionLS > ls) return 1;
2060 else if (fi->dwFileVersionLS < ls) return -1;
2064 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2068 msi_parse_version_string( ver1, &ms1, NULL );
2069 msi_parse_version_string( ver2, &ms2, NULL );
2071 if (ms1 > ms2) return 1;
2072 else if (ms1 < ms2) return -1;
2076 DWORD msi_get_disk_file_size( LPCWSTR filename )
2081 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2082 if (file == INVALID_HANDLE_VALUE)
2083 return INVALID_FILE_SIZE;
2085 size = GetFileSize( file, NULL );
2086 TRACE("size is %u\n", size);
2087 CloseHandle( file );
2091 BOOL msi_file_hash_matches( MSIFILE *file )
2094 MSIFILEHASHINFO hash;
2096 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2097 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2098 if (r != ERROR_SUCCESS)
2101 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2104 static WCHAR *get_temp_dir( void )
2107 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2109 GetTempPathW( MAX_PATH, tmp );
2112 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2113 if (CreateDirectoryW( dir, NULL )) break;
2115 return strdupW( dir );
2119 * msi_build_directory_name()
2121 * This function is to save messing round with directory names
2122 * It handles adding backslashes between path segments,
2123 * and can add \ at the end of the directory name if told to.
2125 * It takes a variable number of arguments.
2126 * It always allocates a new string for the result, so make sure
2127 * to free the return value when finished with it.
2129 * The first arg is the number of path segments that follow.
2130 * The arguments following count are a list of path segments.
2131 * A path segment may be NULL.
2133 * Path segments will be added with a \ separating them.
2134 * A \ will not be added after the last segment, however if the
2135 * last segment is NULL, then the last character will be a \
2137 WCHAR *msi_build_directory_name( DWORD count, ... )
2143 va_start( va, count );
2144 for (i = 0; i < count; i++)
2146 const WCHAR *str = va_arg( va, const WCHAR * );
2147 if (str) sz += strlenW( str ) + 1;
2151 dir = msi_alloc( sz * sizeof(WCHAR) );
2154 va_start( va, count );
2155 for (i = 0; i < count; i++)
2157 const WCHAR *str = va_arg( va, const WCHAR * );
2159 strcatW( dir, str );
2160 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2166 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2168 MSIASSEMBLY *assembly = file->Component->assembly;
2170 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2172 msi_free( file->TargetPath );
2173 if (assembly && !assembly->application)
2175 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2176 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2177 msi_track_tempfile( package, file->TargetPath );
2181 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2182 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2185 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2188 static UINT calculate_file_cost( MSIPACKAGE *package )
2190 VS_FIXEDFILEINFO *file_version;
2191 WCHAR *font_version;
2194 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2196 MSICOMPONENT *comp = file->Component;
2199 if (!comp->Enabled) continue;
2201 if (file->IsCompressed)
2202 comp->ForceLocalState = TRUE;
2204 set_target_path( package, file );
2206 if ((comp->assembly && !comp->assembly->installed) ||
2207 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2209 comp->Cost += file->FileSize;
2212 file_size = msi_get_disk_file_size( file->TargetPath );
2216 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2218 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2220 comp->Cost += file->FileSize - file_size;
2222 msi_free( file_version );
2225 else if ((font_version = font_version_from_file( file->TargetPath )))
2227 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2229 comp->Cost += file->FileSize - file_size;
2231 msi_free( font_version );
2235 if (file_size != file->FileSize)
2237 comp->Cost += file->FileSize - file_size;
2240 return ERROR_SUCCESS;
2243 void msi_clean_path( WCHAR *p )
2250 /* copy until the end of the string or a space */
2251 while (*p != ' ' && (*q = *p))
2254 /* reduce many backslashes to one */
2255 if (*p != '\\' || *q != '\\')
2259 /* quit at the end of the string */
2263 /* count the number of spaces */
2268 /* if it's leading or trailing space, skip it */
2269 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2271 else /* copy n spaces */
2272 while (n && (*q++ = *p++)) n--;
2276 static WCHAR *get_target_dir_property( MSIDATABASE *db )
2279 WCHAR *path, *target_dir = msi_dup_property( db, szTargetDir );
2281 if (!target_dir) return NULL;
2283 len = strlenW( target_dir );
2284 if (target_dir[len - 1] == '\\') return target_dir;
2285 if ((path = msi_alloc( (len + 2) * sizeof(WCHAR) )))
2287 strcpyW( path, target_dir );
2291 msi_free( target_dir );
2295 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2298 MSIFOLDER *folder, *parent, *child;
2301 TRACE("resolving %s\n", debugstr_w(name));
2303 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2305 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2307 if (!load_prop || !(path = get_target_dir_property( package->db )))
2309 path = msi_dup_property( package->db, szRootDrive );
2312 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2314 parent = msi_get_loaded_folder( package, folder->Parent );
2315 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2317 msi_clean_path( path );
2318 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2320 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2324 msi_set_property( package->db, folder->Directory, path );
2325 msi_free( folder->ResolvedTarget );
2326 folder->ResolvedTarget = path;
2328 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2331 msi_resolve_target_folder( package, child->Directory, load_prop );
2333 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2336 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2338 static const WCHAR condition_query[] =
2339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','C','o','n','d','i','t','i','o','n','`',0};
2340 static const WCHAR szOutOfDiskSpace[] =
2341 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2343 UINT rc = ERROR_SUCCESS;
2347 TRACE("Building directory properties\n");
2348 msi_resolve_target_folder( package, szTargetDir, TRUE );
2350 TRACE("Evaluating component conditions\n");
2351 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2353 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2355 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2356 comp->Enabled = FALSE;
2359 comp->Enabled = TRUE;
2362 /* read components states from the registry */
2363 ACTION_GetComponentInstallStates(package);
2364 ACTION_GetFeatureInstallStates(package);
2366 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2368 TRACE("Evaluating feature conditions\n");
2370 rc = MSI_DatabaseOpenViewW( package->db, condition_query, &view );
2371 if (rc == ERROR_SUCCESS)
2373 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2374 msiobj_release( &view->hdr );
2378 TRACE("Calculating file cost\n");
2379 calculate_file_cost( package );
2381 msi_set_property( package->db, szCostingComplete, szOne );
2382 /* set default run level if not set */
2383 level = msi_dup_property( package->db, szInstallLevel );
2385 msi_set_property( package->db, szInstallLevel, szOne );
2388 /* FIXME: check volume disk space */
2389 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2391 return MSI_SetFeatureStates(package);
2394 /* OK this value is "interpreted" and then formatted based on the
2395 first few characters */
2396 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2401 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2407 LPWSTR deformated = NULL;
2410 deformat_string(package, &value[2], &deformated);
2412 /* binary value type */
2416 *size = (strlenW(ptr)/2)+1;
2418 *size = strlenW(ptr)/2;
2420 data = msi_alloc(*size);
2426 /* if uneven pad with a zero in front */
2432 data[count] = (BYTE)strtol(byte,NULL,0);
2434 TRACE("Uneven byte count\n");
2442 data[count] = (BYTE)strtol(byte,NULL,0);
2445 msi_free(deformated);
2447 TRACE("Data %i bytes(%i)\n",*size,count);
2454 deformat_string(package, &value[1], &deformated);
2457 *size = sizeof(DWORD);
2458 data = msi_alloc(*size);
2464 if ( (*p < '0') || (*p > '9') )
2470 if (deformated[0] == '-')
2473 TRACE("DWORD %i\n",*(LPDWORD)data);
2475 msi_free(deformated);
2480 static const WCHAR szMulti[] = {'[','~',']',0};
2489 *type=REG_EXPAND_SZ;
2497 if (strstrW(value, szMulti))
2498 *type = REG_MULTI_SZ;
2500 /* remove initial delimiter */
2501 if (!strncmpW(value, szMulti, 3))
2504 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2506 /* add double NULL terminator */
2507 if (*type == REG_MULTI_SZ)
2509 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2510 data = msi_realloc_zero(data, *size);
2516 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2523 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2525 *root_key = HKEY_LOCAL_MACHINE;
2530 *root_key = HKEY_CURRENT_USER;
2535 *root_key = HKEY_CLASSES_ROOT;
2539 *root_key = HKEY_CURRENT_USER;
2543 *root_key = HKEY_LOCAL_MACHINE;
2547 *root_key = HKEY_USERS;
2551 ERR("Unknown root %i\n", root);
2558 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2560 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2561 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2563 if (is_64bit && package->platform == PLATFORM_INTEL &&
2564 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2569 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2570 if (!(path_32node = msi_alloc( size ))) return NULL;
2572 memcpy( path_32node, path, len * sizeof(WCHAR) );
2573 strcpyW( path_32node + len, szWow6432Node );
2574 strcatW( path_32node, szBackSlash );
2575 strcatW( path_32node, path + len );
2579 return strdupW( path );
2582 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2584 MSIPACKAGE *package = param;
2585 LPSTR value_data = NULL;
2586 HKEY root_key, hkey;
2588 LPWSTR deformated, uikey, keypath;
2589 LPCWSTR szRoot, component, name, key, value;
2593 BOOL check_first = FALSE;
2596 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2598 component = MSI_RecordGetString(row, 6);
2599 comp = msi_get_loaded_component(package,component);
2601 return ERROR_SUCCESS;
2603 comp->Action = msi_get_component_action( package, comp );
2604 if (comp->Action != INSTALLSTATE_LOCAL)
2606 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2607 return ERROR_SUCCESS;
2610 name = MSI_RecordGetString(row, 4);
2611 if( MSI_RecordIsNull(row,5) && name )
2613 /* null values can have special meanings */
2614 if (name[0]=='-' && name[1] == 0)
2615 return ERROR_SUCCESS;
2616 else if ((name[0]=='+' && name[1] == 0) ||
2617 (name[0] == '*' && name[1] == 0))
2622 root = MSI_RecordGetInteger(row,2);
2623 key = MSI_RecordGetString(row, 3);
2625 szRoot = get_root_key( package, root, &root_key );
2627 return ERROR_SUCCESS;
2629 deformat_string(package, key , &deformated);
2630 size = strlenW(deformated) + strlenW(szRoot) + 1;
2631 uikey = msi_alloc(size*sizeof(WCHAR));
2632 strcpyW(uikey,szRoot);
2633 strcatW(uikey,deformated);
2635 keypath = get_keypath( package, root_key, deformated );
2636 msi_free( deformated );
2637 if (RegCreateKeyW( root_key, keypath, &hkey ))
2639 ERR("Could not create key %s\n", debugstr_w(keypath));
2642 return ERROR_SUCCESS;
2645 value = MSI_RecordGetString(row,5);
2647 value_data = parse_value(package, value, &type, &size);
2650 value_data = (LPSTR)strdupW(szEmpty);
2651 size = sizeof(szEmpty);
2655 deformat_string(package, name, &deformated);
2659 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2661 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2666 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2667 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2669 TRACE("value %s of %s checked already exists\n",
2670 debugstr_w(deformated), debugstr_w(uikey));
2674 TRACE("Checked and setting value %s of %s\n",
2675 debugstr_w(deformated), debugstr_w(uikey));
2676 if (deformated || size)
2677 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2682 uirow = MSI_CreateRecord(3);
2683 MSI_RecordSetStringW(uirow,2,deformated);
2684 MSI_RecordSetStringW(uirow,1,uikey);
2685 if (type == REG_SZ || type == REG_EXPAND_SZ)
2686 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2687 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2688 msiobj_release( &uirow->hdr );
2690 msi_free(value_data);
2691 msi_free(deformated);
2695 return ERROR_SUCCESS;
2698 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2702 static const WCHAR ExecSeqQuery[] =
2703 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2704 '`','R','e','g','i','s','t','r','y','`',0 };
2706 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2707 if (rc != ERROR_SUCCESS)
2708 return ERROR_SUCCESS;
2710 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2711 msiobj_release(&view->hdr);
2715 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2719 DWORD num_subkeys, num_values;
2723 if ((res = RegDeleteTreeW( hkey_root, key )))
2725 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2730 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2732 if ((res = RegDeleteValueW( hkey, value )))
2734 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2736 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2737 NULL, NULL, NULL, NULL );
2738 RegCloseKey( hkey );
2739 if (!res && !num_subkeys && !num_values)
2741 TRACE("Removing empty key %s\n", debugstr_w(key));
2742 RegDeleteKeyW( hkey_root, key );
2746 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2750 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2752 MSIPACKAGE *package = param;
2753 LPCWSTR component, name, key_str, root_key_str;
2754 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2757 BOOL delete_key = FALSE;
2762 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2764 component = MSI_RecordGetString( row, 6 );
2765 comp = msi_get_loaded_component( package, component );
2767 return ERROR_SUCCESS;
2769 comp->Action = msi_get_component_action( package, comp );
2770 if (comp->Action != INSTALLSTATE_ABSENT)
2772 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2773 return ERROR_SUCCESS;
2776 name = MSI_RecordGetString( row, 4 );
2777 if (MSI_RecordIsNull( row, 5 ) && name )
2779 if (name[0] == '+' && !name[1])
2780 return ERROR_SUCCESS;
2781 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2788 root = MSI_RecordGetInteger( row, 2 );
2789 key_str = MSI_RecordGetString( row, 3 );
2791 root_key_str = get_root_key( package, root, &hkey_root );
2793 return ERROR_SUCCESS;
2795 deformat_string( package, key_str, &deformated_key );
2796 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2797 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2798 strcpyW( ui_key_str, root_key_str );
2799 strcatW( ui_key_str, deformated_key );
2801 deformat_string( package, name, &deformated_name );
2803 keypath = get_keypath( package, hkey_root, deformated_key );
2804 msi_free( deformated_key );
2805 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2806 msi_free( keypath );
2808 uirow = MSI_CreateRecord( 2 );
2809 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2810 MSI_RecordSetStringW( uirow, 2, deformated_name );
2811 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2812 msiobj_release( &uirow->hdr );
2814 msi_free( ui_key_str );
2815 msi_free( deformated_name );
2816 return ERROR_SUCCESS;
2819 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2821 MSIPACKAGE *package = param;
2822 LPCWSTR component, name, key_str, root_key_str;
2823 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2826 BOOL delete_key = FALSE;
2831 component = MSI_RecordGetString( row, 5 );
2832 comp = msi_get_loaded_component( package, component );
2834 return ERROR_SUCCESS;
2836 comp->Action = msi_get_component_action( package, comp );
2837 if (comp->Action != INSTALLSTATE_LOCAL)
2839 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2840 return ERROR_SUCCESS;
2843 if ((name = MSI_RecordGetString( row, 4 )))
2845 if (name[0] == '-' && !name[1])
2852 root = MSI_RecordGetInteger( row, 2 );
2853 key_str = MSI_RecordGetString( row, 3 );
2855 root_key_str = get_root_key( package, root, &hkey_root );
2857 return ERROR_SUCCESS;
2859 deformat_string( package, key_str, &deformated_key );
2860 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2861 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2862 strcpyW( ui_key_str, root_key_str );
2863 strcatW( ui_key_str, deformated_key );
2865 deformat_string( package, name, &deformated_name );
2867 keypath = get_keypath( package, hkey_root, deformated_key );
2868 msi_free( deformated_key );
2869 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2870 msi_free( keypath );
2872 uirow = MSI_CreateRecord( 2 );
2873 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2874 MSI_RecordSetStringW( uirow, 2, deformated_name );
2875 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2876 msiobj_release( &uirow->hdr );
2878 msi_free( ui_key_str );
2879 msi_free( deformated_name );
2880 return ERROR_SUCCESS;
2883 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2887 static const WCHAR registry_query[] =
2888 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2889 '`','R','e','g','i','s','t','r','y','`',0 };
2890 static const WCHAR remove_registry_query[] =
2891 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2892 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2894 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2895 if (rc == ERROR_SUCCESS)
2897 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2898 msiobj_release( &view->hdr );
2899 if (rc != ERROR_SUCCESS)
2903 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2904 if (rc == ERROR_SUCCESS)
2906 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2907 msiobj_release( &view->hdr );
2908 if (rc != ERROR_SUCCESS)
2912 return ERROR_SUCCESS;
2915 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2917 package->script->CurrentlyScripting = TRUE;
2919 return ERROR_SUCCESS;
2923 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2926 DWORD total = 0, count = 0;
2927 static const WCHAR q1[]=
2928 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2929 '`','R','e','g','i','s','t','r','y','`',0};
2932 MSIFEATURE *feature;
2935 TRACE("InstallValidate\n");
2937 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2938 if (rc == ERROR_SUCCESS)
2940 MSI_IterateRecords( view, &count, NULL, package );
2941 msiobj_release( &view->hdr );
2942 total += count * 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 WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3195 const WCHAR prefixW[] = {'<','\\',0};
3196 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3197 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3201 strcpyW( keypath, prefixW );
3202 strcatW( keypath, comp->assembly->display_name );
3206 return resolve_keypath( package, comp );
3209 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3211 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3218 squash_guid(package->ProductCode,squished_pc);
3219 msi_set_sourcedir_props(package, FALSE);
3221 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3224 INSTALLSTATE action;
3226 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3227 if (!comp->ComponentId)
3230 squash_guid( comp->ComponentId, squished_cc );
3231 msi_free( comp->FullKeypath );
3232 comp->FullKeypath = build_full_keypath( package, comp );
3234 ACTION_RefCountComponent( package, comp );
3236 if (package->need_rollback) action = comp->Installed;
3237 else action = comp->ActionRequest;
3239 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3240 debugstr_w(comp->Component), debugstr_w(squished_cc),
3241 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3243 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3245 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3246 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3248 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3250 if (rc != ERROR_SUCCESS)
3253 if (comp->Attributes & msidbComponentAttributesPermanent)
3255 static const WCHAR szPermKey[] =
3256 { '0','0','0','0','0','0','0','0','0','0','0','0',
3257 '0','0','0','0','0','0','0','0','0','0','0','0',
3258 '0','0','0','0','0','0','0','0',0 };
3260 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3262 if (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 (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, (const BYTE *)patch->localfile,
4092 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4093 RegCloseKey( patch_key );
4094 if (res != ERROR_SUCCESS)
4097 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4099 res = GetLastError();
4100 ERR("Unable to copy patch package %d\n", res);
4103 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4104 if (res != ERROR_SUCCESS)
4107 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4108 RegCloseKey( patch_key );
4109 if (res != ERROR_SUCCESS)
4113 all_patches[len] = 0;
4114 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4115 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4116 if (res != ERROR_SUCCESS)
4119 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4120 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4121 if (res != ERROR_SUCCESS)
4122 r = ERROR_FUNCTION_FAILED;
4125 RegCloseKey( product_patches_key );
4126 RegCloseKey( patches_key );
4127 RegCloseKey( product_key );
4128 msi_free( all_patches );
4132 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4135 HKEY hukey = NULL, hudkey = NULL;
4138 if (!list_empty(&package->patches))
4140 rc = msi_publish_patches(package);
4141 if (rc != ERROR_SUCCESS)
4145 /* FIXME: also need to publish if the product is in advertise mode */
4146 if (!msi_check_publish(package))
4147 return ERROR_SUCCESS;
4149 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4151 if (rc != ERROR_SUCCESS)
4154 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4155 NULL, &hudkey, TRUE);
4156 if (rc != ERROR_SUCCESS)
4159 rc = msi_publish_upgrade_code(package);
4160 if (rc != ERROR_SUCCESS)
4163 rc = msi_publish_product_properties(package, hukey);
4164 if (rc != ERROR_SUCCESS)
4167 rc = msi_publish_sourcelist(package, hukey);
4168 if (rc != ERROR_SUCCESS)
4171 rc = msi_publish_icons(package);
4174 uirow = MSI_CreateRecord( 1 );
4175 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4176 msi_ui_actiondata( package, szPublishProduct, uirow );
4177 msiobj_release( &uirow->hdr );
4180 RegCloseKey(hudkey);
4185 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4187 WCHAR *filename, *ptr, *folder, *ret;
4188 const WCHAR *dirprop;
4190 filename = msi_dup_record_field( row, 2 );
4191 if (filename && (ptr = strchrW( filename, '|' )))
4196 dirprop = MSI_RecordGetString( row, 3 );
4199 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4200 if (!folder) folder = msi_dup_property( package->db, dirprop );
4203 folder = msi_dup_property( package->db, szWindowsFolder );
4207 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4208 msi_free( filename );
4212 ret = msi_build_directory_name( 2, folder, ptr );
4214 msi_free( filename );
4219 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4221 MSIPACKAGE *package = param;
4222 LPCWSTR component, section, key, value, identifier;
4223 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4228 component = MSI_RecordGetString(row, 8);
4229 comp = msi_get_loaded_component(package,component);
4231 return ERROR_SUCCESS;
4233 comp->Action = msi_get_component_action( package, comp );
4234 if (comp->Action != INSTALLSTATE_LOCAL)
4236 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4237 return ERROR_SUCCESS;
4240 identifier = MSI_RecordGetString(row,1);
4241 section = MSI_RecordGetString(row,4);
4242 key = MSI_RecordGetString(row,5);
4243 value = MSI_RecordGetString(row,6);
4244 action = MSI_RecordGetInteger(row,7);
4246 deformat_string(package,section,&deformated_section);
4247 deformat_string(package,key,&deformated_key);
4248 deformat_string(package,value,&deformated_value);
4250 fullname = get_ini_file_name(package, row);
4254 TRACE("Adding value %s to section %s in %s\n",
4255 debugstr_w(deformated_key), debugstr_w(deformated_section),
4256 debugstr_w(fullname));
4257 WritePrivateProfileStringW(deformated_section, deformated_key,
4258 deformated_value, fullname);
4260 else if (action == 1)
4263 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4264 returned, 10, fullname);
4265 if (returned[0] == 0)
4267 TRACE("Adding value %s to section %s in %s\n",
4268 debugstr_w(deformated_key), debugstr_w(deformated_section),
4269 debugstr_w(fullname));
4271 WritePrivateProfileStringW(deformated_section, deformated_key,
4272 deformated_value, fullname);
4275 else if (action == 3)
4276 FIXME("Append to existing section not yet implemented\n");
4278 uirow = MSI_CreateRecord(4);
4279 MSI_RecordSetStringW(uirow,1,identifier);
4280 MSI_RecordSetStringW(uirow,2,deformated_section);
4281 MSI_RecordSetStringW(uirow,3,deformated_key);
4282 MSI_RecordSetStringW(uirow,4,deformated_value);
4283 msi_ui_actiondata( package, szWriteIniValues, uirow );
4284 msiobj_release( &uirow->hdr );
4287 msi_free(deformated_key);
4288 msi_free(deformated_value);
4289 msi_free(deformated_section);
4290 return ERROR_SUCCESS;
4293 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4297 static const WCHAR ExecSeqQuery[] =
4298 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4299 '`','I','n','i','F','i','l','e','`',0};
4301 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4302 if (rc != ERROR_SUCCESS)
4304 TRACE("no IniFile table\n");
4305 return ERROR_SUCCESS;
4308 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4309 msiobj_release(&view->hdr);
4313 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4315 MSIPACKAGE *package = param;
4316 LPCWSTR component, section, key, value, identifier;
4317 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4322 component = MSI_RecordGetString( row, 8 );
4323 comp = msi_get_loaded_component( package, component );
4325 return ERROR_SUCCESS;
4327 comp->Action = msi_get_component_action( package, comp );
4328 if (comp->Action != INSTALLSTATE_ABSENT)
4330 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4331 return ERROR_SUCCESS;
4334 identifier = MSI_RecordGetString( row, 1 );
4335 section = MSI_RecordGetString( row, 4 );
4336 key = MSI_RecordGetString( row, 5 );
4337 value = MSI_RecordGetString( row, 6 );
4338 action = MSI_RecordGetInteger( row, 7 );
4340 deformat_string( package, section, &deformated_section );
4341 deformat_string( package, key, &deformated_key );
4342 deformat_string( package, value, &deformated_value );
4344 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4346 filename = get_ini_file_name( package, row );
4348 TRACE("Removing key %s from section %s in %s\n",
4349 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4351 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4353 WARN("Unable to remove key %u\n", GetLastError());
4355 msi_free( filename );
4358 FIXME("Unsupported action %d\n", action);
4361 uirow = MSI_CreateRecord( 4 );
4362 MSI_RecordSetStringW( uirow, 1, identifier );
4363 MSI_RecordSetStringW( uirow, 2, deformated_section );
4364 MSI_RecordSetStringW( uirow, 3, deformated_key );
4365 MSI_RecordSetStringW( uirow, 4, deformated_value );
4366 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4367 msiobj_release( &uirow->hdr );
4369 msi_free( deformated_key );
4370 msi_free( deformated_value );
4371 msi_free( deformated_section );
4372 return ERROR_SUCCESS;
4375 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4377 MSIPACKAGE *package = param;
4378 LPCWSTR component, section, key, value, identifier;
4379 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4384 component = MSI_RecordGetString( row, 8 );
4385 comp = msi_get_loaded_component( package, component );
4387 return ERROR_SUCCESS;
4389 comp->Action = msi_get_component_action( package, comp );
4390 if (comp->Action != INSTALLSTATE_LOCAL)
4392 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4393 return ERROR_SUCCESS;
4396 identifier = MSI_RecordGetString( row, 1 );
4397 section = MSI_RecordGetString( row, 4 );
4398 key = MSI_RecordGetString( row, 5 );
4399 value = MSI_RecordGetString( row, 6 );
4400 action = MSI_RecordGetInteger( row, 7 );
4402 deformat_string( package, section, &deformated_section );
4403 deformat_string( package, key, &deformated_key );
4404 deformat_string( package, value, &deformated_value );
4406 if (action == msidbIniFileActionRemoveLine)
4408 filename = get_ini_file_name( package, row );
4410 TRACE("Removing key %s from section %s in %s\n",
4411 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4413 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4415 WARN("Unable to remove key %u\n", GetLastError());
4417 msi_free( filename );
4420 FIXME("Unsupported action %d\n", action);
4422 uirow = MSI_CreateRecord( 4 );
4423 MSI_RecordSetStringW( uirow, 1, identifier );
4424 MSI_RecordSetStringW( uirow, 2, deformated_section );
4425 MSI_RecordSetStringW( uirow, 3, deformated_key );
4426 MSI_RecordSetStringW( uirow, 4, deformated_value );
4427 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4428 msiobj_release( &uirow->hdr );
4430 msi_free( deformated_key );
4431 msi_free( deformated_value );
4432 msi_free( deformated_section );
4433 return ERROR_SUCCESS;
4436 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4440 static const WCHAR query[] =
4441 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4442 '`','I','n','i','F','i','l','e','`',0};
4443 static const WCHAR remove_query[] =
4444 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4445 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4447 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4448 if (rc == ERROR_SUCCESS)
4450 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4451 msiobj_release( &view->hdr );
4452 if (rc != ERROR_SUCCESS)
4456 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4457 if (rc == ERROR_SUCCESS)
4459 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4460 msiobj_release( &view->hdr );
4461 if (rc != ERROR_SUCCESS)
4465 return ERROR_SUCCESS;
4468 static void register_dll( const WCHAR *dll, BOOL unregister )
4472 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4475 HRESULT (WINAPI *func_ptr)( void );
4476 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4478 func_ptr = (void *)GetProcAddress( hmod, func );
4481 HRESULT hr = func_ptr();
4483 WARN("failed to register dll 0x%08x\n", hr);
4486 WARN("entry point %s not found\n", func);
4487 FreeLibrary( hmod );
4490 WARN("failed to load library %u\n", GetLastError());
4493 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4495 MSIPACKAGE *package = param;
4500 filename = MSI_RecordGetString(row,1);
4501 file = msi_get_loaded_file( package, filename );
4504 WARN("unable to find file %s\n", debugstr_w(filename));
4505 return ERROR_SUCCESS;
4507 file->Component->Action = msi_get_component_action( package, file->Component );
4508 if (file->Component->Action != INSTALLSTATE_LOCAL)
4510 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4511 return ERROR_SUCCESS;
4514 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4515 register_dll( file->TargetPath, FALSE );
4517 uirow = MSI_CreateRecord( 2 );
4518 MSI_RecordSetStringW( uirow, 1, filename );
4519 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4520 msi_ui_actiondata( package, szSelfRegModules, uirow );
4521 msiobj_release( &uirow->hdr );
4523 return ERROR_SUCCESS;
4526 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4530 static const WCHAR ExecSeqQuery[] =
4531 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4532 '`','S','e','l','f','R','e','g','`',0};
4534 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4535 if (rc != ERROR_SUCCESS)
4537 TRACE("no SelfReg table\n");
4538 return ERROR_SUCCESS;
4541 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4542 msiobj_release(&view->hdr);
4544 return ERROR_SUCCESS;
4547 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4549 MSIPACKAGE *package = param;
4554 filename = MSI_RecordGetString( row, 1 );
4555 file = msi_get_loaded_file( package, filename );
4558 WARN("unable to find file %s\n", debugstr_w(filename));
4559 return ERROR_SUCCESS;
4561 file->Component->Action = msi_get_component_action( package, file->Component );
4562 if (file->Component->Action != INSTALLSTATE_ABSENT)
4564 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4565 return ERROR_SUCCESS;
4568 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4569 register_dll( file->TargetPath, TRUE );
4571 uirow = MSI_CreateRecord( 2 );
4572 MSI_RecordSetStringW( uirow, 1, filename );
4573 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4574 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4575 msiobj_release( &uirow->hdr );
4577 return ERROR_SUCCESS;
4580 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4584 static const WCHAR query[] =
4585 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4586 '`','S','e','l','f','R','e','g','`',0};
4588 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4589 if (rc != ERROR_SUCCESS)
4591 TRACE("no SelfReg table\n");
4592 return ERROR_SUCCESS;
4595 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4596 msiobj_release( &view->hdr );
4598 return ERROR_SUCCESS;
4601 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4603 MSIFEATURE *feature;
4605 HKEY hkey = NULL, userdata = NULL;
4607 if (!msi_check_publish(package))
4608 return ERROR_SUCCESS;
4610 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4612 if (rc != ERROR_SUCCESS)
4615 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4617 if (rc != ERROR_SUCCESS)
4620 /* here the guids are base 85 encoded */
4621 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4627 BOOL absent = FALSE;
4630 if (feature->Action != INSTALLSTATE_LOCAL &&
4631 feature->Action != INSTALLSTATE_SOURCE &&
4632 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4635 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4639 if (feature->Feature_Parent)
4640 size += strlenW( feature->Feature_Parent )+2;
4642 data = msi_alloc(size * sizeof(WCHAR));
4645 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4647 MSICOMPONENT* component = cl->component;
4651 if (component->ComponentId)
4653 TRACE("From %s\n",debugstr_w(component->ComponentId));
4654 CLSIDFromString(component->ComponentId, &clsid);
4655 encode_base85_guid(&clsid,buf);
4656 TRACE("to %s\n",debugstr_w(buf));
4661 if (feature->Feature_Parent)
4663 static const WCHAR sep[] = {'\2',0};
4665 strcatW(data,feature->Feature_Parent);
4668 msi_reg_set_val_str( userdata, feature->Feature, data );
4672 if (feature->Feature_Parent)
4673 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4676 size += sizeof(WCHAR);
4677 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4678 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4682 size += 2*sizeof(WCHAR);
4683 data = msi_alloc(size);
4686 if (feature->Feature_Parent)
4687 strcpyW( &data[1], feature->Feature_Parent );
4688 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4694 uirow = MSI_CreateRecord( 1 );
4695 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4696 msi_ui_actiondata( package, szPublishFeatures, uirow );
4697 msiobj_release( &uirow->hdr );
4698 /* FIXME: call msi_ui_progress? */
4703 RegCloseKey(userdata);
4707 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4713 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4715 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4717 if (r == ERROR_SUCCESS)
4719 RegDeleteValueW(hkey, feature->Feature);
4723 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4725 if (r == ERROR_SUCCESS)
4727 RegDeleteValueW(hkey, feature->Feature);
4731 uirow = MSI_CreateRecord( 1 );
4732 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4733 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4734 msiobj_release( &uirow->hdr );
4736 return ERROR_SUCCESS;
4739 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4741 MSIFEATURE *feature;
4743 if (!msi_check_unpublish(package))
4744 return ERROR_SUCCESS;
4746 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4748 msi_unpublish_feature(package, feature);
4751 return ERROR_SUCCESS;
4754 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4758 WCHAR date[9], *val, *buffer;
4759 const WCHAR *prop, *key;
4761 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4762 static const WCHAR modpath_fmt[] =
4763 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4764 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4765 static const WCHAR szModifyPath[] =
4766 {'M','o','d','i','f','y','P','a','t','h',0};
4767 static const WCHAR szUninstallString[] =
4768 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4769 static const WCHAR szEstimatedSize[] =
4770 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4771 static const WCHAR szDisplayVersion[] =
4772 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4773 static const WCHAR szInstallSource[] =
4774 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4775 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4776 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4777 static const WCHAR szAuthorizedCDFPrefix[] =
4778 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4779 static const WCHAR szARPCONTACT[] =
4780 {'A','R','P','C','O','N','T','A','C','T',0};
4781 static const WCHAR szContact[] =
4782 {'C','o','n','t','a','c','t',0};
4783 static const WCHAR szARPCOMMENTS[] =
4784 {'A','R','P','C','O','M','M','E','N','T','S',0};
4785 static const WCHAR szComments[] =
4786 {'C','o','m','m','e','n','t','s',0};
4787 static const WCHAR szProductName[] =
4788 {'P','r','o','d','u','c','t','N','a','m','e',0};
4789 static const WCHAR szDisplayName[] =
4790 {'D','i','s','p','l','a','y','N','a','m','e',0};
4791 static const WCHAR szARPHELPLINK[] =
4792 {'A','R','P','H','E','L','P','L','I','N','K',0};
4793 static const WCHAR szHelpLink[] =
4794 {'H','e','l','p','L','i','n','k',0};
4795 static const WCHAR szARPHELPTELEPHONE[] =
4796 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4797 static const WCHAR szHelpTelephone[] =
4798 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4799 static const WCHAR szARPINSTALLLOCATION[] =
4800 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4801 static const WCHAR szInstallLocation[] =
4802 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4803 static const WCHAR szManufacturer[] =
4804 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4805 static const WCHAR szPublisher[] =
4806 {'P','u','b','l','i','s','h','e','r',0};
4807 static const WCHAR szARPREADME[] =
4808 {'A','R','P','R','E','A','D','M','E',0};
4809 static const WCHAR szReadme[] =
4810 {'R','e','a','d','M','e',0};
4811 static const WCHAR szARPSIZE[] =
4812 {'A','R','P','S','I','Z','E',0};
4813 static const WCHAR szSize[] =
4814 {'S','i','z','e',0};
4815 static const WCHAR szARPURLINFOABOUT[] =
4816 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4817 static const WCHAR szURLInfoAbout[] =
4818 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4819 static const WCHAR szARPURLUPDATEINFO[] =
4820 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4821 static const WCHAR szURLUpdateInfo[] =
4822 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4823 static const WCHAR szARPSYSTEMCOMPONENT[] =
4824 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4825 static const WCHAR szSystemComponent[] =
4826 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4828 static const WCHAR *propval[] = {
4829 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4830 szARPCONTACT, szContact,
4831 szARPCOMMENTS, szComments,
4832 szProductName, szDisplayName,
4833 szARPHELPLINK, szHelpLink,
4834 szARPHELPTELEPHONE, szHelpTelephone,
4835 szARPINSTALLLOCATION, szInstallLocation,
4836 szSourceDir, szInstallSource,
4837 szManufacturer, szPublisher,
4838 szARPREADME, szReadme,
4840 szARPURLINFOABOUT, szURLInfoAbout,
4841 szARPURLUPDATEINFO, szURLUpdateInfo,
4844 const WCHAR **p = propval;
4850 val = msi_dup_property(package->db, prop);
4851 msi_reg_set_val_str(hkey, key, val);
4855 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4856 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4858 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4860 size = deformat_string(package, modpath_fmt, &buffer);
4861 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4862 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4865 /* FIXME: Write real Estimated Size when we have it */
4866 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4868 GetLocalTime(&systime);
4869 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4870 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4872 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4873 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4875 buffer = msi_dup_property(package->db, szProductVersion);
4876 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4879 DWORD verdword = msi_version_str_to_dword(buffer);
4881 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4882 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4883 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4887 return ERROR_SUCCESS;
4890 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4892 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4894 LPWSTR upgrade_code;
4895 HKEY hkey, props, upgrade_key;
4898 /* FIXME: also need to publish if the product is in advertise mode */
4899 if (!msi_check_publish(package))
4900 return ERROR_SUCCESS;
4902 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4903 if (rc != ERROR_SUCCESS)
4906 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4907 if (rc != ERROR_SUCCESS)
4910 if (!msi_get_property_int( package->db, szInstalled, 0 ))
4912 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4913 if (!CopyFileW( package->PackagePath, package->localfile, FALSE ))
4915 rc = GetLastError();
4916 ERR("Unable to copy package %u\n", rc);
4920 msi_free( package->localfile );
4921 package->localfile = NULL;
4923 rc = msi_publish_install_properties(package, hkey);
4924 if (rc != ERROR_SUCCESS)
4927 rc = msi_publish_install_properties(package, props);
4928 if (rc != ERROR_SUCCESS)
4931 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4934 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4935 if (rc == ERROR_SUCCESS)
4937 squash_guid( package->ProductCode, squashed_pc );
4938 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4939 RegCloseKey( upgrade_key );
4941 msi_free( upgrade_code );
4945 uirow = MSI_CreateRecord( 1 );
4946 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4947 msi_ui_actiondata( package, szRegisterProduct, uirow );
4948 msiobj_release( &uirow->hdr );
4951 return ERROR_SUCCESS;
4954 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4956 return execute_script(package,INSTALL_SCRIPT);
4959 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4961 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4962 WCHAR *upgrade, **features;
4963 BOOL full_uninstall = TRUE;
4964 MSIFEATURE *feature;
4965 MSIPATCHINFO *patch;
4968 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4970 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4972 features = msi_split_string( remove, ',' );
4973 for (i = 0; features && features[i]; i++)
4975 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4979 if (!full_uninstall)
4980 return ERROR_SUCCESS;
4982 MSIREG_DeleteProductKey(package->ProductCode);
4983 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4984 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4986 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4987 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4988 MSIREG_DeleteUserProductKey(package->ProductCode);
4989 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4991 upgrade = msi_dup_property(package->db, szUpgradeCode);
4994 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4995 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4999 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5001 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5002 /* FIXME: remove local patch package if this is the last product */
5005 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5006 DeleteFileW( package->localfile );
5007 msi_free( package->localfile );
5008 package->localfile = NULL;
5010 return ERROR_SUCCESS;
5013 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5018 /* turn off scheduling */
5019 package->script->CurrentlyScripting= FALSE;
5021 /* first do the same as an InstallExecute */
5022 rc = ACTION_InstallExecute(package);
5023 if (rc != ERROR_SUCCESS)
5026 /* then handle Commit Actions */
5027 rc = execute_script(package,COMMIT_SCRIPT);
5028 if (rc != ERROR_SUCCESS)
5031 remove = msi_dup_property(package->db, szRemove);
5032 rc = msi_unpublish_product(package, remove);
5037 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5039 static const WCHAR RunOnce[] = {
5040 'S','o','f','t','w','a','r','e','\\',
5041 'M','i','c','r','o','s','o','f','t','\\',
5042 'W','i','n','d','o','w','s','\\',
5043 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5044 'R','u','n','O','n','c','e',0};
5045 static const WCHAR InstallRunOnce[] = {
5046 'S','o','f','t','w','a','r','e','\\',
5047 'M','i','c','r','o','s','o','f','t','\\',
5048 'W','i','n','d','o','w','s','\\',
5049 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5050 'I','n','s','t','a','l','l','e','r','\\',
5051 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5053 static const WCHAR msiexec_fmt[] = {
5055 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5056 '\"','%','s','\"',0};
5057 static const WCHAR install_fmt[] = {
5058 '/','I',' ','\"','%','s','\"',' ',
5059 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5060 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5061 WCHAR buffer[256], sysdir[MAX_PATH];
5063 WCHAR squished_pc[100];
5065 squash_guid(package->ProductCode,squished_pc);
5067 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5068 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5069 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5072 msi_reg_set_val_str( hkey, squished_pc, buffer );
5075 TRACE("Reboot command %s\n",debugstr_w(buffer));
5077 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5078 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5080 msi_reg_set_val_str( hkey, squished_pc, buffer );
5083 return ERROR_INSTALL_SUSPEND;
5086 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5088 static const WCHAR query[] =
5089 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5090 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5091 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5092 MSIRECORD *rec, *row;
5098 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5100 rec = MSI_CreateRecord( count + 2 );
5101 str = MSI_RecordGetString( row, 1 );
5102 MSI_RecordSetStringW( rec, 0, str );
5103 msiobj_release( &row->hdr );
5104 MSI_RecordSetInteger( rec, 1, error );
5106 va_start( va, count );
5107 for (i = 0; i < count; i++)
5109 str = va_arg( va, const WCHAR *);
5110 MSI_RecordSetStringW( rec, i + 2, str );
5114 MSI_FormatRecordW( package, rec, NULL, &size );
5116 data = msi_alloc( size * sizeof(WCHAR) );
5117 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5119 msiobj_release( &rec->hdr );
5123 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5129 * We are currently doing what should be done here in the top level Install
5130 * however for Administrative and uninstalls this step will be needed
5132 if (!package->PackagePath)
5133 return ERROR_SUCCESS;
5135 msi_set_sourcedir_props(package, TRUE);
5137 attrib = GetFileAttributesW(package->db->path);
5138 if (attrib == INVALID_FILE_ATTRIBUTES)
5144 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5145 package->Context, MSICODE_PRODUCT,
5146 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5147 if (rc == ERROR_MORE_DATA)
5149 prompt = msi_alloc(size * sizeof(WCHAR));
5150 MsiSourceListGetInfoW(package->ProductCode, NULL,
5151 package->Context, MSICODE_PRODUCT,
5152 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5155 prompt = strdupW(package->db->path);
5157 msg = msi_build_error_string(package, 1302, 1, prompt);
5158 while(attrib == INVALID_FILE_ATTRIBUTES)
5160 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5163 rc = ERROR_INSTALL_USEREXIT;
5166 attrib = GetFileAttributesW(package->db->path);
5172 return ERROR_SUCCESS;
5177 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5180 LPWSTR buffer, productid = NULL;
5181 UINT i, rc = ERROR_SUCCESS;
5184 static const WCHAR szPropKeys[][80] =
5186 {'P','r','o','d','u','c','t','I','D',0},
5187 {'U','S','E','R','N','A','M','E',0},
5188 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5192 static const WCHAR szRegKeys[][80] =
5194 {'P','r','o','d','u','c','t','I','D',0},
5195 {'R','e','g','O','w','n','e','r',0},
5196 {'R','e','g','C','o','m','p','a','n','y',0},
5200 if (msi_check_unpublish(package))
5202 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5206 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5210 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5212 if (rc != ERROR_SUCCESS)
5215 for( i = 0; szPropKeys[i][0]; i++ )
5217 buffer = msi_dup_property( package->db, szPropKeys[i] );
5218 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5223 uirow = MSI_CreateRecord( 1 );
5224 MSI_RecordSetStringW( uirow, 1, productid );
5225 msi_ui_actiondata( package, szRegisterUser, uirow );
5226 msiobj_release( &uirow->hdr );
5228 msi_free(productid);
5234 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5238 package->script->InWhatSequence |= SEQUENCE_EXEC;
5239 rc = ACTION_ProcessExecSequence(package,FALSE);
5243 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5245 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5246 WCHAR productid_85[21], component_85[21], *ret;
5250 /* > is used if there is a component GUID and < if not. */
5252 productid_85[0] = 0;
5253 component_85[0] = 0;
5254 CLSIDFromString( package->ProductCode, &clsid );
5256 encode_base85_guid( &clsid, productid_85 );
5259 CLSIDFromString( component->ComponentId, &clsid );
5260 encode_base85_guid( &clsid, component_85 );
5263 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5264 debugstr_w(component_85));
5266 sz = 20 + strlenW( feature ) + 20 + 3;
5267 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5268 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5272 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5274 MSIPACKAGE *package = param;
5275 LPCWSTR compgroupid, component, feature, qualifier, text;
5276 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5285 feature = MSI_RecordGetString(rec, 5);
5286 feat = msi_get_loaded_feature(package, feature);
5288 return ERROR_SUCCESS;
5290 feat->Action = msi_get_feature_action( package, feat );
5291 if (feat->Action != INSTALLSTATE_LOCAL &&
5292 feat->Action != INSTALLSTATE_SOURCE &&
5293 feat->Action != INSTALLSTATE_ADVERTISED)
5295 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5296 return ERROR_SUCCESS;
5299 component = MSI_RecordGetString(rec, 3);
5300 comp = msi_get_loaded_component(package, component);
5302 return ERROR_SUCCESS;
5304 compgroupid = MSI_RecordGetString(rec,1);
5305 qualifier = MSI_RecordGetString(rec,2);
5307 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5308 if (rc != ERROR_SUCCESS)
5311 advertise = msi_create_component_advertise_string( package, comp, feature );
5312 text = MSI_RecordGetString( rec, 4 );
5315 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5316 strcpyW( p, advertise );
5318 msi_free( advertise );
5321 existing = msi_reg_get_val_str( hkey, qualifier );
5323 sz = strlenW( advertise ) + 1;
5326 for (p = existing; *p; p += len)
5328 len = strlenW( p ) + 1;
5329 if (strcmpW( advertise, p )) sz += len;
5332 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5334 rc = ERROR_OUTOFMEMORY;
5340 for (p = existing; *p; p += len)
5342 len = strlenW( p ) + 1;
5343 if (strcmpW( advertise, p ))
5345 memcpy( q, p, len * sizeof(WCHAR) );
5350 strcpyW( q, advertise );
5351 q[strlenW( q ) + 1] = 0;
5353 msi_reg_set_val_multi_str( hkey, qualifier, output );
5358 msi_free( advertise );
5359 msi_free( existing );
5362 uirow = MSI_CreateRecord( 2 );
5363 MSI_RecordSetStringW( uirow, 1, compgroupid );
5364 MSI_RecordSetStringW( uirow, 2, qualifier);
5365 msi_ui_actiondata( package, szPublishComponents, uirow );
5366 msiobj_release( &uirow->hdr );
5367 /* FIXME: call ui_progress? */
5373 * At present I am ignorning the advertised components part of this and only
5374 * focusing on the qualified component sets
5376 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5380 static const WCHAR ExecSeqQuery[] =
5381 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5382 '`','P','u','b','l','i','s','h',
5383 'C','o','m','p','o','n','e','n','t','`',0};
5385 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5386 if (rc != ERROR_SUCCESS)
5387 return ERROR_SUCCESS;
5389 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5390 msiobj_release(&view->hdr);
5395 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5397 static const WCHAR szInstallerComponents[] = {
5398 'S','o','f','t','w','a','r','e','\\',
5399 'M','i','c','r','o','s','o','f','t','\\',
5400 'I','n','s','t','a','l','l','e','r','\\',
5401 'C','o','m','p','o','n','e','n','t','s','\\',0};
5403 MSIPACKAGE *package = param;
5404 LPCWSTR compgroupid, component, feature, qualifier;
5408 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5411 feature = MSI_RecordGetString( rec, 5 );
5412 feat = msi_get_loaded_feature( package, feature );
5414 return ERROR_SUCCESS;
5416 feat->Action = msi_get_feature_action( package, feat );
5417 if (feat->Action != INSTALLSTATE_ABSENT)
5419 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5420 return ERROR_SUCCESS;
5423 component = MSI_RecordGetString( rec, 3 );
5424 comp = msi_get_loaded_component( package, component );
5426 return ERROR_SUCCESS;
5428 compgroupid = MSI_RecordGetString( rec, 1 );
5429 qualifier = MSI_RecordGetString( rec, 2 );
5431 squash_guid( compgroupid, squashed );
5432 strcpyW( keypath, szInstallerComponents );
5433 strcatW( keypath, squashed );
5435 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5436 if (res != ERROR_SUCCESS)
5438 WARN("Unable to delete component key %d\n", res);
5441 uirow = MSI_CreateRecord( 2 );
5442 MSI_RecordSetStringW( uirow, 1, compgroupid );
5443 MSI_RecordSetStringW( uirow, 2, qualifier );
5444 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5445 msiobj_release( &uirow->hdr );
5447 return ERROR_SUCCESS;
5450 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5454 static const WCHAR query[] =
5455 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5456 '`','P','u','b','l','i','s','h',
5457 'C','o','m','p','o','n','e','n','t','`',0};
5459 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5460 if (rc != ERROR_SUCCESS)
5461 return ERROR_SUCCESS;
5463 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5464 msiobj_release( &view->hdr );
5469 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5471 static const WCHAR query[] =
5472 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5473 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5474 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5475 MSIPACKAGE *package = param;
5476 MSICOMPONENT *component;
5479 SC_HANDLE hscm = NULL, service = NULL;
5481 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5482 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5483 DWORD serv_type, start_type, err_control;
5484 SERVICE_DESCRIPTIONW sd = {NULL};
5486 comp = MSI_RecordGetString( rec, 12 );
5487 component = msi_get_loaded_component( package, comp );
5490 WARN("service component not found\n");
5493 component->Action = msi_get_component_action( package, component );
5494 if (component->Action != INSTALLSTATE_LOCAL)
5496 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5499 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5502 ERR("Failed to open the SC Manager!\n");
5506 start_type = MSI_RecordGetInteger(rec, 5);
5507 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5510 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5511 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5512 serv_type = MSI_RecordGetInteger(rec, 4);
5513 err_control = MSI_RecordGetInteger(rec, 6);
5514 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5515 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5516 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5517 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5518 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5519 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5521 /* fetch the service path */
5522 row = MSI_QueryGetRecord(package->db, query, comp);
5525 ERR("Query failed\n");
5528 key = MSI_RecordGetString(row, 6);
5529 file = msi_get_loaded_file(package, key);
5530 msiobj_release(&row->hdr);
5533 ERR("Failed to load the service file\n");
5537 if (!args || !args[0]) image_path = file->TargetPath;
5540 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5541 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5542 return ERROR_OUTOFMEMORY;
5544 strcpyW(image_path, file->TargetPath);
5545 strcatW(image_path, szSpace);
5546 strcatW(image_path, args);
5548 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5549 start_type, err_control, image_path, load_order,
5550 NULL, depends, serv_name, pass);
5554 if (GetLastError() != ERROR_SERVICE_EXISTS)
5555 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5557 else if (sd.lpDescription)
5559 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5560 WARN("failed to set service description %u\n", GetLastError());
5563 if (image_path != file->TargetPath) msi_free(image_path);
5565 CloseServiceHandle(service);
5566 CloseServiceHandle(hscm);
5569 msi_free(sd.lpDescription);
5570 msi_free(load_order);
5571 msi_free(serv_name);
5576 return ERROR_SUCCESS;
5579 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5583 static const WCHAR ExecSeqQuery[] =
5584 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5585 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5587 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5588 if (rc != ERROR_SUCCESS)
5589 return ERROR_SUCCESS;
5591 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5592 msiobj_release(&view->hdr);
5597 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5598 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5600 LPCWSTR *vector, *temp_vector;
5604 static const WCHAR separator[] = {'[','~',']',0};
5607 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5612 vector = msi_alloc(sizeof(LPWSTR));
5620 vector[*numargs - 1] = p;
5622 if ((q = strstrW(p, separator)))
5626 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5632 vector = temp_vector;
5641 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5643 MSIPACKAGE *package = param;
5646 SC_HANDLE scm = NULL, service = NULL;
5647 LPCWSTR component, *vector = NULL;
5648 LPWSTR name, args, display_name = NULL;
5649 DWORD event, numargs, len;
5650 UINT r = ERROR_FUNCTION_FAILED;
5652 component = MSI_RecordGetString(rec, 6);
5653 comp = msi_get_loaded_component(package, component);
5655 return ERROR_SUCCESS;
5657 comp->Action = msi_get_component_action( package, comp );
5658 if (comp->Action != INSTALLSTATE_LOCAL)
5660 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5661 return ERROR_SUCCESS;
5664 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5665 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5666 event = MSI_RecordGetInteger(rec, 3);
5668 if (!(event & msidbServiceControlEventStart))
5674 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5677 ERR("Failed to open the service control manager\n");
5682 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5683 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5685 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5686 GetServiceDisplayNameW( scm, name, display_name, &len );
5689 service = OpenServiceW(scm, name, SERVICE_START);
5692 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5696 vector = msi_service_args_to_vector(args, &numargs);
5698 if (!StartServiceW(service, numargs, vector) &&
5699 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5701 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5708 uirow = MSI_CreateRecord( 2 );
5709 MSI_RecordSetStringW( uirow, 1, display_name );
5710 MSI_RecordSetStringW( uirow, 2, name );
5711 msi_ui_actiondata( package, szStartServices, uirow );
5712 msiobj_release( &uirow->hdr );
5714 CloseServiceHandle(service);
5715 CloseServiceHandle(scm);
5720 msi_free(display_name);
5724 static UINT ACTION_StartServices( MSIPACKAGE *package )
5729 static const WCHAR query[] = {
5730 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5731 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5733 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5734 if (rc != ERROR_SUCCESS)
5735 return ERROR_SUCCESS;
5737 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5738 msiobj_release(&view->hdr);
5743 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5745 DWORD i, needed, count;
5746 ENUM_SERVICE_STATUSW *dependencies;
5750 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5751 0, &needed, &count))
5754 if (GetLastError() != ERROR_MORE_DATA)
5757 dependencies = msi_alloc(needed);
5761 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5762 needed, &needed, &count))
5765 for (i = 0; i < count; i++)
5767 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5768 SERVICE_STOP | SERVICE_QUERY_STATUS);
5772 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5779 msi_free(dependencies);
5783 static UINT stop_service( LPCWSTR name )
5785 SC_HANDLE scm = NULL, service = NULL;
5786 SERVICE_STATUS status;
5787 SERVICE_STATUS_PROCESS ssp;
5790 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5793 WARN("Failed to open the SCM: %d\n", GetLastError());
5797 service = OpenServiceW(scm, name,
5799 SERVICE_QUERY_STATUS |
5800 SERVICE_ENUMERATE_DEPENDENTS);
5803 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5807 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5808 sizeof(SERVICE_STATUS_PROCESS), &needed))
5810 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5814 if (ssp.dwCurrentState == SERVICE_STOPPED)
5817 stop_service_dependents(scm, service);
5819 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5820 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5823 CloseServiceHandle(service);
5824 CloseServiceHandle(scm);
5826 return ERROR_SUCCESS;
5829 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5831 MSIPACKAGE *package = param;
5835 LPWSTR name = NULL, display_name = NULL;
5839 event = MSI_RecordGetInteger( rec, 3 );
5840 if (!(event & msidbServiceControlEventStop))
5841 return ERROR_SUCCESS;
5843 component = MSI_RecordGetString( rec, 6 );
5844 comp = msi_get_loaded_component( package, component );
5846 return ERROR_SUCCESS;
5848 comp->Action = msi_get_component_action( package, comp );
5849 if (comp->Action != INSTALLSTATE_ABSENT)
5851 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5852 return ERROR_SUCCESS;
5855 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5858 ERR("Failed to open the service control manager\n");
5863 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5864 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5866 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5867 GetServiceDisplayNameW( scm, name, display_name, &len );
5869 CloseServiceHandle( scm );
5871 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5872 stop_service( name );
5875 uirow = MSI_CreateRecord( 2 );
5876 MSI_RecordSetStringW( uirow, 1, display_name );
5877 MSI_RecordSetStringW( uirow, 2, name );
5878 msi_ui_actiondata( package, szStopServices, uirow );
5879 msiobj_release( &uirow->hdr );
5882 msi_free( display_name );
5883 return ERROR_SUCCESS;
5886 static UINT ACTION_StopServices( MSIPACKAGE *package )
5891 static const WCHAR query[] = {
5892 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5893 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5895 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5896 if (rc != ERROR_SUCCESS)
5897 return ERROR_SUCCESS;
5899 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5900 msiobj_release(&view->hdr);
5905 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5907 MSIPACKAGE *package = param;
5911 LPWSTR name = NULL, display_name = NULL;
5913 SC_HANDLE scm = NULL, service = NULL;
5915 event = MSI_RecordGetInteger( rec, 3 );
5916 if (!(event & msidbServiceControlEventDelete))
5917 return ERROR_SUCCESS;
5919 component = MSI_RecordGetString(rec, 6);
5920 comp = msi_get_loaded_component(package, component);
5922 return ERROR_SUCCESS;
5924 comp->Action = msi_get_component_action( package, comp );
5925 if (comp->Action != INSTALLSTATE_ABSENT)
5927 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5928 return ERROR_SUCCESS;
5931 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5932 stop_service( name );
5934 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5937 WARN("Failed to open the SCM: %d\n", GetLastError());
5942 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5943 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5945 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5946 GetServiceDisplayNameW( scm, name, display_name, &len );
5949 service = OpenServiceW( scm, name, DELETE );
5952 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5956 if (!DeleteService( service ))
5957 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5960 uirow = MSI_CreateRecord( 2 );
5961 MSI_RecordSetStringW( uirow, 1, display_name );
5962 MSI_RecordSetStringW( uirow, 2, name );
5963 msi_ui_actiondata( package, szDeleteServices, uirow );
5964 msiobj_release( &uirow->hdr );
5966 CloseServiceHandle( service );
5967 CloseServiceHandle( scm );
5969 msi_free( display_name );
5971 return ERROR_SUCCESS;
5974 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5979 static const WCHAR query[] = {
5980 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5981 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5983 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5984 if (rc != ERROR_SUCCESS)
5985 return ERROR_SUCCESS;
5987 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5988 msiobj_release( &view->hdr );
5993 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5995 MSIPACKAGE *package = param;
5996 LPWSTR driver, driver_path, ptr;
5997 WCHAR outpath[MAX_PATH];
5998 MSIFILE *driver_file = NULL, *setup_file = NULL;
6001 LPCWSTR desc, file_key, component;
6003 UINT r = ERROR_SUCCESS;
6005 static const WCHAR driver_fmt[] = {
6006 'D','r','i','v','e','r','=','%','s',0};
6007 static const WCHAR setup_fmt[] = {
6008 'S','e','t','u','p','=','%','s',0};
6009 static const WCHAR usage_fmt[] = {
6010 'F','i','l','e','U','s','a','g','e','=','1',0};
6012 component = MSI_RecordGetString( rec, 2 );
6013 comp = msi_get_loaded_component( package, component );
6015 return ERROR_SUCCESS;
6017 comp->Action = msi_get_component_action( package, comp );
6018 if (comp->Action != INSTALLSTATE_LOCAL)
6020 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6021 return ERROR_SUCCESS;
6023 desc = MSI_RecordGetString(rec, 3);
6025 file_key = MSI_RecordGetString( rec, 4 );
6026 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6028 file_key = MSI_RecordGetString( rec, 5 );
6029 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6033 ERR("ODBC Driver entry not found!\n");
6034 return ERROR_FUNCTION_FAILED;
6037 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6039 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6040 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6042 driver = msi_alloc(len * sizeof(WCHAR));
6044 return ERROR_OUTOFMEMORY;
6047 lstrcpyW(ptr, desc);
6048 ptr += lstrlenW(ptr) + 1;
6050 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6055 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6059 lstrcpyW(ptr, usage_fmt);
6060 ptr += lstrlenW(ptr) + 1;
6063 driver_path = strdupW(driver_file->TargetPath);
6064 ptr = strrchrW(driver_path, '\\');
6065 if (ptr) *ptr = '\0';
6067 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6068 NULL, ODBC_INSTALL_COMPLETE, &usage))
6070 ERR("Failed to install SQL driver!\n");
6071 r = ERROR_FUNCTION_FAILED;
6074 uirow = MSI_CreateRecord( 5 );
6075 MSI_RecordSetStringW( uirow, 1, desc );
6076 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6077 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6078 msi_ui_actiondata( package, szInstallODBC, uirow );
6079 msiobj_release( &uirow->hdr );
6082 msi_free(driver_path);
6087 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6089 MSIPACKAGE *package = param;
6090 LPWSTR translator, translator_path, ptr;
6091 WCHAR outpath[MAX_PATH];
6092 MSIFILE *translator_file = NULL, *setup_file = NULL;
6095 LPCWSTR desc, file_key, component;
6097 UINT r = ERROR_SUCCESS;
6099 static const WCHAR translator_fmt[] = {
6100 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6101 static const WCHAR setup_fmt[] = {
6102 'S','e','t','u','p','=','%','s',0};
6104 component = MSI_RecordGetString( rec, 2 );
6105 comp = msi_get_loaded_component( package, component );
6107 return ERROR_SUCCESS;
6109 comp->Action = msi_get_component_action( package, comp );
6110 if (comp->Action != INSTALLSTATE_LOCAL)
6112 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6113 return ERROR_SUCCESS;
6115 desc = MSI_RecordGetString(rec, 3);
6117 file_key = MSI_RecordGetString( rec, 4 );
6118 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6120 file_key = MSI_RecordGetString( rec, 5 );
6121 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6123 if (!translator_file)
6125 ERR("ODBC Translator entry not found!\n");
6126 return ERROR_FUNCTION_FAILED;
6129 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6131 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6133 translator = msi_alloc(len * sizeof(WCHAR));
6135 return ERROR_OUTOFMEMORY;
6138 lstrcpyW(ptr, desc);
6139 ptr += lstrlenW(ptr) + 1;
6141 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6146 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6151 translator_path = strdupW(translator_file->TargetPath);
6152 ptr = strrchrW(translator_path, '\\');
6153 if (ptr) *ptr = '\0';
6155 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6156 NULL, ODBC_INSTALL_COMPLETE, &usage))
6158 ERR("Failed to install SQL translator!\n");
6159 r = ERROR_FUNCTION_FAILED;
6162 uirow = MSI_CreateRecord( 5 );
6163 MSI_RecordSetStringW( uirow, 1, desc );
6164 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6165 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6166 msi_ui_actiondata( package, szInstallODBC, uirow );
6167 msiobj_release( &uirow->hdr );
6169 msi_free(translator);
6170 msi_free(translator_path);
6175 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6177 MSIPACKAGE *package = param;
6180 LPCWSTR desc, driver, component;
6181 WORD request = ODBC_ADD_SYS_DSN;
6184 UINT r = ERROR_SUCCESS;
6187 static const WCHAR attrs_fmt[] = {
6188 'D','S','N','=','%','s',0 };
6190 component = MSI_RecordGetString( rec, 2 );
6191 comp = msi_get_loaded_component( package, component );
6193 return ERROR_SUCCESS;
6195 comp->Action = msi_get_component_action( package, comp );
6196 if (comp->Action != INSTALLSTATE_LOCAL)
6198 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6199 return ERROR_SUCCESS;
6202 desc = MSI_RecordGetString(rec, 3);
6203 driver = MSI_RecordGetString(rec, 4);
6204 registration = MSI_RecordGetInteger(rec, 5);
6206 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6207 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6209 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6210 attrs = msi_alloc(len * sizeof(WCHAR));
6212 return ERROR_OUTOFMEMORY;
6214 len = sprintfW(attrs, attrs_fmt, desc);
6217 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6219 ERR("Failed to install SQL data source!\n");
6220 r = ERROR_FUNCTION_FAILED;
6223 uirow = MSI_CreateRecord( 5 );
6224 MSI_RecordSetStringW( uirow, 1, desc );
6225 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6226 MSI_RecordSetInteger( uirow, 3, request );
6227 msi_ui_actiondata( package, szInstallODBC, uirow );
6228 msiobj_release( &uirow->hdr );
6235 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6240 static const WCHAR driver_query[] = {
6241 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6242 'O','D','B','C','D','r','i','v','e','r',0 };
6244 static const WCHAR translator_query[] = {
6245 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6246 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6248 static const WCHAR source_query[] = {
6249 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6250 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6252 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6253 if (rc != ERROR_SUCCESS)
6254 return ERROR_SUCCESS;
6256 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6257 msiobj_release(&view->hdr);
6259 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6260 if (rc != ERROR_SUCCESS)
6261 return ERROR_SUCCESS;
6263 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6264 msiobj_release(&view->hdr);
6266 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6267 if (rc != ERROR_SUCCESS)
6268 return ERROR_SUCCESS;
6270 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6271 msiobj_release(&view->hdr);
6276 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6278 MSIPACKAGE *package = param;
6282 LPCWSTR desc, component;
6284 component = MSI_RecordGetString( rec, 2 );
6285 comp = msi_get_loaded_component( package, component );
6287 return ERROR_SUCCESS;
6289 comp->Action = msi_get_component_action( package, comp );
6290 if (comp->Action != INSTALLSTATE_ABSENT)
6292 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6293 return ERROR_SUCCESS;
6296 desc = MSI_RecordGetString( rec, 3 );
6297 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6299 WARN("Failed to remove ODBC driver\n");
6303 FIXME("Usage count reached 0\n");
6306 uirow = MSI_CreateRecord( 2 );
6307 MSI_RecordSetStringW( uirow, 1, desc );
6308 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6309 msi_ui_actiondata( package, szRemoveODBC, uirow );
6310 msiobj_release( &uirow->hdr );
6312 return ERROR_SUCCESS;
6315 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6317 MSIPACKAGE *package = param;
6321 LPCWSTR desc, component;
6323 component = MSI_RecordGetString( rec, 2 );
6324 comp = msi_get_loaded_component( package, component );
6326 return ERROR_SUCCESS;
6328 comp->Action = msi_get_component_action( package, comp );
6329 if (comp->Action != INSTALLSTATE_ABSENT)
6331 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6332 return ERROR_SUCCESS;
6335 desc = MSI_RecordGetString( rec, 3 );
6336 if (!SQLRemoveTranslatorW( desc, &usage ))
6338 WARN("Failed to remove ODBC translator\n");
6342 FIXME("Usage count reached 0\n");
6345 uirow = MSI_CreateRecord( 2 );
6346 MSI_RecordSetStringW( uirow, 1, desc );
6347 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6348 msi_ui_actiondata( package, szRemoveODBC, uirow );
6349 msiobj_release( &uirow->hdr );
6351 return ERROR_SUCCESS;
6354 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6356 MSIPACKAGE *package = param;
6360 LPCWSTR desc, driver, component;
6361 WORD request = ODBC_REMOVE_SYS_DSN;
6365 static const WCHAR attrs_fmt[] = {
6366 'D','S','N','=','%','s',0 };
6368 component = MSI_RecordGetString( rec, 2 );
6369 comp = msi_get_loaded_component( package, component );
6371 return ERROR_SUCCESS;
6373 comp->Action = msi_get_component_action( package, comp );
6374 if (comp->Action != INSTALLSTATE_ABSENT)
6376 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6377 return ERROR_SUCCESS;
6380 desc = MSI_RecordGetString( rec, 3 );
6381 driver = MSI_RecordGetString( rec, 4 );
6382 registration = MSI_RecordGetInteger( rec, 5 );
6384 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6385 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6387 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6388 attrs = msi_alloc( len * sizeof(WCHAR) );
6390 return ERROR_OUTOFMEMORY;
6392 FIXME("Use ODBCSourceAttribute table\n");
6394 len = sprintfW( attrs, attrs_fmt, desc );
6397 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6399 WARN("Failed to remove ODBC data source\n");
6403 uirow = MSI_CreateRecord( 3 );
6404 MSI_RecordSetStringW( uirow, 1, desc );
6405 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6406 MSI_RecordSetInteger( uirow, 3, request );
6407 msi_ui_actiondata( package, szRemoveODBC, uirow );
6408 msiobj_release( &uirow->hdr );
6410 return ERROR_SUCCESS;
6413 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6418 static const WCHAR driver_query[] = {
6419 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6420 'O','D','B','C','D','r','i','v','e','r',0 };
6422 static const WCHAR translator_query[] = {
6423 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6424 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6426 static const WCHAR source_query[] = {
6427 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6428 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6430 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6431 if (rc != ERROR_SUCCESS)
6432 return ERROR_SUCCESS;
6434 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6435 msiobj_release( &view->hdr );
6437 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6438 if (rc != ERROR_SUCCESS)
6439 return ERROR_SUCCESS;
6441 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6442 msiobj_release( &view->hdr );
6444 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6445 if (rc != ERROR_SUCCESS)
6446 return ERROR_SUCCESS;
6448 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6449 msiobj_release( &view->hdr );
6454 #define ENV_ACT_SETALWAYS 0x1
6455 #define ENV_ACT_SETABSENT 0x2
6456 #define ENV_ACT_REMOVE 0x4
6457 #define ENV_ACT_REMOVEMATCH 0x8
6459 #define ENV_MOD_MACHINE 0x20000000
6460 #define ENV_MOD_APPEND 0x40000000
6461 #define ENV_MOD_PREFIX 0x80000000
6462 #define ENV_MOD_MASK 0xC0000000
6464 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6466 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6468 LPCWSTR cptr = *name;
6470 static const WCHAR prefix[] = {'[','~',']',0};
6471 static const int prefix_len = 3;
6477 *flags |= ENV_ACT_SETALWAYS;
6478 else if (*cptr == '+')
6479 *flags |= ENV_ACT_SETABSENT;
6480 else if (*cptr == '-')
6481 *flags |= ENV_ACT_REMOVE;
6482 else if (*cptr == '!')
6483 *flags |= ENV_ACT_REMOVEMATCH;
6484 else if (*cptr == '*')
6485 *flags |= ENV_MOD_MACHINE;
6495 ERR("Missing environment variable\n");
6496 return ERROR_FUNCTION_FAILED;
6501 LPCWSTR ptr = *value;
6502 if (!strncmpW(ptr, prefix, prefix_len))
6504 if (ptr[prefix_len] == szSemiColon[0])
6506 *flags |= ENV_MOD_APPEND;
6507 *value += lstrlenW(prefix);
6514 else if (lstrlenW(*value) >= prefix_len)
6516 ptr += lstrlenW(ptr) - prefix_len;
6517 if (!strcmpW( ptr, prefix ))
6519 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6521 *flags |= ENV_MOD_PREFIX;
6522 /* the "[~]" will be removed by deformat_string */;
6532 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6533 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6534 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6535 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6537 ERR("Invalid flags: %08x\n", *flags);
6538 return ERROR_FUNCTION_FAILED;
6542 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6544 return ERROR_SUCCESS;
6547 static UINT open_env_key( DWORD flags, HKEY *key )
6549 static const WCHAR user_env[] =
6550 {'E','n','v','i','r','o','n','m','e','n','t',0};
6551 static const WCHAR machine_env[] =
6552 {'S','y','s','t','e','m','\\',
6553 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6554 'C','o','n','t','r','o','l','\\',
6555 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6556 'E','n','v','i','r','o','n','m','e','n','t',0};
6561 if (flags & ENV_MOD_MACHINE)
6564 root = HKEY_LOCAL_MACHINE;
6569 root = HKEY_CURRENT_USER;
6572 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6573 if (res != ERROR_SUCCESS)
6575 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6576 return ERROR_FUNCTION_FAILED;
6579 return ERROR_SUCCESS;
6582 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6584 MSIPACKAGE *package = param;
6585 LPCWSTR name, value, component;
6586 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6587 DWORD flags, type, size;
6594 component = MSI_RecordGetString(rec, 4);
6595 comp = msi_get_loaded_component(package, component);
6597 return ERROR_SUCCESS;
6599 comp->Action = msi_get_component_action( package, comp );
6600 if (comp->Action != INSTALLSTATE_LOCAL)
6602 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6603 return ERROR_SUCCESS;
6605 name = MSI_RecordGetString(rec, 2);
6606 value = MSI_RecordGetString(rec, 3);
6608 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6610 res = env_parse_flags(&name, &value, &flags);
6611 if (res != ERROR_SUCCESS || !value)
6614 if (value && !deformat_string(package, value, &deformatted))
6616 res = ERROR_OUTOFMEMORY;
6620 value = deformatted;
6622 res = open_env_key( flags, &env );
6623 if (res != ERROR_SUCCESS)
6626 if (flags & ENV_MOD_MACHINE)
6627 action |= 0x20000000;
6631 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6632 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6633 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6636 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6640 /* Nothing to do. */
6643 res = ERROR_SUCCESS;
6647 /* If we are appending but the string was empty, strip ; */
6648 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6650 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6651 newval = strdupW(value);
6654 res = ERROR_OUTOFMEMORY;
6662 /* Contrary to MSDN, +-variable to [~];path works */
6663 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6665 res = ERROR_SUCCESS;
6669 data = msi_alloc(size);
6673 return ERROR_OUTOFMEMORY;
6676 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6677 if (res != ERROR_SUCCESS)
6680 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6683 res = RegDeleteValueW(env, name);
6684 if (res != ERROR_SUCCESS)
6685 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6689 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6690 if (flags & ENV_MOD_MASK)
6694 if (flags & ENV_MOD_APPEND) multiplier++;
6695 if (flags & ENV_MOD_PREFIX) multiplier++;
6696 mod_size = lstrlenW(value) * multiplier;
6697 size += mod_size * sizeof(WCHAR);
6700 newval = msi_alloc(size);
6704 res = ERROR_OUTOFMEMORY;
6708 if (flags & ENV_MOD_PREFIX)
6710 lstrcpyW(newval, value);
6711 ptr = newval + lstrlenW(value);
6712 action |= 0x80000000;
6715 lstrcpyW(ptr, data);
6717 if (flags & ENV_MOD_APPEND)
6719 lstrcatW(newval, value);
6720 action |= 0x40000000;
6723 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6724 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6727 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6731 uirow = MSI_CreateRecord( 3 );
6732 MSI_RecordSetStringW( uirow, 1, name );
6733 MSI_RecordSetStringW( uirow, 2, newval );
6734 MSI_RecordSetInteger( uirow, 3, action );
6735 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6736 msiobj_release( &uirow->hdr );
6738 if (env) RegCloseKey(env);
6739 msi_free(deformatted);
6745 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6749 static const WCHAR ExecSeqQuery[] =
6750 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6751 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6752 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6753 if (rc != ERROR_SUCCESS)
6754 return ERROR_SUCCESS;
6756 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6757 msiobj_release(&view->hdr);
6762 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6764 MSIPACKAGE *package = param;
6765 LPCWSTR name, value, component;
6766 LPWSTR deformatted = NULL;
6775 component = MSI_RecordGetString( rec, 4 );
6776 comp = msi_get_loaded_component( package, component );
6778 return ERROR_SUCCESS;
6780 comp->Action = msi_get_component_action( package, comp );
6781 if (comp->Action != INSTALLSTATE_ABSENT)
6783 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6784 return ERROR_SUCCESS;
6786 name = MSI_RecordGetString( rec, 2 );
6787 value = MSI_RecordGetString( rec, 3 );
6789 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6791 r = env_parse_flags( &name, &value, &flags );
6792 if (r != ERROR_SUCCESS)
6795 if (!(flags & ENV_ACT_REMOVE))
6797 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6798 return ERROR_SUCCESS;
6801 if (value && !deformat_string( package, value, &deformatted ))
6802 return ERROR_OUTOFMEMORY;
6804 value = deformatted;
6806 r = open_env_key( flags, &env );
6807 if (r != ERROR_SUCCESS)
6813 if (flags & ENV_MOD_MACHINE)
6814 action |= 0x20000000;
6816 TRACE("Removing %s\n", debugstr_w(name));
6818 res = RegDeleteValueW( env, name );
6819 if (res != ERROR_SUCCESS)
6821 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6826 uirow = MSI_CreateRecord( 3 );
6827 MSI_RecordSetStringW( uirow, 1, name );
6828 MSI_RecordSetStringW( uirow, 2, value );
6829 MSI_RecordSetInteger( uirow, 3, action );
6830 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6831 msiobj_release( &uirow->hdr );
6833 if (env) RegCloseKey( env );
6834 msi_free( deformatted );
6838 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6842 static const WCHAR query[] =
6843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6844 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6846 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6847 if (rc != ERROR_SUCCESS)
6848 return ERROR_SUCCESS;
6850 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6851 msiobj_release( &view->hdr );
6856 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6858 LPWSTR key, template, id;
6859 UINT r = ERROR_SUCCESS;
6861 id = msi_dup_property( package->db, szProductID );
6865 return ERROR_SUCCESS;
6867 template = msi_dup_property( package->db, szPIDTemplate );
6868 key = msi_dup_property( package->db, szPIDKEY );
6870 if (key && template)
6872 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6873 r = msi_set_property( package->db, szProductID, key );
6875 msi_free( template );
6880 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6883 package->need_reboot = 1;
6884 return ERROR_SUCCESS;
6887 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6889 static const WCHAR szAvailableFreeReg[] =
6890 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6892 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6894 TRACE("%p %d kilobytes\n", package, space);
6896 uirow = MSI_CreateRecord( 1 );
6897 MSI_RecordSetInteger( uirow, 1, space );
6898 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6899 msiobj_release( &uirow->hdr );
6901 return ERROR_SUCCESS;
6904 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6906 TRACE("%p\n", package);
6908 msi_set_property( package->db, szRollbackDisabled, szOne );
6909 return ERROR_SUCCESS;
6912 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6914 FIXME("%p\n", package);
6915 return ERROR_SUCCESS;
6918 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6923 static const WCHAR driver_query[] = {
6924 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6925 'O','D','B','C','D','r','i','v','e','r',0 };
6927 static const WCHAR translator_query[] = {
6928 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6929 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6931 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6932 if (r == ERROR_SUCCESS)
6935 r = MSI_IterateRecords( view, &count, NULL, package );
6936 msiobj_release( &view->hdr );
6937 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6940 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6941 if (r == ERROR_SUCCESS)
6944 r = MSI_IterateRecords( view, &count, NULL, package );
6945 msiobj_release( &view->hdr );
6946 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6949 return ERROR_SUCCESS;
6952 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6954 MSIPACKAGE *package = param;
6955 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6958 if ((value = msi_dup_property( package->db, property )))
6960 FIXME("remove %s\n", debugstr_w(value));
6963 return ERROR_SUCCESS;
6966 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6971 static const WCHAR query[] =
6972 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
6973 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
6975 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6976 if (r == ERROR_SUCCESS)
6978 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6979 msiobj_release( &view->hdr );
6982 return ERROR_SUCCESS;
6985 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6987 MSIPACKAGE *package = param;
6988 int attributes = MSI_RecordGetInteger( rec, 5 );
6990 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6992 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6993 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6994 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6995 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6999 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7001 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7002 if (r != ERROR_SUCCESS)
7003 return ERROR_SUCCESS;
7007 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7008 if (r != ERROR_SUCCESS)
7009 return ERROR_SUCCESS;
7011 RegCloseKey( hkey );
7013 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7014 debugstr_w(upgrade_code), debugstr_w(version_min),
7015 debugstr_w(version_max), debugstr_w(language));
7017 return ERROR_SUCCESS;
7020 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7024 static const WCHAR query[] =
7025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7027 if (msi_get_property_int( package->db, szInstalled, 0 ))
7029 TRACE("product is installed, skipping action\n");
7030 return ERROR_SUCCESS;
7032 if (msi_get_property_int( package->db, szPreselected, 0 ))
7034 TRACE("Preselected property is set, not migrating feature states\n");
7035 return ERROR_SUCCESS;
7038 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7039 if (r == ERROR_SUCCESS)
7041 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7042 msiobj_release( &view->hdr );
7044 return ERROR_SUCCESS;
7047 static void bind_image( const char *filename, const char *path )
7049 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7051 WARN("failed to bind image %u\n", GetLastError());
7055 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7059 MSIPACKAGE *package = param;
7060 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7061 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7062 char *filenameA, *pathA;
7063 WCHAR *pathW, **path_list;
7065 if (!(file = msi_get_loaded_file( package, key )))
7067 WARN("file %s not found\n", debugstr_w(key));
7068 return ERROR_SUCCESS;
7070 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7071 path_list = msi_split_string( paths, ';' );
7072 if (!path_list) bind_image( filenameA, NULL );
7075 for (i = 0; path_list[i] && path_list[i][0]; i++)
7077 deformat_string( package, path_list[i], &pathW );
7078 if ((pathA = strdupWtoA( pathW )))
7080 bind_image( filenameA, pathA );
7086 msi_free( path_list );
7087 msi_free( filenameA );
7088 return ERROR_SUCCESS;
7091 static UINT ACTION_BindImage( MSIPACKAGE *package )
7095 static const WCHAR query[] =
7096 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','B','i','n','d','I','m','a','g','e',0};
7098 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7099 if (r == ERROR_SUCCESS)
7101 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7102 msiobj_release( &view->hdr );
7104 return ERROR_SUCCESS;
7107 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7108 LPCSTR action, LPCWSTR table )
7110 static const WCHAR query[] = {
7111 'S','E','L','E','C','T',' ','*',' ',
7112 'F','R','O','M',' ','`','%','s','`',0 };
7113 MSIQUERY *view = NULL;
7117 r = MSI_OpenQuery( package->db, &view, query, table );
7118 if (r == ERROR_SUCCESS)
7120 r = MSI_IterateRecords(view, &count, NULL, package);
7121 msiobj_release(&view->hdr);
7125 FIXME("%s -> %u ignored %s table values\n",
7126 action, count, debugstr_w(table));
7128 return ERROR_SUCCESS;
7131 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7133 static const WCHAR table[] = {
7134 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7135 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7138 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7140 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7141 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7144 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7146 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7147 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7150 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7152 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7153 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7156 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7158 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7159 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7164 const WCHAR *action;
7165 UINT (*handler)(MSIPACKAGE *);
7166 const WCHAR *action_rollback;
7170 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7171 { szAppSearch, ACTION_AppSearch, NULL },
7172 { szBindImage, ACTION_BindImage, NULL },
7173 { szCCPSearch, ACTION_CCPSearch, NULL },
7174 { szCostFinalize, ACTION_CostFinalize, NULL },
7175 { szCostInitialize, ACTION_CostInitialize, NULL },
7176 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7177 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7178 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7179 { szDisableRollback, ACTION_DisableRollback, NULL },
7180 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7181 { szExecuteAction, ACTION_ExecuteAction, NULL },
7182 { szFileCost, ACTION_FileCost, NULL },
7183 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7184 { szForceReboot, ACTION_ForceReboot, NULL },
7185 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7186 { szInstallExecute, ACTION_InstallExecute, NULL },
7187 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7188 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7189 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7190 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7191 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7192 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7193 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7194 { szInstallValidate, ACTION_InstallValidate, NULL },
7195 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7196 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7197 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7198 { szMoveFiles, ACTION_MoveFiles, NULL },
7199 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7200 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7201 { szPatchFiles, ACTION_PatchFiles, NULL },
7202 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7203 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7204 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7205 { szPublishProduct, ACTION_PublishProduct, NULL },
7206 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7207 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7208 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7209 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7210 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7211 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7212 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7213 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7214 { szRegisterUser, ACTION_RegisterUser, NULL },
7215 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7216 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7217 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7218 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7219 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7220 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7221 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7222 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7223 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7224 { szResolveSource, ACTION_ResolveSource, NULL },
7225 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7226 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7227 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7228 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7229 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7230 { szStartServices, ACTION_StartServices, szStopServices },
7231 { szStopServices, ACTION_StopServices, szStartServices },
7232 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7233 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7234 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7235 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7236 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7237 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7238 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7239 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7240 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7241 { szValidateProductID, ACTION_ValidateProductID, NULL },
7242 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7243 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7244 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7245 { NULL, NULL, NULL }
7248 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7254 while (StandardActions[i].action != NULL)
7256 if (!strcmpW( StandardActions[i].action, action ))
7258 ui_actionstart( package, action );
7259 if (StandardActions[i].handler)
7261 ui_actioninfo( package, action, TRUE, 0 );
7262 *rc = StandardActions[i].handler( package );
7263 ui_actioninfo( package, action, FALSE, *rc );
7265 if (StandardActions[i].action_rollback && !package->need_rollback)
7267 TRACE("scheduling rollback action\n");
7268 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7273 FIXME("unhandled standard action %s\n", debugstr_w(action));
7274 *rc = ERROR_SUCCESS;
7284 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7286 UINT rc = ERROR_SUCCESS;
7289 TRACE("Performing action (%s)\n", debugstr_w(action));
7291 handled = ACTION_HandleStandardAction(package, action, &rc);
7294 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7298 WARN("unhandled msi action %s\n", debugstr_w(action));
7299 rc = ERROR_FUNCTION_NOT_CALLED;
7305 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7307 UINT rc = ERROR_SUCCESS;
7308 BOOL handled = FALSE;
7310 TRACE("Performing action (%s)\n", debugstr_w(action));
7312 handled = ACTION_HandleStandardAction(package, action, &rc);
7315 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7317 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7322 WARN("unhandled msi action %s\n", debugstr_w(action));
7323 rc = ERROR_FUNCTION_NOT_CALLED;
7329 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7331 UINT rc = ERROR_SUCCESS;
7334 static const WCHAR ExecSeqQuery[] =
7335 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7336 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7337 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7338 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7339 static const WCHAR UISeqQuery[] =
7340 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7341 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7342 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7343 ' ', '=',' ','%','i',0};
7345 if (needs_ui_sequence(package))
7346 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7348 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7352 LPCWSTR action, cond;
7354 TRACE("Running the actions\n");
7356 /* check conditions */
7357 cond = MSI_RecordGetString(row, 2);
7359 /* this is a hack to skip errors in the condition code */
7360 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7362 msiobj_release(&row->hdr);
7363 return ERROR_SUCCESS;
7366 action = MSI_RecordGetString(row, 1);
7369 ERR("failed to fetch action\n");
7370 msiobj_release(&row->hdr);
7371 return ERROR_FUNCTION_FAILED;
7374 if (needs_ui_sequence(package))
7375 rc = ACTION_PerformUIAction(package, action, -1);
7377 rc = ACTION_PerformAction(package, action, -1);
7379 msiobj_release(&row->hdr);
7385 /****************************************************
7386 * TOP level entry points
7387 *****************************************************/
7389 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7390 LPCWSTR szCommandLine )
7394 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7395 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7396 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7398 msi_set_property( package->db, szAction, szInstall );
7400 package->script->InWhatSequence = SEQUENCE_INSTALL;
7407 dir = strdupW(szPackagePath);
7408 p = strrchrW(dir, '\\');
7412 file = szPackagePath + (p - dir);
7417 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7418 GetCurrentDirectoryW(MAX_PATH, dir);
7419 lstrcatW(dir, szBackSlash);
7420 file = szPackagePath;
7423 msi_free( package->PackagePath );
7424 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7425 if (!package->PackagePath)
7428 return ERROR_OUTOFMEMORY;
7431 lstrcpyW(package->PackagePath, dir);
7432 lstrcatW(package->PackagePath, file);
7435 msi_set_sourcedir_props(package, FALSE);
7438 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7439 if (rc != ERROR_SUCCESS)
7442 msi_apply_transforms( package );
7443 msi_apply_patches( package );
7445 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7447 TRACE("setting reinstall property\n");
7448 msi_set_property( package->db, szReinstall, szAll );
7451 /* properties may have been added by a transform */
7452 msi_clone_properties( package );
7454 msi_parse_command_line( package, szCommandLine, FALSE );
7455 msi_adjust_privilege_properties( package );
7456 msi_set_context( package );
7458 if (msi_get_property_int( package->db, szInstalled, 0 ))
7461 DeleteFileW( package->localfile );
7462 msi_free( package->localfile );
7463 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
7464 package->localfile = msi_reg_get_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW );
7465 RegCloseKey( hkey );
7467 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7469 TRACE("disabling rollback\n");
7470 msi_set_property( package->db, szRollbackDisabled, szOne );
7473 if (needs_ui_sequence( package))
7475 package->script->InWhatSequence |= SEQUENCE_UI;
7476 rc = ACTION_ProcessUISequence(package);
7477 ui_exists = ui_sequence_exists(package);
7478 if (rc == ERROR_SUCCESS || !ui_exists)
7480 package->script->InWhatSequence |= SEQUENCE_EXEC;
7481 rc = ACTION_ProcessExecSequence(package, ui_exists);
7485 rc = ACTION_ProcessExecSequence(package, FALSE);
7487 package->script->CurrentlyScripting = FALSE;
7489 /* process the ending type action */
7490 if (rc == ERROR_SUCCESS)
7491 ACTION_PerformActionSequence(package, -1);
7492 else if (rc == ERROR_INSTALL_USEREXIT)
7493 ACTION_PerformActionSequence(package, -2);
7494 else if (rc == ERROR_INSTALL_SUSPEND)
7495 ACTION_PerformActionSequence(package, -4);
7498 ACTION_PerformActionSequence(package, -3);
7499 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7501 package->need_rollback = TRUE;
7505 /* finish up running custom actions */
7506 ACTION_FinishCustomActions(package);
7508 if (package->need_rollback)
7510 WARN("installation failed, running rollback script\n");
7511 execute_script( package, ROLLBACK_SCRIPT );
7514 if (rc == ERROR_SUCCESS && package->need_reboot)
7515 return ERROR_SUCCESS_REBOOT_REQUIRED;