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:
231 if (in_quotes && p[1] != '\"') count--;
247 if (in_quotes) count--;
251 state = state_whitespace;
252 if (!count) goto done;
257 if (!count) in_quotes = 0;
268 if (in_quotes && p[1] != '\"') count--;
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
279 if (!count) in_quotes = 0;
288 if (!ignore) *out++ = *p;
292 if (!len) *value = 0;
299 static void remove_quotes( WCHAR *str )
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
321 return ERROR_SUCCESS;
326 while (*ptr == ' ') ptr++;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
338 if (!preserve_case) struprW( prop );
341 while (*ptr2 == ' ') ptr2++;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
348 WARN("unbalanced quotes\n");
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
372 LPWSTR p, *ret = NULL;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
395 for( count = 0; (ret[count] = p); count++ )
397 p = strchrW( p, sep );
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 db = msi_dup_property( package->db, szOriginalDatabase );
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
448 p = strrchrW( db, '/' );
452 return ERROR_SUCCESS;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
543 rc = ACTION_ForceReboot( package );
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property(package->db, szSourceDir, NULL);
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
736 if (!(slash = strrchrW( new_path, '\\' )))
741 len = slash - new_path;
743 if (!msi_create_full_path( new_path ))
748 new_path[len] = '\\';
750 msi_free( new_path );
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 return comp->ActionRequest;
815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
817 if (package->need_rollback) return feature->Installed;
818 return feature->ActionRequest;
821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
823 MSIPACKAGE *package = param;
824 LPCWSTR dir, component, full_path;
829 component = MSI_RecordGetString(row, 2);
831 return ERROR_SUCCESS;
833 comp = msi_get_loaded_component(package, component);
835 return ERROR_SUCCESS;
837 comp->Action = msi_get_component_action( package, comp );
838 if (comp->Action != INSTALLSTATE_LOCAL)
840 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
841 return ERROR_SUCCESS;
844 dir = MSI_RecordGetString(row,1);
847 ERR("Unable to get folder id\n");
848 return ERROR_SUCCESS;
851 uirow = MSI_CreateRecord(1);
852 MSI_RecordSetStringW(uirow, 1, dir);
853 msi_ui_actiondata(package, szCreateFolders, uirow);
854 msiobj_release(&uirow->hdr);
856 full_path = msi_get_target_folder( package, dir );
859 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
860 return ERROR_SUCCESS;
862 TRACE("folder is %s\n", debugstr_w(full_path));
864 folder = msi_get_loaded_folder( package, dir );
865 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
866 folder->State = FOLDER_STATE_CREATED;
867 return ERROR_SUCCESS;
870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
872 static const WCHAR query[] = {
873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
874 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
879 if (rc != ERROR_SUCCESS)
880 return ERROR_SUCCESS;
882 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
883 msiobj_release(&view->hdr);
887 static void remove_persistent_folder( MSIFOLDER *folder )
891 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
893 remove_persistent_folder( fl->folder );
895 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
897 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
903 MSIPACKAGE *package = param;
904 LPCWSTR dir, component, full_path;
909 component = MSI_RecordGetString(row, 2);
911 return ERROR_SUCCESS;
913 comp = msi_get_loaded_component(package, component);
915 return ERROR_SUCCESS;
917 comp->Action = msi_get_component_action( package, comp );
918 if (comp->Action != INSTALLSTATE_ABSENT)
920 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
921 return ERROR_SUCCESS;
924 dir = MSI_RecordGetString( row, 1 );
927 ERR("Unable to get folder id\n");
928 return ERROR_SUCCESS;
931 full_path = msi_get_target_folder( package, dir );
934 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
935 return ERROR_SUCCESS;
937 TRACE("folder is %s\n", debugstr_w(full_path));
939 uirow = MSI_CreateRecord( 1 );
940 MSI_RecordSetStringW( uirow, 1, dir );
941 msi_ui_actiondata( package, szRemoveFolders, uirow );
942 msiobj_release( &uirow->hdr );
944 folder = msi_get_loaded_folder( package, dir );
945 remove_persistent_folder( folder );
946 return ERROR_SUCCESS;
949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
951 static const WCHAR query[] = {
952 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
953 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
957 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
958 if (rc != ERROR_SUCCESS)
959 return ERROR_SUCCESS;
961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
962 msiobj_release( &view->hdr );
966 static UINT load_component( MSIRECORD *row, LPVOID param )
968 MSIPACKAGE *package = param;
971 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
973 return ERROR_FUNCTION_FAILED;
975 list_add_tail( &package->components, &comp->entry );
977 /* fill in the data */
978 comp->Component = msi_dup_record_field( row, 1 );
980 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
982 comp->ComponentId = msi_dup_record_field( row, 2 );
983 comp->Directory = msi_dup_record_field( row, 3 );
984 comp->Attributes = MSI_RecordGetInteger(row,4);
985 comp->Condition = msi_dup_record_field( row, 5 );
986 comp->KeyPath = msi_dup_record_field( row, 6 );
988 comp->Installed = INSTALLSTATE_UNKNOWN;
989 comp->Action = INSTALLSTATE_UNKNOWN;
990 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
992 comp->assembly = msi_load_assembly( package, comp );
993 return ERROR_SUCCESS;
996 UINT msi_load_all_components( MSIPACKAGE *package )
998 static const WCHAR query[] = {
999 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1000 '`','C','o','m','p','o','n','e','n','t','`',0};
1004 if (!list_empty(&package->components))
1005 return ERROR_SUCCESS;
1007 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1008 if (r != ERROR_SUCCESS)
1011 if (!msi_init_assembly_caches( package ))
1013 ERR("can't initialize assembly caches\n");
1014 msiobj_release( &view->hdr );
1015 return ERROR_FUNCTION_FAILED;
1018 r = MSI_IterateRecords(view, NULL, load_component, package);
1019 msiobj_release(&view->hdr);
1024 MSIPACKAGE *package;
1025 MSIFEATURE *feature;
1028 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1032 cl = msi_alloc( sizeof (*cl) );
1034 return ERROR_NOT_ENOUGH_MEMORY;
1035 cl->component = comp;
1036 list_add_tail( &feature->Components, &cl->entry );
1038 return ERROR_SUCCESS;
1041 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1045 fl = msi_alloc( sizeof(*fl) );
1047 return ERROR_NOT_ENOUGH_MEMORY;
1048 fl->feature = child;
1049 list_add_tail( &parent->Children, &fl->entry );
1051 return ERROR_SUCCESS;
1054 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1056 _ilfs* ilfs = param;
1060 component = MSI_RecordGetString(row,1);
1062 /* check to see if the component is already loaded */
1063 comp = msi_get_loaded_component( ilfs->package, component );
1066 WARN("ignoring unknown component %s\n", debugstr_w(component));
1067 return ERROR_SUCCESS;
1069 add_feature_component( ilfs->feature, comp );
1070 comp->Enabled = TRUE;
1072 return ERROR_SUCCESS;
1075 static UINT load_feature(MSIRECORD * row, LPVOID param)
1077 static const WCHAR query[] = {
1078 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1079 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1080 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1081 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1082 MSIPACKAGE *package = param;
1083 MSIFEATURE *feature;
1088 /* fill in the data */
1090 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1092 return ERROR_NOT_ENOUGH_MEMORY;
1094 list_init( &feature->Children );
1095 list_init( &feature->Components );
1097 feature->Feature = msi_dup_record_field( row, 1 );
1099 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1101 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1102 feature->Title = msi_dup_record_field( row, 3 );
1103 feature->Description = msi_dup_record_field( row, 4 );
1105 if (!MSI_RecordIsNull(row,5))
1106 feature->Display = MSI_RecordGetInteger(row,5);
1108 feature->Level= MSI_RecordGetInteger(row,6);
1109 feature->Directory = msi_dup_record_field( row, 7 );
1110 feature->Attributes = MSI_RecordGetInteger(row,8);
1112 feature->Installed = INSTALLSTATE_UNKNOWN;
1113 feature->Action = INSTALLSTATE_UNKNOWN;
1114 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1116 list_add_tail( &package->features, &feature->entry );
1118 /* load feature components */
1120 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1121 if (rc != ERROR_SUCCESS)
1122 return ERROR_SUCCESS;
1124 ilfs.package = package;
1125 ilfs.feature = feature;
1127 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1128 msiobj_release(&view->hdr);
1132 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1134 MSIPACKAGE *package = param;
1135 MSIFEATURE *parent, *child;
1137 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1139 return ERROR_FUNCTION_FAILED;
1141 if (!child->Feature_Parent)
1142 return ERROR_SUCCESS;
1144 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1146 return ERROR_FUNCTION_FAILED;
1148 add_feature_child( parent, child );
1149 return ERROR_SUCCESS;
1152 UINT msi_load_all_features( MSIPACKAGE *package )
1154 static const WCHAR query[] = {
1155 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1156 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1157 '`','D','i','s','p','l','a','y','`',0};
1161 if (!list_empty(&package->features))
1162 return ERROR_SUCCESS;
1164 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1165 if (r != ERROR_SUCCESS)
1168 r = MSI_IterateRecords( view, NULL, load_feature, package );
1169 if (r != ERROR_SUCCESS)
1171 msiobj_release( &view->hdr );
1174 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1175 msiobj_release( &view->hdr );
1179 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1190 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1192 static const WCHAR query[] = {
1193 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1194 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1195 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1196 MSIQUERY *view = NULL;
1197 MSIRECORD *row = NULL;
1200 TRACE("%s\n", debugstr_w(file->File));
1202 r = MSI_OpenQuery(package->db, &view, query, file->File);
1203 if (r != ERROR_SUCCESS)
1206 r = MSI_ViewExecute(view, NULL);
1207 if (r != ERROR_SUCCESS)
1210 r = MSI_ViewFetch(view, &row);
1211 if (r != ERROR_SUCCESS)
1214 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1215 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1216 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1217 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1218 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1221 if (view) msiobj_release(&view->hdr);
1222 if (row) msiobj_release(&row->hdr);
1226 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1229 static const WCHAR query[] = {
1230 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1231 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1232 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1234 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1237 WARN("query failed\n");
1238 return ERROR_FUNCTION_FAILED;
1241 file->disk_id = MSI_RecordGetInteger( row, 1 );
1242 msiobj_release( &row->hdr );
1243 return ERROR_SUCCESS;
1246 static UINT load_file(MSIRECORD *row, LPVOID param)
1248 MSIPACKAGE* package = param;
1252 /* fill in the data */
1254 file = msi_alloc_zero( sizeof (MSIFILE) );
1256 return ERROR_NOT_ENOUGH_MEMORY;
1258 file->File = msi_dup_record_field( row, 1 );
1260 component = MSI_RecordGetString( row, 2 );
1261 file->Component = msi_get_loaded_component( package, component );
1263 if (!file->Component)
1265 WARN("Component not found: %s\n", debugstr_w(component));
1266 msi_free(file->File);
1268 return ERROR_SUCCESS;
1271 file->FileName = msi_dup_record_field( row, 3 );
1272 msi_reduce_to_long_filename( file->FileName );
1274 file->ShortName = msi_dup_record_field( row, 3 );
1275 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1277 file->FileSize = MSI_RecordGetInteger( row, 4 );
1278 file->Version = msi_dup_record_field( row, 5 );
1279 file->Language = msi_dup_record_field( row, 6 );
1280 file->Attributes = MSI_RecordGetInteger( row, 7 );
1281 file->Sequence = MSI_RecordGetInteger( row, 8 );
1283 file->state = msifs_invalid;
1285 /* if the compressed bits are not set in the file attributes,
1286 * then read the information from the package word count property
1288 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1290 file->IsCompressed = FALSE;
1292 else if (file->Attributes &
1293 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1295 file->IsCompressed = TRUE;
1297 else if (file->Attributes & msidbFileAttributesNoncompressed)
1299 file->IsCompressed = FALSE;
1303 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1306 load_file_hash(package, file);
1307 load_file_disk_id(package, file);
1309 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1311 list_add_tail( &package->files, &file->entry );
1313 return ERROR_SUCCESS;
1316 static UINT load_all_files(MSIPACKAGE *package)
1318 static const WCHAR query[] = {
1319 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1320 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1321 '`','S','e','q','u','e','n','c','e','`', 0};
1325 if (!list_empty(&package->files))
1326 return ERROR_SUCCESS;
1328 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1329 if (rc != ERROR_SUCCESS)
1330 return ERROR_SUCCESS;
1332 rc = MSI_IterateRecords(view, NULL, load_file, package);
1333 msiobj_release(&view->hdr);
1337 static UINT load_media( MSIRECORD *row, LPVOID param )
1339 MSIPACKAGE *package = param;
1340 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1341 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1343 /* FIXME: load external cabinets and directory sources too */
1344 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1345 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1346 return ERROR_SUCCESS;
1349 static UINT load_all_media( MSIPACKAGE *package )
1351 static const WCHAR query[] = {
1352 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1353 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1354 '`','D','i','s','k','I','d','`',0};
1358 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1359 if (r != ERROR_SUCCESS)
1360 return ERROR_SUCCESS;
1362 r = MSI_IterateRecords( view, NULL, load_media, package );
1363 msiobj_release( &view->hdr );
1367 static UINT load_patch(MSIRECORD *row, LPVOID param)
1369 MSIPACKAGE *package = param;
1370 MSIFILEPATCH *patch;
1373 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1375 return ERROR_NOT_ENOUGH_MEMORY;
1377 file_key = msi_dup_record_field( row, 1 );
1378 patch->File = msi_get_loaded_file( package, file_key );
1383 ERR("Failed to find target for patch in File table\n");
1385 return ERROR_FUNCTION_FAILED;
1388 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1390 /* FIXME: The database should be properly transformed */
1391 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1393 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1394 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1395 patch->IsApplied = FALSE;
1398 * Header field - for patch validation.
1399 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1402 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1404 list_add_tail( &package->filepatches, &patch->entry );
1406 return ERROR_SUCCESS;
1409 static UINT load_all_patches(MSIPACKAGE *package)
1411 static const WCHAR query[] = {
1412 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1413 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1414 '`','S','e','q','u','e','n','c','e','`',0};
1418 if (!list_empty(&package->filepatches))
1419 return ERROR_SUCCESS;
1421 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1422 if (rc != ERROR_SUCCESS)
1423 return ERROR_SUCCESS;
1425 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1426 msiobj_release(&view->hdr);
1430 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1432 static const WCHAR query[] = {
1433 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1434 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1435 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1438 folder->persistent = FALSE;
1439 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1441 if (!MSI_ViewExecute( view, NULL ))
1444 if (!MSI_ViewFetch( view, &rec ))
1446 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1447 folder->persistent = TRUE;
1448 msiobj_release( &rec->hdr );
1451 msiobj_release( &view->hdr );
1453 return ERROR_SUCCESS;
1456 static UINT load_folder( MSIRECORD *row, LPVOID param )
1458 MSIPACKAGE *package = param;
1459 static WCHAR szEmpty[] = { 0 };
1460 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1463 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1464 list_init( &folder->children );
1465 folder->Directory = msi_dup_record_field( row, 1 );
1466 folder->Parent = msi_dup_record_field( row, 2 );
1467 p = msi_dup_record_field(row, 3);
1469 TRACE("%s\n", debugstr_w(folder->Directory));
1471 /* split src and target dir */
1473 src_short = folder_split_path( p, ':' );
1475 /* split the long and short paths */
1476 tgt_long = folder_split_path( tgt_short, '|' );
1477 src_long = folder_split_path( src_short, '|' );
1479 /* check for no-op dirs */
1480 if (tgt_short && !strcmpW( szDot, tgt_short ))
1481 tgt_short = szEmpty;
1482 if (src_short && !strcmpW( szDot, src_short ))
1483 src_short = szEmpty;
1486 tgt_long = tgt_short;
1489 src_short = tgt_short;
1490 src_long = tgt_long;
1494 src_long = src_short;
1496 /* FIXME: use the target short path too */
1497 folder->TargetDefault = strdupW(tgt_long);
1498 folder->SourceShortPath = strdupW(src_short);
1499 folder->SourceLongPath = strdupW(src_long);
1502 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1503 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1504 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1506 load_folder_persistence( package, folder );
1508 list_add_tail( &package->folders, &folder->entry );
1509 return ERROR_SUCCESS;
1512 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1516 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1518 list_add_tail( &parent->children, &fl->entry );
1519 return ERROR_SUCCESS;
1522 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1524 MSIPACKAGE *package = param;
1525 MSIFOLDER *parent, *child;
1527 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1528 return ERROR_FUNCTION_FAILED;
1530 if (!child->Parent) return ERROR_SUCCESS;
1532 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1533 return ERROR_FUNCTION_FAILED;
1535 return add_folder_child( parent, child );
1538 static UINT load_all_folders( MSIPACKAGE *package )
1540 static const WCHAR query[] = {
1541 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1542 '`','D','i','r','e','c','t','o','r','y','`',0};
1546 if (!list_empty(&package->folders))
1547 return ERROR_SUCCESS;
1549 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1550 if (r != ERROR_SUCCESS)
1553 r = MSI_IterateRecords( view, NULL, load_folder, package );
1554 if (r != ERROR_SUCCESS)
1556 msiobj_release( &view->hdr );
1559 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1560 msiobj_release( &view->hdr );
1564 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1566 msi_set_property( package->db, szCostingComplete, szZero );
1567 msi_set_property( package->db, szRootDrive, szCRoot );
1569 load_all_folders( package );
1570 msi_load_all_components( package );
1571 msi_load_all_features( package );
1572 load_all_files( package );
1573 load_all_patches( package );
1574 load_all_media( package );
1576 return ERROR_SUCCESS;
1579 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1581 const WCHAR *action = package->script->Actions[script][index];
1582 ui_actionstart( package, action );
1583 TRACE("executing %s\n", debugstr_w(action));
1584 return ACTION_PerformAction( package, action, script );
1587 static UINT execute_script( MSIPACKAGE *package, UINT script )
1589 UINT i, rc = ERROR_SUCCESS;
1591 TRACE("executing script %u\n", script);
1593 if (!package->script)
1595 ERR("no script!\n");
1596 return ERROR_FUNCTION_FAILED;
1598 if (script == SCRIPT_ROLLBACK)
1600 for (i = package->script->ActionCount[script]; i > 0; i--)
1602 rc = execute_script_action( package, script, i - 1 );
1603 if (rc != ERROR_SUCCESS) break;
1608 for (i = 0; i < package->script->ActionCount[script]; i++)
1610 rc = execute_script_action( package, script, i );
1611 if (rc != ERROR_SUCCESS) break;
1614 msi_free_action_script(package, script);
1618 static UINT ACTION_FileCost(MSIPACKAGE *package)
1620 return ERROR_SUCCESS;
1623 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1628 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1630 if (!comp->ComponentId) continue;
1632 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1633 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1635 if (r == ERROR_SUCCESS) continue;
1637 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1638 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1640 if (r == ERROR_SUCCESS) continue;
1642 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1643 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1645 if (r == ERROR_SUCCESS) continue;
1647 comp->Installed = INSTALLSTATE_ABSENT;
1651 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1653 MSIFEATURE *feature;
1655 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1657 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1659 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1660 feature->Installed = INSTALLSTATE_ABSENT;
1662 feature->Installed = state;
1666 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1668 return (feature->Level > 0 && feature->Level <= level);
1671 static BOOL process_state_property(MSIPACKAGE* package, int level,
1672 LPCWSTR property, INSTALLSTATE state)
1675 MSIFEATURE *feature;
1677 override = msi_dup_property( package->db, property );
1681 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1686 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1688 if (!strcmpiW( override, szAll ))
1690 if (feature->Installed != state)
1692 feature->Action = state;
1693 feature->ActionRequest = state;
1698 LPWSTR ptr = override;
1699 LPWSTR ptr2 = strchrW(override,',');
1703 int len = ptr2 - ptr;
1705 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1706 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1708 if (feature->Installed != state)
1710 feature->Action = state;
1711 feature->ActionRequest = state;
1718 ptr2 = strchrW(ptr,',');
1729 static BOOL process_overrides( MSIPACKAGE *package, int level )
1731 static const WCHAR szAddLocal[] =
1732 {'A','D','D','L','O','C','A','L',0};
1733 static const WCHAR szAddSource[] =
1734 {'A','D','D','S','O','U','R','C','E',0};
1735 static const WCHAR szAdvertise[] =
1736 {'A','D','V','E','R','T','I','S','E',0};
1739 /* all these activation/deactivation things happen in order and things
1740 * later on the list override things earlier on the list.
1742 * 0 INSTALLLEVEL processing
1755 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1756 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1757 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1758 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1759 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1762 msi_set_property( package->db, szPreselected, szOne );
1767 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1770 MSICOMPONENT* component;
1771 MSIFEATURE *feature;
1773 TRACE("Checking Install Level\n");
1775 level = msi_get_property_int(package->db, szInstallLevel, 1);
1777 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1779 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1781 if (!is_feature_selected( feature, level )) continue;
1783 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1785 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1787 feature->Action = INSTALLSTATE_SOURCE;
1788 feature->ActionRequest = INSTALLSTATE_SOURCE;
1790 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1792 feature->Action = INSTALLSTATE_ADVERTISED;
1793 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1797 feature->Action = INSTALLSTATE_LOCAL;
1798 feature->ActionRequest = INSTALLSTATE_LOCAL;
1802 /* disable child features of unselected parent or follow parent */
1803 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1807 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1809 if (!is_feature_selected( feature, level ))
1811 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1812 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1814 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1816 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1817 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1818 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1819 fl->feature->Action = feature->Action;
1820 fl->feature->ActionRequest = feature->ActionRequest;
1825 else /* preselected */
1827 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1829 if (!is_feature_selected( feature, level )) continue;
1831 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1833 if (feature->Installed == INSTALLSTATE_ABSENT)
1835 feature->Action = INSTALLSTATE_UNKNOWN;
1836 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1840 feature->Action = feature->Installed;
1841 feature->ActionRequest = feature->Installed;
1845 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1849 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1851 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1852 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1854 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1855 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1856 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1857 fl->feature->Action = feature->Action;
1858 fl->feature->ActionRequest = feature->ActionRequest;
1864 /* now we want to set component state based based on feature state */
1865 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1869 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1870 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1871 feature->ActionRequest, feature->Action);
1873 if (!is_feature_selected( feature, level )) continue;
1875 /* features with components that have compressed files are made local */
1876 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1878 if (cl->component->ForceLocalState &&
1879 feature->ActionRequest == INSTALLSTATE_SOURCE)
1881 feature->Action = INSTALLSTATE_LOCAL;
1882 feature->ActionRequest = INSTALLSTATE_LOCAL;
1887 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1889 component = cl->component;
1891 switch (feature->ActionRequest)
1893 case INSTALLSTATE_ABSENT:
1894 component->anyAbsent = 1;
1896 case INSTALLSTATE_ADVERTISED:
1897 component->hasAdvertiseFeature = 1;
1899 case INSTALLSTATE_SOURCE:
1900 component->hasSourceFeature = 1;
1902 case INSTALLSTATE_LOCAL:
1903 component->hasLocalFeature = 1;
1905 case INSTALLSTATE_DEFAULT:
1906 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1907 component->hasAdvertiseFeature = 1;
1908 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1909 component->hasSourceFeature = 1;
1911 component->hasLocalFeature = 1;
1919 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1921 /* check if it's local or source */
1922 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1923 (component->hasLocalFeature || component->hasSourceFeature))
1925 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1926 !component->ForceLocalState)
1928 component->Action = INSTALLSTATE_SOURCE;
1929 component->ActionRequest = INSTALLSTATE_SOURCE;
1933 component->Action = INSTALLSTATE_LOCAL;
1934 component->ActionRequest = INSTALLSTATE_LOCAL;
1939 /* if any feature is local, the component must be local too */
1940 if (component->hasLocalFeature)
1942 component->Action = INSTALLSTATE_LOCAL;
1943 component->ActionRequest = INSTALLSTATE_LOCAL;
1946 if (component->hasSourceFeature)
1948 component->Action = INSTALLSTATE_SOURCE;
1949 component->ActionRequest = INSTALLSTATE_SOURCE;
1952 if (component->hasAdvertiseFeature)
1954 component->Action = INSTALLSTATE_ADVERTISED;
1955 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1958 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1959 if (component->anyAbsent &&
1960 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1962 component->Action = INSTALLSTATE_ABSENT;
1963 component->ActionRequest = INSTALLSTATE_ABSENT;
1967 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1969 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1971 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1972 component->Action = INSTALLSTATE_LOCAL;
1973 component->ActionRequest = INSTALLSTATE_LOCAL;
1976 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1977 component->Installed == INSTALLSTATE_SOURCE &&
1978 component->hasSourceFeature)
1980 component->Action = INSTALLSTATE_UNKNOWN;
1981 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1984 TRACE("component %s (installed %d request %d action %d)\n",
1985 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1988 return ERROR_SUCCESS;
1991 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1993 MSIPACKAGE *package = param;
1995 MSIFEATURE *feature;
1997 name = MSI_RecordGetString( row, 1 );
1999 feature = msi_get_loaded_feature( package, name );
2001 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2005 Condition = MSI_RecordGetString(row,3);
2007 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2009 int level = MSI_RecordGetInteger(row,2);
2010 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2011 feature->Level = level;
2014 return ERROR_SUCCESS;
2017 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2019 static const WCHAR name[] = {'\\',0};
2020 VS_FIXEDFILEINFO *ptr, *ret;
2022 DWORD versize, handle;
2025 versize = GetFileVersionInfoSizeW( filename, &handle );
2029 version = msi_alloc( versize );
2033 GetFileVersionInfoW( filename, 0, versize, version );
2035 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2037 msi_free( version );
2041 ret = msi_alloc( sz );
2042 memcpy( ret, ptr, sz );
2044 msi_free( version );
2048 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2052 msi_parse_version_string( version, &ms, &ls );
2054 if (fi->dwFileVersionMS > ms) return 1;
2055 else if (fi->dwFileVersionMS < ms) return -1;
2056 else if (fi->dwFileVersionLS > ls) return 1;
2057 else if (fi->dwFileVersionLS < ls) return -1;
2061 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2065 msi_parse_version_string( ver1, &ms1, NULL );
2066 msi_parse_version_string( ver2, &ms2, NULL );
2068 if (ms1 > ms2) return 1;
2069 else if (ms1 < ms2) return -1;
2073 DWORD msi_get_disk_file_size( LPCWSTR filename )
2078 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2079 if (file == INVALID_HANDLE_VALUE)
2080 return INVALID_FILE_SIZE;
2082 size = GetFileSize( file, NULL );
2083 TRACE("size is %u\n", size);
2084 CloseHandle( file );
2088 BOOL msi_file_hash_matches( MSIFILE *file )
2091 MSIFILEHASHINFO hash;
2093 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2094 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2095 if (r != ERROR_SUCCESS)
2098 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2101 static WCHAR *get_temp_dir( void )
2104 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2106 GetTempPathW( MAX_PATH, tmp );
2109 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2110 if (CreateDirectoryW( dir, NULL )) break;
2112 return strdupW( dir );
2116 * msi_build_directory_name()
2118 * This function is to save messing round with directory names
2119 * It handles adding backslashes between path segments,
2120 * and can add \ at the end of the directory name if told to.
2122 * It takes a variable number of arguments.
2123 * It always allocates a new string for the result, so make sure
2124 * to free the return value when finished with it.
2126 * The first arg is the number of path segments that follow.
2127 * The arguments following count are a list of path segments.
2128 * A path segment may be NULL.
2130 * Path segments will be added with a \ separating them.
2131 * A \ will not be added after the last segment, however if the
2132 * last segment is NULL, then the last character will be a \
2134 WCHAR *msi_build_directory_name( DWORD count, ... )
2140 va_start( va, count );
2141 for (i = 0; i < count; i++)
2143 const WCHAR *str = va_arg( va, const WCHAR * );
2144 if (str) sz += strlenW( str ) + 1;
2148 dir = msi_alloc( sz * sizeof(WCHAR) );
2151 va_start( va, count );
2152 for (i = 0; i < count; i++)
2154 const WCHAR *str = va_arg( va, const WCHAR * );
2156 strcatW( dir, str );
2157 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2163 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2165 MSIASSEMBLY *assembly = file->Component->assembly;
2167 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2169 msi_free( file->TargetPath );
2170 if (assembly && !assembly->application)
2172 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2173 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2174 msi_track_tempfile( package, file->TargetPath );
2178 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2179 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2182 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2185 static UINT calculate_file_cost( MSIPACKAGE *package )
2187 VS_FIXEDFILEINFO *file_version;
2188 WCHAR *font_version;
2191 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2193 MSICOMPONENT *comp = file->Component;
2196 if (!comp->Enabled) continue;
2198 if (file->IsCompressed)
2199 comp->ForceLocalState = TRUE;
2201 set_target_path( package, file );
2203 if ((comp->assembly && !comp->assembly->installed) ||
2204 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2206 comp->Cost += file->FileSize;
2209 file_size = msi_get_disk_file_size( file->TargetPath );
2213 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2215 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2217 comp->Cost += file->FileSize - file_size;
2219 msi_free( file_version );
2222 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2224 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2226 comp->Cost += file->FileSize - file_size;
2228 msi_free( font_version );
2232 if (file_size != file->FileSize)
2234 comp->Cost += file->FileSize - file_size;
2237 return ERROR_SUCCESS;
2240 WCHAR *msi_normalize_path( const WCHAR *in )
2242 const WCHAR *p = in;
2244 int n, len = strlenW( in ) + 2;
2246 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2251 /* copy until the end of the string or a space */
2252 while (*p != ' ' && (*q = *p))
2255 /* reduce many backslashes to one */
2256 if (*p != '\\' || *q != '\\')
2260 /* quit at the end of the string */
2264 /* count the number of spaces */
2269 /* if it's leading or trailing space, skip it */
2270 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2272 else /* copy n spaces */
2273 while (n && (*q++ = *p++)) n--;
2275 while (q - ret > 0 && q[-1] == ' ') q--;
2276 if (q - ret > 0 && q[-1] != '\\')
2284 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2287 MSIFOLDER *folder, *parent, *child;
2288 WCHAR *path, *normalized_path;
2290 TRACE("resolving %s\n", debugstr_w(name));
2292 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2294 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2296 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2298 path = msi_dup_property( package->db, szRootDrive );
2301 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2303 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2305 parent = msi_get_loaded_folder( package, folder->Parent );
2306 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2309 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2311 normalized_path = msi_normalize_path( path );
2313 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2315 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2316 msi_free( normalized_path );
2319 msi_set_property( package->db, folder->Directory, normalized_path );
2320 msi_free( folder->ResolvedTarget );
2321 folder->ResolvedTarget = normalized_path;
2323 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2326 msi_resolve_target_folder( package, child->Directory, load_prop );
2328 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2331 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2333 static const WCHAR query[] = {
2334 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2335 '`','C','o','n','d','i','t','i','o','n','`',0};
2336 static const WCHAR szOutOfDiskSpace[] = {
2337 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2343 TRACE("Building directory properties\n");
2344 msi_resolve_target_folder( package, szTargetDir, TRUE );
2346 TRACE("Evaluating component conditions\n");
2347 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2349 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2351 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2352 comp->Enabled = FALSE;
2355 comp->Enabled = TRUE;
2358 /* read components states from the registry */
2359 ACTION_GetComponentInstallStates(package);
2360 ACTION_GetFeatureInstallStates(package);
2362 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2364 TRACE("Evaluating feature conditions\n");
2366 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2367 if (rc == ERROR_SUCCESS)
2369 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2370 msiobj_release( &view->hdr );
2371 if (rc != ERROR_SUCCESS)
2376 TRACE("Calculating file cost\n");
2377 calculate_file_cost( package );
2379 msi_set_property( package->db, szCostingComplete, szOne );
2380 /* set default run level if not set */
2381 level = msi_dup_property( package->db, szInstallLevel );
2383 msi_set_property( package->db, szInstallLevel, szOne );
2386 /* FIXME: check volume disk space */
2387 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2389 return MSI_SetFeatureStates(package);
2392 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, DWORD *size)
2398 data = (LPSTR)strdupW(szEmpty);
2399 *size = sizeof(szEmpty);
2403 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2409 LPWSTR deformated = NULL;
2412 deformat_string(package, &value[2], &deformated);
2414 /* binary value type */
2418 *size = (strlenW(ptr)/2)+1;
2420 *size = strlenW(ptr)/2;
2422 data = msi_alloc(*size);
2428 /* if uneven pad with a zero in front */
2434 data[count] = (BYTE)strtol(byte,NULL,0);
2436 TRACE("Uneven byte count\n");
2444 data[count] = (BYTE)strtol(byte,NULL,0);
2447 msi_free(deformated);
2449 TRACE("Data %i bytes(%i)\n",*size,count);
2456 deformat_string(package, &value[1], &deformated);
2459 *size = sizeof(DWORD);
2460 data = msi_alloc(*size);
2466 if ( (*p < '0') || (*p > '9') )
2472 if (deformated[0] == '-')
2475 TRACE("DWORD %i\n",*(LPDWORD)data);
2477 msi_free(deformated);
2482 static const WCHAR szMulti[] = {'[','~',']',0};
2491 *type=REG_EXPAND_SZ;
2499 if (strstrW(value, szMulti))
2500 *type = REG_MULTI_SZ;
2502 /* remove initial delimiter */
2503 if (!strncmpW(value, szMulti, 3))
2506 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2508 /* add double NULL terminator */
2509 if (*type == REG_MULTI_SZ)
2511 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2512 data = msi_realloc_zero(data, *size);
2518 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2525 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2527 *root_key = HKEY_LOCAL_MACHINE;
2532 *root_key = HKEY_CURRENT_USER;
2537 *root_key = HKEY_CLASSES_ROOT;
2541 *root_key = HKEY_CURRENT_USER;
2545 *root_key = HKEY_LOCAL_MACHINE;
2549 *root_key = HKEY_USERS;
2553 ERR("Unknown root %i\n", root);
2560 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2562 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2563 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2565 if ((is_64bit || is_wow64) &&
2566 !(comp->Attributes & msidbComponentAttributes64bit) &&
2567 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2572 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2573 if (!(path_32node = msi_alloc( size ))) return NULL;
2575 memcpy( path_32node, path, len * sizeof(WCHAR) );
2576 strcpyW( path_32node + len, szWow6432Node );
2577 strcatW( path_32node, szBackSlash );
2578 strcatW( path_32node, path + len );
2581 return strdupW( path );
2584 static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
2586 REGSAM access = KEY_ALL_ACCESS;
2587 WCHAR *subkey, *p, *q;
2588 HKEY hkey, ret = NULL;
2591 if (is_wow64) access |= KEY_WOW64_64KEY;
2593 if (!(subkey = strdupW( path ))) return NULL;
2595 if ((q = strchrW( p, '\\' ))) *q = 0;
2597 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2599 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2602 TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
2608 ret = open_key( hkey, q + 1, create );
2609 RegCloseKey( hkey );
2616 static BOOL is_special_entry( const WCHAR *name )
2618 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2621 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2623 MSIPACKAGE *package = param;
2625 HKEY root_key, hkey;
2627 LPWSTR deformated, uikey, keypath;
2628 LPCWSTR szRoot, component, name, key;
2632 BOOL check_first = FALSE;
2635 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2637 component = MSI_RecordGetString(row, 6);
2638 comp = msi_get_loaded_component(package,component);
2640 return ERROR_SUCCESS;
2642 comp->Action = msi_get_component_action( package, comp );
2643 if (comp->Action != INSTALLSTATE_LOCAL)
2645 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2646 return ERROR_SUCCESS;
2649 name = MSI_RecordGetString(row, 4);
2650 if( MSI_RecordIsNull(row,5) && name )
2652 /* null values can have special meanings */
2653 if (name[0]=='-' && name[1] == 0)
2654 return ERROR_SUCCESS;
2655 if ((name[0] == '+' || name[0] == '*') && !name[1])
2659 root = MSI_RecordGetInteger(row,2);
2660 key = MSI_RecordGetString(row, 3);
2662 szRoot = get_root_key( package, root, &root_key );
2664 return ERROR_SUCCESS;
2666 deformat_string(package, key , &deformated);
2667 size = strlenW(deformated) + strlenW(szRoot) + 1;
2668 uikey = msi_alloc(size*sizeof(WCHAR));
2669 strcpyW(uikey,szRoot);
2670 strcatW(uikey,deformated);
2672 keypath = get_keypath( comp, root_key, deformated );
2673 msi_free( deformated );
2674 if (!(hkey = open_key( root_key, keypath, TRUE )))
2676 ERR("Could not create key %s\n", debugstr_w(keypath));
2679 return ERROR_FUNCTION_FAILED;
2681 value = parse_value(package, MSI_RecordGetString(row, 5), &type, &size);
2682 deformat_string(package, name, &deformated);
2684 if (!is_special_entry( name ))
2688 TRACE("Setting value %s of %s\n", debugstr_w(deformated),
2690 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2695 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2696 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2698 TRACE("value %s of %s checked already exists\n", debugstr_w(deformated),
2703 TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated),
2705 if (deformated || size)
2706 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2712 uirow = MSI_CreateRecord(3);
2713 MSI_RecordSetStringW(uirow,2,deformated);
2714 MSI_RecordSetStringW(uirow,1,uikey);
2715 if (type == REG_SZ || type == REG_EXPAND_SZ)
2716 MSI_RecordSetStringW(uirow, 3, (LPWSTR)value);
2717 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2718 msiobj_release( &uirow->hdr );
2721 msi_free(deformated);
2725 return ERROR_SUCCESS;
2728 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2730 static const WCHAR query[] = {
2731 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2732 '`','R','e','g','i','s','t','r','y','`',0};
2736 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2737 if (rc != ERROR_SUCCESS)
2738 return ERROR_SUCCESS;
2740 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2741 msiobj_release(&view->hdr);
2745 static void delete_key( HKEY root, const WCHAR *path )
2752 if (is_wow64) access |= KEY_WOW64_64KEY;
2754 if (!(subkey = strdupW( path ))) return;
2757 if ((p = strrchrW( subkey, '\\' ))) *p = 0;
2758 hkey = open_key( root, subkey, FALSE );
2761 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2763 res = RegDeleteKeyExW( root, subkey, access, 0 );
2766 TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
2769 if (p && p[1]) RegCloseKey( hkey );
2775 static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
2779 DWORD num_subkeys, num_values;
2781 if ((hkey = open_key( root, path, FALSE )))
2783 if ((res = RegDeleteValueW( hkey, value )))
2784 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2786 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2787 NULL, NULL, NULL, NULL );
2788 RegCloseKey( hkey );
2789 if (!res && !num_subkeys && !num_values)
2791 TRACE("removing empty key %s\n", debugstr_w(path));
2792 delete_key( root, path );
2797 static void delete_tree( HKEY root, const WCHAR *path )
2802 if (!(hkey = open_key( root, path, FALSE ))) return;
2803 res = RegDeleteTreeW( hkey, NULL );
2804 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
2805 delete_key( root, path );
2806 RegCloseKey( hkey );
2809 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2811 MSIPACKAGE *package = param;
2812 LPCWSTR component, name, key_str, root_key_str;
2813 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2816 BOOL delete_key = FALSE;
2821 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2823 component = MSI_RecordGetString( row, 6 );
2824 comp = msi_get_loaded_component( package, component );
2826 return ERROR_SUCCESS;
2828 comp->Action = msi_get_component_action( package, comp );
2829 if (comp->Action != INSTALLSTATE_ABSENT)
2831 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2832 return ERROR_SUCCESS;
2835 name = MSI_RecordGetString( row, 4 );
2836 if (MSI_RecordIsNull( row, 5 ) && name )
2838 if (name[0] == '+' && !name[1])
2839 return ERROR_SUCCESS;
2840 if ((name[0] == '-' || name[0] == '*') && !name[1])
2847 root = MSI_RecordGetInteger( row, 2 );
2848 key_str = MSI_RecordGetString( row, 3 );
2850 root_key_str = get_root_key( package, root, &hkey_root );
2852 return ERROR_SUCCESS;
2854 deformat_string( package, key_str, &deformated_key );
2855 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2856 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2857 strcpyW( ui_key_str, root_key_str );
2858 strcatW( ui_key_str, deformated_key );
2860 deformat_string( package, name, &deformated_name );
2862 keypath = get_keypath( comp, hkey_root, deformated_key );
2863 msi_free( deformated_key );
2864 if (delete_key) delete_tree( hkey_root, keypath );
2865 else delete_value( hkey_root, keypath, deformated_name );
2866 msi_free( keypath );
2868 uirow = MSI_CreateRecord( 2 );
2869 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2870 MSI_RecordSetStringW( uirow, 2, deformated_name );
2871 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2872 msiobj_release( &uirow->hdr );
2874 msi_free( ui_key_str );
2875 msi_free( deformated_name );
2876 return ERROR_SUCCESS;
2879 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2881 MSIPACKAGE *package = param;
2882 LPCWSTR component, name, key_str, root_key_str;
2883 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2886 BOOL delete_key = FALSE;
2891 component = MSI_RecordGetString( row, 5 );
2892 comp = msi_get_loaded_component( package, component );
2894 return ERROR_SUCCESS;
2896 comp->Action = msi_get_component_action( package, comp );
2897 if (comp->Action != INSTALLSTATE_LOCAL)
2899 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2900 return ERROR_SUCCESS;
2903 if ((name = MSI_RecordGetString( row, 4 )))
2905 if (name[0] == '-' && !name[1])
2912 root = MSI_RecordGetInteger( row, 2 );
2913 key_str = MSI_RecordGetString( row, 3 );
2915 root_key_str = get_root_key( package, root, &hkey_root );
2917 return ERROR_SUCCESS;
2919 deformat_string( package, key_str, &deformated_key );
2920 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2921 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2922 strcpyW( ui_key_str, root_key_str );
2923 strcatW( ui_key_str, deformated_key );
2925 deformat_string( package, name, &deformated_name );
2927 keypath = get_keypath( comp, hkey_root, deformated_key );
2928 msi_free( deformated_key );
2929 if (delete_key) delete_tree( hkey_root, keypath );
2930 else delete_value( hkey_root, keypath, deformated_name );
2931 msi_free( keypath );
2933 uirow = MSI_CreateRecord( 2 );
2934 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2935 MSI_RecordSetStringW( uirow, 2, deformated_name );
2936 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2937 msiobj_release( &uirow->hdr );
2939 msi_free( ui_key_str );
2940 msi_free( deformated_name );
2941 return ERROR_SUCCESS;
2944 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2946 static const WCHAR registry_query[] = {
2947 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2948 '`','R','e','g','i','s','t','r','y','`',0};
2949 static const WCHAR remove_registry_query[] = {
2950 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2951 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2955 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2956 if (rc == ERROR_SUCCESS)
2958 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2959 msiobj_release( &view->hdr );
2960 if (rc != ERROR_SUCCESS)
2963 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2964 if (rc == ERROR_SUCCESS)
2966 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2967 msiobj_release( &view->hdr );
2968 if (rc != ERROR_SUCCESS)
2971 return ERROR_SUCCESS;
2974 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2976 package->script->CurrentlyScripting = TRUE;
2978 return ERROR_SUCCESS;
2982 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2984 static const WCHAR query[]= {
2985 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2986 '`','R','e','g','i','s','t','r','y','`',0};
2988 DWORD total = 0, count = 0;
2990 MSIFEATURE *feature;
2994 TRACE("InstallValidate\n");
2996 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2997 if (rc == ERROR_SUCCESS)
2999 rc = MSI_IterateRecords( view, &count, NULL, package );
3000 msiobj_release( &view->hdr );
3001 if (rc != ERROR_SUCCESS)
3003 total += count * REG_PROGRESS_VALUE;
3005 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3006 total += COMPONENT_PROGRESS_VALUE;
3008 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3009 total += file->FileSize;
3011 msi_ui_progress( package, 0, total, 0, 0 );
3013 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3015 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3016 debugstr_w(feature->Feature), feature->Installed,
3017 feature->ActionRequest, feature->Action);
3019 return ERROR_SUCCESS;
3022 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3024 MSIPACKAGE* package = param;
3025 LPCWSTR cond = NULL;
3026 LPCWSTR message = NULL;
3029 static const WCHAR title[]=
3030 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3032 cond = MSI_RecordGetString(row,1);
3034 r = MSI_EvaluateConditionW(package,cond);
3035 if (r == MSICONDITION_FALSE)
3037 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3040 message = MSI_RecordGetString(row,2);
3041 deformat_string(package,message,&deformated);
3042 MessageBoxW(NULL,deformated,title,MB_OK);
3043 msi_free(deformated);
3046 return ERROR_INSTALL_FAILURE;
3049 return ERROR_SUCCESS;
3052 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3054 static const WCHAR query[] = {
3055 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3056 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3060 TRACE("Checking launch conditions\n");
3062 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3063 if (rc != ERROR_SUCCESS)
3064 return ERROR_SUCCESS;
3066 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3067 msiobj_release(&view->hdr);
3071 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3075 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3077 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3079 static const WCHAR query[] = {
3080 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3081 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3082 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3083 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3084 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3087 LPWSTR deformated, buffer, deformated_name;
3090 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3094 root = MSI_RecordGetInteger(row,2);
3095 key = MSI_RecordGetString(row, 3);
3096 name = MSI_RecordGetString(row, 4);
3097 deformat_string(package, key , &deformated);
3098 deformat_string(package, name, &deformated_name);
3100 len = strlenW(deformated) + 6;
3101 if (deformated_name)
3102 len+=strlenW(deformated_name);
3104 buffer = msi_alloc( len *sizeof(WCHAR));
3106 if (deformated_name)
3107 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3109 sprintfW(buffer,fmt,root,deformated);
3111 msi_free(deformated);
3112 msi_free(deformated_name);
3113 msiobj_release(&row->hdr);
3117 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3119 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3124 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3127 return strdupW( file->TargetPath );
3132 static HKEY openSharedDLLsKey(void)
3135 static const WCHAR path[] =
3136 {'S','o','f','t','w','a','r','e','\\',
3137 'M','i','c','r','o','s','o','f','t','\\',
3138 'W','i','n','d','o','w','s','\\',
3139 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3140 'S','h','a','r','e','d','D','L','L','s',0};
3142 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3146 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3151 DWORD sz = sizeof(count);
3154 hkey = openSharedDLLsKey();
3155 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3156 if (rc != ERROR_SUCCESS)
3162 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3166 hkey = openSharedDLLsKey();
3168 msi_reg_set_val_dword( hkey, path, count );
3170 RegDeleteValueW(hkey,path);
3175 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3177 MSIFEATURE *feature;
3181 /* only refcount DLLs */
3182 if (comp->KeyPath == NULL ||
3184 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3185 comp->Attributes & msidbComponentAttributesODBCDataSource)
3189 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3190 write = (count > 0);
3192 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3196 /* increment counts */
3197 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3201 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3204 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3206 if ( cl->component == comp )
3211 /* decrement counts */
3212 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3216 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3219 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3221 if ( cl->component == comp )
3226 /* ref count all the files in the component */
3231 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3233 if (file->Component == comp)
3234 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3238 /* add a count for permanent */
3239 if (comp->Attributes & msidbComponentAttributesPermanent)
3242 comp->RefCount = count;
3245 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3248 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3252 const WCHAR prefixW[] = {'<','\\',0};
3253 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3254 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3258 strcpyW( keypath, prefixW );
3259 strcatW( keypath, comp->assembly->display_name );
3263 return resolve_keypath( package, comp );
3266 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3268 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3275 squash_guid(package->ProductCode,squished_pc);
3276 msi_set_sourcedir_props(package, FALSE);
3278 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3281 INSTALLSTATE action;
3283 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3284 if (!comp->ComponentId)
3287 squash_guid( comp->ComponentId, squished_cc );
3288 msi_free( comp->FullKeypath );
3289 comp->FullKeypath = build_full_keypath( package, comp );
3291 ACTION_RefCountComponent( package, comp );
3293 if (package->need_rollback) action = comp->Installed;
3294 else action = comp->ActionRequest;
3296 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3297 debugstr_w(comp->Component), debugstr_w(squished_cc),
3298 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3300 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3302 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3303 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3305 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3307 if (rc != ERROR_SUCCESS)
3310 if (comp->Attributes & msidbComponentAttributesPermanent)
3312 static const WCHAR szPermKey[] =
3313 { '0','0','0','0','0','0','0','0','0','0','0','0',
3314 '0','0','0','0','0','0','0','0','0','0','0','0',
3315 '0','0','0','0','0','0','0','0',0 };
3317 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3319 if (action == INSTALLSTATE_LOCAL)
3320 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3326 WCHAR source[MAX_PATH];
3327 WCHAR base[MAX_PATH];
3330 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3331 static const WCHAR query[] = {
3332 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3333 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3334 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3335 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3336 '`','D','i','s','k','I','d','`',0};
3338 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3341 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3342 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3343 ptr2 = strrchrW(source, '\\') + 1;
3344 msiobj_release(&row->hdr);
3346 lstrcpyW(base, package->PackagePath);
3347 ptr = strrchrW(base, '\\');
3350 sourcepath = msi_resolve_file_source(package, file);
3351 ptr = sourcepath + lstrlenW(base);
3352 lstrcpyW(ptr2, ptr);
3353 msi_free(sourcepath);
3355 msi_reg_set_val_str(hkey, squished_pc, source);
3359 else if (action == INSTALLSTATE_ABSENT)
3361 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3362 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3364 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3368 uirow = MSI_CreateRecord(3);
3369 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3370 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3371 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3372 msi_ui_actiondata( package, szProcessComponents, uirow );
3373 msiobj_release( &uirow->hdr );
3375 return ERROR_SUCCESS;
3386 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3387 LPWSTR lpszName, LONG_PTR lParam)
3390 typelib_struct *tl_struct = (typelib_struct*) lParam;
3391 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3395 if (!IS_INTRESOURCE(lpszName))
3397 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3401 sz = strlenW(tl_struct->source)+4;
3402 sz *= sizeof(WCHAR);
3404 if ((INT_PTR)lpszName == 1)
3405 tl_struct->path = strdupW(tl_struct->source);
3408 tl_struct->path = msi_alloc(sz);
3409 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3412 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3413 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3416 msi_free(tl_struct->path);
3417 tl_struct->path = NULL;
3422 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3423 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3425 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3429 msi_free(tl_struct->path);
3430 tl_struct->path = NULL;
3432 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3433 ITypeLib_Release(tl_struct->ptLib);
3438 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3440 MSIPACKAGE* package = param;
3444 typelib_struct tl_struct;
3449 component = MSI_RecordGetString(row,3);
3450 comp = msi_get_loaded_component(package,component);
3452 return ERROR_SUCCESS;
3454 comp->Action = msi_get_component_action( package, comp );
3455 if (comp->Action != INSTALLSTATE_LOCAL)
3457 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3458 return ERROR_SUCCESS;
3461 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3463 TRACE("component has no key path\n");
3464 return ERROR_SUCCESS;
3466 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3468 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3472 guid = MSI_RecordGetString(row,1);
3473 CLSIDFromString( guid, &tl_struct.clsid);
3474 tl_struct.source = strdupW( file->TargetPath );
3475 tl_struct.path = NULL;
3477 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3478 (LONG_PTR)&tl_struct);
3482 LPCWSTR helpid, help_path = NULL;
3485 helpid = MSI_RecordGetString(row,6);
3487 if (helpid) help_path = msi_get_target_folder( package, helpid );
3488 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3491 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3493 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3495 ITypeLib_Release(tl_struct.ptLib);
3496 msi_free(tl_struct.path);
3498 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3500 FreeLibrary(module);
3501 msi_free(tl_struct.source);
3505 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3508 ERR("Failed to load type library: %08x\n", hr);
3509 return ERROR_INSTALL_FAILURE;
3512 ITypeLib_Release(tlib);
3515 return ERROR_SUCCESS;
3518 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3520 static const WCHAR query[] = {
3521 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3522 '`','T','y','p','e','L','i','b','`',0};
3526 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3527 if (rc != ERROR_SUCCESS)
3528 return ERROR_SUCCESS;
3530 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3531 msiobj_release(&view->hdr);
3535 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3537 MSIPACKAGE *package = param;
3538 LPCWSTR component, guid;
3546 component = MSI_RecordGetString( row, 3 );
3547 comp = msi_get_loaded_component( package, component );
3549 return ERROR_SUCCESS;
3551 comp->Action = msi_get_component_action( package, comp );
3552 if (comp->Action != INSTALLSTATE_ABSENT)
3554 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3555 return ERROR_SUCCESS;
3557 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3559 guid = MSI_RecordGetString( row, 1 );
3560 CLSIDFromString( guid, &libid );
3561 version = MSI_RecordGetInteger( row, 4 );
3562 language = MSI_RecordGetInteger( row, 2 );
3565 syskind = SYS_WIN64;
3567 syskind = SYS_WIN32;
3570 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3573 WARN("Failed to unregister typelib: %08x\n", hr);
3576 return ERROR_SUCCESS;
3579 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3581 static const WCHAR query[] = {
3582 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3583 '`','T','y','p','e','L','i','b','`',0};
3587 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3588 if (rc != ERROR_SUCCESS)
3589 return ERROR_SUCCESS;
3591 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3592 msiobj_release( &view->hdr );
3596 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3598 static const WCHAR szlnk[] = {'.','l','n','k',0};
3599 LPCWSTR directory, extension, link_folder;
3600 LPWSTR link_file, filename;
3602 directory = MSI_RecordGetString( row, 2 );
3603 link_folder = msi_get_target_folder( package, directory );
3606 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3609 /* may be needed because of a bug somewhere else */
3610 msi_create_full_path( link_folder );
3612 filename = msi_dup_record_field( row, 3 );
3613 msi_reduce_to_long_filename( filename );
3615 extension = strchrW( filename, '.' );
3616 if (!extension || strcmpiW( extension, szlnk ))
3618 int len = strlenW( filename );
3619 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3620 memcpy( filename + len, szlnk, sizeof(szlnk) );
3622 link_file = msi_build_directory_name( 2, link_folder, filename );
3623 msi_free( filename );
3628 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3630 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3631 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3632 WCHAR *folder, *dest, *path;
3634 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3635 folder = msi_dup_property( package->db, szWindowsFolder );
3638 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3639 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3640 msi_free( appdata );
3642 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3643 msi_create_full_path( dest );
3644 path = msi_build_directory_name( 2, dest, icon_name );
3650 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3652 MSIPACKAGE *package = param;
3653 LPWSTR link_file, deformated, path;
3654 LPCWSTR component, target;
3656 IShellLinkW *sl = NULL;
3657 IPersistFile *pf = NULL;
3660 component = MSI_RecordGetString(row, 4);
3661 comp = msi_get_loaded_component(package, component);
3663 return ERROR_SUCCESS;
3665 comp->Action = msi_get_component_action( package, comp );
3666 if (comp->Action != INSTALLSTATE_LOCAL)
3668 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3669 return ERROR_SUCCESS;
3671 msi_ui_actiondata( package, szCreateShortcuts, row );
3673 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3674 &IID_IShellLinkW, (LPVOID *) &sl );
3678 ERR("CLSID_ShellLink not available\n");
3682 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3685 ERR("QueryInterface(IID_IPersistFile) failed\n");
3689 target = MSI_RecordGetString(row, 5);
3690 if (strchrW(target, '['))
3692 deformat_string( package, target, &path );
3693 TRACE("target path is %s\n", debugstr_w(path));
3694 IShellLinkW_SetPath( sl, path );
3699 FIXME("poorly handled shortcut format, advertised shortcut\n");
3700 IShellLinkW_SetPath(sl,comp->FullKeypath);
3703 if (!MSI_RecordIsNull(row,6))
3705 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3706 deformat_string(package, arguments, &deformated);
3707 IShellLinkW_SetArguments(sl,deformated);
3708 msi_free(deformated);
3711 if (!MSI_RecordIsNull(row,7))
3713 LPCWSTR description = MSI_RecordGetString(row, 7);
3714 IShellLinkW_SetDescription(sl, description);
3717 if (!MSI_RecordIsNull(row,8))
3718 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3720 if (!MSI_RecordIsNull(row,9))
3723 LPCWSTR icon = MSI_RecordGetString(row, 9);
3725 path = msi_build_icon_path(package, icon);
3726 index = MSI_RecordGetInteger(row,10);
3728 /* no value means 0 */
3729 if (index == MSI_NULL_INTEGER)
3732 IShellLinkW_SetIconLocation(sl, path, index);
3736 if (!MSI_RecordIsNull(row,11))
3737 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3739 if (!MSI_RecordIsNull(row,12))
3741 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3742 full_path = msi_get_target_folder( package, wkdir );
3743 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3745 link_file = get_link_file(package, row);
3747 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3748 IPersistFile_Save(pf, link_file, FALSE);
3749 msi_free(link_file);
3753 IPersistFile_Release( pf );
3755 IShellLinkW_Release( sl );
3757 return ERROR_SUCCESS;
3760 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3762 static const WCHAR query[] = {
3763 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3764 '`','S','h','o','r','t','c','u','t','`',0};
3769 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3770 if (rc != ERROR_SUCCESS)
3771 return ERROR_SUCCESS;
3773 res = CoInitialize( NULL );
3775 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3776 msiobj_release(&view->hdr);
3778 if (SUCCEEDED(res)) CoUninitialize();
3782 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3784 MSIPACKAGE *package = param;
3789 component = MSI_RecordGetString( row, 4 );
3790 comp = msi_get_loaded_component( package, component );
3792 return ERROR_SUCCESS;
3794 comp->Action = msi_get_component_action( package, comp );
3795 if (comp->Action != INSTALLSTATE_ABSENT)
3797 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3798 return ERROR_SUCCESS;
3800 msi_ui_actiondata( package, szRemoveShortcuts, row );
3802 link_file = get_link_file( package, row );
3804 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3805 if (!DeleteFileW( link_file ))
3807 WARN("Failed to remove shortcut file %u\n", GetLastError());
3809 msi_free( link_file );
3811 return ERROR_SUCCESS;
3814 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3816 static const WCHAR query[] = {
3817 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3818 '`','S','h','o','r','t','c','u','t','`',0};
3822 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3823 if (rc != ERROR_SUCCESS)
3824 return ERROR_SUCCESS;
3826 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3827 msiobj_release( &view->hdr );
3831 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3833 MSIPACKAGE* package = param;
3841 FileName = MSI_RecordGetString(row,1);
3844 ERR("Unable to get FileName\n");
3845 return ERROR_SUCCESS;
3848 FilePath = msi_build_icon_path(package, FileName);
3850 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3852 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3853 FILE_ATTRIBUTE_NORMAL, NULL);
3855 if (the_file == INVALID_HANDLE_VALUE)
3857 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3859 return ERROR_SUCCESS;
3866 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3867 if (rc != ERROR_SUCCESS)
3869 ERR("Failed to get stream\n");
3870 CloseHandle(the_file);
3871 DeleteFileW(FilePath);
3874 WriteFile(the_file,buffer,sz,&write,NULL);
3875 } while (sz == 1024);
3878 CloseHandle(the_file);
3880 return ERROR_SUCCESS;
3883 static UINT msi_publish_icons(MSIPACKAGE *package)
3885 static const WCHAR query[]= {
3886 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3887 '`','I','c','o','n','`',0};
3891 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3892 if (r == ERROR_SUCCESS)
3894 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3895 msiobj_release(&view->hdr);
3896 if (r != ERROR_SUCCESS)
3899 return ERROR_SUCCESS;
3902 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3908 MSISOURCELISTINFO *info;
3910 r = RegCreateKeyW(hkey, szSourceList, &source);
3911 if (r != ERROR_SUCCESS)
3914 RegCloseKey(source);
3916 buffer = strrchrW(package->PackagePath, '\\') + 1;
3917 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3918 package->Context, MSICODE_PRODUCT,
3919 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3920 if (r != ERROR_SUCCESS)
3923 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3924 package->Context, MSICODE_PRODUCT,
3925 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3926 if (r != ERROR_SUCCESS)
3929 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3930 package->Context, MSICODE_PRODUCT,
3931 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3932 if (r != ERROR_SUCCESS)
3935 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3937 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3938 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3939 info->options, info->value);
3941 MsiSourceListSetInfoW(package->ProductCode, NULL,
3942 info->context, info->options,
3943 info->property, info->value);
3946 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3948 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3949 disk->context, disk->options,
3950 disk->disk_id, disk->volume_label, disk->disk_prompt);
3953 return ERROR_SUCCESS;
3956 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3958 MSIHANDLE hdb, suminfo;
3959 WCHAR guids[MAX_PATH];
3960 WCHAR packcode[SQUISH_GUID_SIZE];
3967 static const WCHAR szARPProductIcon[] =
3968 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3969 static const WCHAR szAssignment[] =
3970 {'A','s','s','i','g','n','m','e','n','t',0};
3971 static const WCHAR szAdvertiseFlags[] =
3972 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3973 static const WCHAR szClients[] =
3974 {'C','l','i','e','n','t','s',0};
3975 static const WCHAR szColon[] = {':',0};
3977 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3978 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3981 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3982 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3985 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3987 buffer = msi_dup_property(package->db, szARPProductIcon);
3990 LPWSTR path = msi_build_icon_path(package, buffer);
3991 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3996 buffer = msi_dup_property(package->db, szProductVersion);
3999 DWORD verdword = msi_version_str_to_dword(buffer);
4000 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4004 msi_reg_set_val_dword(hkey, szAssignment, 0);
4005 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4006 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4007 msi_reg_set_val_str(hkey, szClients, szColon);
4009 hdb = alloc_msihandle(&package->db->hdr);
4011 return ERROR_NOT_ENOUGH_MEMORY;
4013 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4014 MsiCloseHandle(hdb);
4015 if (r != ERROR_SUCCESS)
4019 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4020 NULL, guids, &size);
4021 if (r != ERROR_SUCCESS)
4024 ptr = strchrW(guids, ';');
4026 squash_guid(guids, packcode);
4027 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4030 MsiCloseHandle(suminfo);
4031 return ERROR_SUCCESS;
4034 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4039 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4041 upgrade = msi_dup_property(package->db, szUpgradeCode);
4043 return ERROR_SUCCESS;
4045 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4046 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4048 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4050 if (r != ERROR_SUCCESS)
4052 WARN("failed to open upgrade code key\n");
4054 return ERROR_SUCCESS;
4056 squash_guid(package->ProductCode, squashed_pc);
4057 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4060 return ERROR_SUCCESS;
4063 static BOOL msi_check_publish(MSIPACKAGE *package)
4065 MSIFEATURE *feature;
4067 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4069 feature->Action = msi_get_feature_action( package, feature );
4070 if (feature->Action == INSTALLSTATE_LOCAL)
4077 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4079 MSIFEATURE *feature;
4081 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4083 feature->Action = msi_get_feature_action( package, feature );
4084 if (feature->Action != INSTALLSTATE_ABSENT)
4091 static UINT msi_publish_patches( MSIPACKAGE *package )
4093 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4094 WCHAR patch_squashed[GUID_SIZE];
4095 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4097 MSIPATCHINFO *patch;
4099 WCHAR *p, *all_patches = NULL;
4102 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4103 if (r != ERROR_SUCCESS)
4104 return ERROR_FUNCTION_FAILED;
4106 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4107 if (res != ERROR_SUCCESS)
4109 r = ERROR_FUNCTION_FAILED;
4113 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4114 if (r != ERROR_SUCCESS)
4117 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4119 squash_guid( patch->patchcode, patch_squashed );
4120 len += strlenW( patch_squashed ) + 1;
4123 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4127 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4131 squash_guid( patch->patchcode, p );
4132 p += strlenW( p ) + 1;
4134 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4135 (const BYTE *)patch->transforms,
4136 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4137 if (res != ERROR_SUCCESS)
4140 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4141 if (r != ERROR_SUCCESS)
4144 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4145 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4146 RegCloseKey( patch_key );
4147 if (res != ERROR_SUCCESS)
4150 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4152 res = GetLastError();
4153 ERR("Unable to copy patch package %d\n", res);
4156 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4157 if (res != ERROR_SUCCESS)
4160 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4161 RegCloseKey( patch_key );
4162 if (res != ERROR_SUCCESS)
4166 all_patches[len] = 0;
4167 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4168 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4169 if (res != ERROR_SUCCESS)
4172 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4173 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4174 if (res != ERROR_SUCCESS)
4175 r = ERROR_FUNCTION_FAILED;
4178 RegCloseKey( product_patches_key );
4179 RegCloseKey( patches_key );
4180 RegCloseKey( product_key );
4181 msi_free( all_patches );
4185 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4188 HKEY hukey = NULL, hudkey = NULL;
4191 if (!list_empty(&package->patches))
4193 rc = msi_publish_patches(package);
4194 if (rc != ERROR_SUCCESS)
4198 /* FIXME: also need to publish if the product is in advertise mode */
4199 if (!msi_check_publish(package))
4200 return ERROR_SUCCESS;
4202 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4204 if (rc != ERROR_SUCCESS)
4207 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4208 NULL, &hudkey, TRUE);
4209 if (rc != ERROR_SUCCESS)
4212 rc = msi_publish_upgrade_code(package);
4213 if (rc != ERROR_SUCCESS)
4216 rc = msi_publish_product_properties(package, hukey);
4217 if (rc != ERROR_SUCCESS)
4220 rc = msi_publish_sourcelist(package, hukey);
4221 if (rc != ERROR_SUCCESS)
4224 rc = msi_publish_icons(package);
4227 uirow = MSI_CreateRecord( 1 );
4228 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4229 msi_ui_actiondata( package, szPublishProduct, uirow );
4230 msiobj_release( &uirow->hdr );
4233 RegCloseKey(hudkey);
4237 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4239 WCHAR *filename, *ptr, *folder, *ret;
4240 const WCHAR *dirprop;
4242 filename = msi_dup_record_field( row, 2 );
4243 if (filename && (ptr = strchrW( filename, '|' )))
4248 dirprop = MSI_RecordGetString( row, 3 );
4251 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4252 if (!folder) folder = msi_dup_property( package->db, dirprop );
4255 folder = msi_dup_property( package->db, szWindowsFolder );
4259 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4260 msi_free( filename );
4264 ret = msi_build_directory_name( 2, folder, ptr );
4266 msi_free( filename );
4271 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4273 MSIPACKAGE *package = param;
4274 LPCWSTR component, section, key, value, identifier;
4275 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4280 component = MSI_RecordGetString(row, 8);
4281 comp = msi_get_loaded_component(package,component);
4283 return ERROR_SUCCESS;
4285 comp->Action = msi_get_component_action( package, comp );
4286 if (comp->Action != INSTALLSTATE_LOCAL)
4288 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4289 return ERROR_SUCCESS;
4292 identifier = MSI_RecordGetString(row,1);
4293 section = MSI_RecordGetString(row,4);
4294 key = MSI_RecordGetString(row,5);
4295 value = MSI_RecordGetString(row,6);
4296 action = MSI_RecordGetInteger(row,7);
4298 deformat_string(package,section,&deformated_section);
4299 deformat_string(package,key,&deformated_key);
4300 deformat_string(package,value,&deformated_value);
4302 fullname = get_ini_file_name(package, row);
4306 TRACE("Adding value %s to section %s in %s\n",
4307 debugstr_w(deformated_key), debugstr_w(deformated_section),
4308 debugstr_w(fullname));
4309 WritePrivateProfileStringW(deformated_section, deformated_key,
4310 deformated_value, fullname);
4312 else if (action == 1)
4315 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4316 returned, 10, fullname);
4317 if (returned[0] == 0)
4319 TRACE("Adding value %s to section %s in %s\n",
4320 debugstr_w(deformated_key), debugstr_w(deformated_section),
4321 debugstr_w(fullname));
4323 WritePrivateProfileStringW(deformated_section, deformated_key,
4324 deformated_value, fullname);
4327 else if (action == 3)
4328 FIXME("Append to existing section not yet implemented\n");
4330 uirow = MSI_CreateRecord(4);
4331 MSI_RecordSetStringW(uirow,1,identifier);
4332 MSI_RecordSetStringW(uirow,2,deformated_section);
4333 MSI_RecordSetStringW(uirow,3,deformated_key);
4334 MSI_RecordSetStringW(uirow,4,deformated_value);
4335 msi_ui_actiondata( package, szWriteIniValues, uirow );
4336 msiobj_release( &uirow->hdr );
4339 msi_free(deformated_key);
4340 msi_free(deformated_value);
4341 msi_free(deformated_section);
4342 return ERROR_SUCCESS;
4345 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4347 static const WCHAR query[] = {
4348 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4349 '`','I','n','i','F','i','l','e','`',0};
4353 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4354 if (rc != ERROR_SUCCESS)
4355 return ERROR_SUCCESS;
4357 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4358 msiobj_release(&view->hdr);
4362 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4364 MSIPACKAGE *package = param;
4365 LPCWSTR component, section, key, value, identifier;
4366 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4371 component = MSI_RecordGetString( row, 8 );
4372 comp = msi_get_loaded_component( package, component );
4374 return ERROR_SUCCESS;
4376 comp->Action = msi_get_component_action( package, comp );
4377 if (comp->Action != INSTALLSTATE_ABSENT)
4379 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4380 return ERROR_SUCCESS;
4383 identifier = MSI_RecordGetString( row, 1 );
4384 section = MSI_RecordGetString( row, 4 );
4385 key = MSI_RecordGetString( row, 5 );
4386 value = MSI_RecordGetString( row, 6 );
4387 action = MSI_RecordGetInteger( row, 7 );
4389 deformat_string( package, section, &deformated_section );
4390 deformat_string( package, key, &deformated_key );
4391 deformat_string( package, value, &deformated_value );
4393 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4395 filename = get_ini_file_name( package, row );
4397 TRACE("Removing key %s from section %s in %s\n",
4398 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4400 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4402 WARN("Unable to remove key %u\n", GetLastError());
4404 msi_free( filename );
4407 FIXME("Unsupported action %d\n", action);
4410 uirow = MSI_CreateRecord( 4 );
4411 MSI_RecordSetStringW( uirow, 1, identifier );
4412 MSI_RecordSetStringW( uirow, 2, deformated_section );
4413 MSI_RecordSetStringW( uirow, 3, deformated_key );
4414 MSI_RecordSetStringW( uirow, 4, deformated_value );
4415 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4416 msiobj_release( &uirow->hdr );
4418 msi_free( deformated_key );
4419 msi_free( deformated_value );
4420 msi_free( deformated_section );
4421 return ERROR_SUCCESS;
4424 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4426 MSIPACKAGE *package = param;
4427 LPCWSTR component, section, key, value, identifier;
4428 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4433 component = MSI_RecordGetString( row, 8 );
4434 comp = msi_get_loaded_component( package, component );
4436 return ERROR_SUCCESS;
4438 comp->Action = msi_get_component_action( package, comp );
4439 if (comp->Action != INSTALLSTATE_LOCAL)
4441 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4442 return ERROR_SUCCESS;
4445 identifier = MSI_RecordGetString( row, 1 );
4446 section = MSI_RecordGetString( row, 4 );
4447 key = MSI_RecordGetString( row, 5 );
4448 value = MSI_RecordGetString( row, 6 );
4449 action = MSI_RecordGetInteger( row, 7 );
4451 deformat_string( package, section, &deformated_section );
4452 deformat_string( package, key, &deformated_key );
4453 deformat_string( package, value, &deformated_value );
4455 if (action == msidbIniFileActionRemoveLine)
4457 filename = get_ini_file_name( package, row );
4459 TRACE("Removing key %s from section %s in %s\n",
4460 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4462 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4464 WARN("Unable to remove key %u\n", GetLastError());
4466 msi_free( filename );
4469 FIXME("Unsupported action %d\n", action);
4471 uirow = MSI_CreateRecord( 4 );
4472 MSI_RecordSetStringW( uirow, 1, identifier );
4473 MSI_RecordSetStringW( uirow, 2, deformated_section );
4474 MSI_RecordSetStringW( uirow, 3, deformated_key );
4475 MSI_RecordSetStringW( uirow, 4, deformated_value );
4476 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4477 msiobj_release( &uirow->hdr );
4479 msi_free( deformated_key );
4480 msi_free( deformated_value );
4481 msi_free( deformated_section );
4482 return ERROR_SUCCESS;
4485 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4487 static const WCHAR query[] = {
4488 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4489 '`','I','n','i','F','i','l','e','`',0};
4490 static const WCHAR remove_query[] = {
4491 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4492 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4496 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4497 if (rc == ERROR_SUCCESS)
4499 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4500 msiobj_release( &view->hdr );
4501 if (rc != ERROR_SUCCESS)
4504 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4505 if (rc == ERROR_SUCCESS)
4507 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4508 msiobj_release( &view->hdr );
4509 if (rc != ERROR_SUCCESS)
4512 return ERROR_SUCCESS;
4515 static void register_dll( const WCHAR *dll, BOOL unregister )
4519 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4522 HRESULT (WINAPI *func_ptr)( void );
4523 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4525 func_ptr = (void *)GetProcAddress( hmod, func );
4528 HRESULT hr = func_ptr();
4530 WARN("failed to register dll 0x%08x\n", hr);
4533 WARN("entry point %s not found\n", func);
4534 FreeLibrary( hmod );
4537 WARN("failed to load library %u\n", GetLastError());
4540 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4542 MSIPACKAGE *package = param;
4547 filename = MSI_RecordGetString( row, 1 );
4548 file = msi_get_loaded_file( package, filename );
4551 WARN("unable to find file %s\n", debugstr_w(filename));
4552 return ERROR_SUCCESS;
4554 file->Component->Action = msi_get_component_action( package, file->Component );
4555 if (file->Component->Action != INSTALLSTATE_LOCAL)
4557 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4558 return ERROR_SUCCESS;
4561 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4562 register_dll( file->TargetPath, FALSE );
4564 uirow = MSI_CreateRecord( 2 );
4565 MSI_RecordSetStringW( uirow, 1, file->File );
4566 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4567 msi_ui_actiondata( package, szSelfRegModules, uirow );
4568 msiobj_release( &uirow->hdr );
4570 return ERROR_SUCCESS;
4573 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4575 static const WCHAR query[] = {
4576 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4577 '`','S','e','l','f','R','e','g','`',0};
4581 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4582 if (rc != ERROR_SUCCESS)
4583 return ERROR_SUCCESS;
4585 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4586 msiobj_release(&view->hdr);
4590 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4592 MSIPACKAGE *package = param;
4597 filename = MSI_RecordGetString( row, 1 );
4598 file = msi_get_loaded_file( package, filename );
4601 WARN("unable to find file %s\n", debugstr_w(filename));
4602 return ERROR_SUCCESS;
4604 file->Component->Action = msi_get_component_action( package, file->Component );
4605 if (file->Component->Action != INSTALLSTATE_ABSENT)
4607 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4608 return ERROR_SUCCESS;
4611 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4612 register_dll( file->TargetPath, TRUE );
4614 uirow = MSI_CreateRecord( 2 );
4615 MSI_RecordSetStringW( uirow, 1, file->File );
4616 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4617 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4618 msiobj_release( &uirow->hdr );
4620 return ERROR_SUCCESS;
4623 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4625 static const WCHAR query[] = {
4626 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4627 '`','S','e','l','f','R','e','g','`',0};
4631 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4632 if (rc != ERROR_SUCCESS)
4633 return ERROR_SUCCESS;
4635 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4636 msiobj_release( &view->hdr );
4640 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4642 MSIFEATURE *feature;
4644 HKEY hkey = NULL, userdata = NULL;
4646 if (!msi_check_publish(package))
4647 return ERROR_SUCCESS;
4649 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4651 if (rc != ERROR_SUCCESS)
4654 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4656 if (rc != ERROR_SUCCESS)
4659 /* here the guids are base 85 encoded */
4660 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4666 BOOL absent = FALSE;
4669 if (feature->Action != INSTALLSTATE_LOCAL &&
4670 feature->Action != INSTALLSTATE_SOURCE &&
4671 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4674 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4678 if (feature->Feature_Parent)
4679 size += strlenW( feature->Feature_Parent )+2;
4681 data = msi_alloc(size * sizeof(WCHAR));
4684 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4686 MSICOMPONENT* component = cl->component;
4690 if (component->ComponentId)
4692 TRACE("From %s\n",debugstr_w(component->ComponentId));
4693 CLSIDFromString(component->ComponentId, &clsid);
4694 encode_base85_guid(&clsid,buf);
4695 TRACE("to %s\n",debugstr_w(buf));
4700 if (feature->Feature_Parent)
4702 static const WCHAR sep[] = {'\2',0};
4704 strcatW(data,feature->Feature_Parent);
4707 msi_reg_set_val_str( userdata, feature->Feature, data );
4711 if (feature->Feature_Parent)
4712 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4715 size += sizeof(WCHAR);
4716 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4717 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4721 size += 2*sizeof(WCHAR);
4722 data = msi_alloc(size);
4725 if (feature->Feature_Parent)
4726 strcpyW( &data[1], feature->Feature_Parent );
4727 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4733 uirow = MSI_CreateRecord( 1 );
4734 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4735 msi_ui_actiondata( package, szPublishFeatures, uirow );
4736 msiobj_release( &uirow->hdr );
4737 /* FIXME: call msi_ui_progress? */
4742 RegCloseKey(userdata);
4746 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4752 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4754 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4756 if (r == ERROR_SUCCESS)
4758 RegDeleteValueW(hkey, feature->Feature);
4762 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4764 if (r == ERROR_SUCCESS)
4766 RegDeleteValueW(hkey, feature->Feature);
4770 uirow = MSI_CreateRecord( 1 );
4771 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4772 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4773 msiobj_release( &uirow->hdr );
4775 return ERROR_SUCCESS;
4778 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4780 MSIFEATURE *feature;
4782 if (!msi_check_unpublish(package))
4783 return ERROR_SUCCESS;
4785 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4787 msi_unpublish_feature(package, feature);
4790 return ERROR_SUCCESS;
4793 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4797 WCHAR date[9], *val, *buffer;
4798 const WCHAR *prop, *key;
4800 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4801 static const WCHAR modpath_fmt[] =
4802 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4803 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4804 static const WCHAR szModifyPath[] =
4805 {'M','o','d','i','f','y','P','a','t','h',0};
4806 static const WCHAR szUninstallString[] =
4807 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4808 static const WCHAR szEstimatedSize[] =
4809 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4810 static const WCHAR szDisplayVersion[] =
4811 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4812 static const WCHAR szInstallSource[] =
4813 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4814 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4815 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4816 static const WCHAR szAuthorizedCDFPrefix[] =
4817 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4818 static const WCHAR szARPCONTACT[] =
4819 {'A','R','P','C','O','N','T','A','C','T',0};
4820 static const WCHAR szContact[] =
4821 {'C','o','n','t','a','c','t',0};
4822 static const WCHAR szARPCOMMENTS[] =
4823 {'A','R','P','C','O','M','M','E','N','T','S',0};
4824 static const WCHAR szComments[] =
4825 {'C','o','m','m','e','n','t','s',0};
4826 static const WCHAR szProductName[] =
4827 {'P','r','o','d','u','c','t','N','a','m','e',0};
4828 static const WCHAR szDisplayName[] =
4829 {'D','i','s','p','l','a','y','N','a','m','e',0};
4830 static const WCHAR szARPHELPLINK[] =
4831 {'A','R','P','H','E','L','P','L','I','N','K',0};
4832 static const WCHAR szHelpLink[] =
4833 {'H','e','l','p','L','i','n','k',0};
4834 static const WCHAR szARPHELPTELEPHONE[] =
4835 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4836 static const WCHAR szHelpTelephone[] =
4837 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4838 static const WCHAR szARPINSTALLLOCATION[] =
4839 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4840 static const WCHAR szInstallLocation[] =
4841 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4842 static const WCHAR szManufacturer[] =
4843 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4844 static const WCHAR szPublisher[] =
4845 {'P','u','b','l','i','s','h','e','r',0};
4846 static const WCHAR szARPREADME[] =
4847 {'A','R','P','R','E','A','D','M','E',0};
4848 static const WCHAR szReadme[] =
4849 {'R','e','a','d','M','e',0};
4850 static const WCHAR szARPSIZE[] =
4851 {'A','R','P','S','I','Z','E',0};
4852 static const WCHAR szSize[] =
4853 {'S','i','z','e',0};
4854 static const WCHAR szARPURLINFOABOUT[] =
4855 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4856 static const WCHAR szURLInfoAbout[] =
4857 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4858 static const WCHAR szARPURLUPDATEINFO[] =
4859 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4860 static const WCHAR szURLUpdateInfo[] =
4861 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4862 static const WCHAR szARPSYSTEMCOMPONENT[] =
4863 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4864 static const WCHAR szSystemComponent[] =
4865 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4867 static const WCHAR *propval[] = {
4868 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4869 szARPCONTACT, szContact,
4870 szARPCOMMENTS, szComments,
4871 szProductName, szDisplayName,
4872 szARPHELPLINK, szHelpLink,
4873 szARPHELPTELEPHONE, szHelpTelephone,
4874 szARPINSTALLLOCATION, szInstallLocation,
4875 szSourceDir, szInstallSource,
4876 szManufacturer, szPublisher,
4877 szARPREADME, szReadme,
4879 szARPURLINFOABOUT, szURLInfoAbout,
4880 szARPURLUPDATEINFO, szURLUpdateInfo,
4883 const WCHAR **p = propval;
4889 val = msi_dup_property(package->db, prop);
4890 msi_reg_set_val_str(hkey, key, val);
4894 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4895 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4897 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4899 size = deformat_string(package, modpath_fmt, &buffer);
4900 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4901 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4904 /* FIXME: Write real Estimated Size when we have it */
4905 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4907 GetLocalTime(&systime);
4908 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4909 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4911 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4912 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4914 buffer = msi_dup_property(package->db, szProductVersion);
4915 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4918 DWORD verdword = msi_version_str_to_dword(buffer);
4920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4921 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4922 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4926 return ERROR_SUCCESS;
4929 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4931 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4933 LPWSTR upgrade_code;
4934 HKEY hkey, props, upgrade_key;
4937 /* FIXME: also need to publish if the product is in advertise mode */
4938 if (!msi_check_publish(package))
4939 return ERROR_SUCCESS;
4941 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4942 if (rc != ERROR_SUCCESS)
4945 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4946 if (rc != ERROR_SUCCESS)
4949 rc = msi_publish_install_properties(package, hkey);
4950 if (rc != ERROR_SUCCESS)
4953 rc = msi_publish_install_properties(package, props);
4954 if (rc != ERROR_SUCCESS)
4957 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4960 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4961 if (rc == ERROR_SUCCESS)
4963 squash_guid( package->ProductCode, squashed_pc );
4964 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4965 RegCloseKey( upgrade_key );
4967 msi_free( upgrade_code );
4969 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4970 package->delete_on_close = FALSE;
4973 uirow = MSI_CreateRecord( 1 );
4974 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4975 msi_ui_actiondata( package, szRegisterProduct, uirow );
4976 msiobj_release( &uirow->hdr );
4979 return ERROR_SUCCESS;
4982 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4984 return execute_script(package, SCRIPT_INSTALL);
4987 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4989 MSIPACKAGE *package = param;
4990 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4991 WCHAR *p, *icon_path;
4993 if (!icon) return ERROR_SUCCESS;
4994 if ((icon_path = msi_build_icon_path( package, icon )))
4996 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4997 DeleteFileW( icon_path );
4998 if ((p = strrchrW( icon_path, '\\' )))
5001 RemoveDirectoryW( icon_path );
5003 msi_free( icon_path );
5005 return ERROR_SUCCESS;
5008 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5010 static const WCHAR query[]= {
5011 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
5015 r = MSI_DatabaseOpenViewW( package->db, query, &view );
5016 if (r == ERROR_SUCCESS)
5018 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5019 msiobj_release( &view->hdr );
5020 if (r != ERROR_SUCCESS)
5023 return ERROR_SUCCESS;
5026 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
5028 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
5029 WCHAR *upgrade, **features;
5030 BOOL full_uninstall = TRUE;
5031 MSIFEATURE *feature;
5032 MSIPATCHINFO *patch;
5035 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5037 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
5039 features = msi_split_string( remove, ',' );
5040 for (i = 0; features && features[i]; i++)
5042 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
5046 if (!full_uninstall)
5047 return ERROR_SUCCESS;
5049 MSIREG_DeleteProductKey(package->ProductCode);
5050 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5051 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5053 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5054 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5055 MSIREG_DeleteUserProductKey(package->ProductCode);
5056 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5058 upgrade = msi_dup_property(package->db, szUpgradeCode);
5061 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5062 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5066 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5068 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5069 if (!strcmpW( package->ProductCode, patch->products ))
5071 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5072 patch->delete_on_close = TRUE;
5074 /* FIXME: remove local patch package if this is the last product */
5076 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5077 package->delete_on_close = TRUE;
5079 msi_unpublish_icons( package );
5080 return ERROR_SUCCESS;
5083 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5088 /* turn off scheduling */
5089 package->script->CurrentlyScripting= FALSE;
5091 /* first do the same as an InstallExecute */
5092 rc = ACTION_InstallExecute(package);
5093 if (rc != ERROR_SUCCESS)
5096 /* then handle commit actions */
5097 rc = execute_script(package, SCRIPT_COMMIT);
5098 if (rc != ERROR_SUCCESS)
5101 remove = msi_dup_property(package->db, szRemove);
5102 rc = msi_unpublish_product(package, remove);
5107 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5109 static const WCHAR RunOnce[] = {
5110 'S','o','f','t','w','a','r','e','\\',
5111 'M','i','c','r','o','s','o','f','t','\\',
5112 'W','i','n','d','o','w','s','\\',
5113 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5114 'R','u','n','O','n','c','e',0};
5115 static const WCHAR InstallRunOnce[] = {
5116 'S','o','f','t','w','a','r','e','\\',
5117 'M','i','c','r','o','s','o','f','t','\\',
5118 'W','i','n','d','o','w','s','\\',
5119 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5120 'I','n','s','t','a','l','l','e','r','\\',
5121 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5123 static const WCHAR msiexec_fmt[] = {
5125 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5126 '\"','%','s','\"',0};
5127 static const WCHAR install_fmt[] = {
5128 '/','I',' ','\"','%','s','\"',' ',
5129 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5130 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5131 WCHAR buffer[256], sysdir[MAX_PATH];
5133 WCHAR squished_pc[100];
5135 squash_guid(package->ProductCode,squished_pc);
5137 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5138 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5139 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5142 msi_reg_set_val_str( hkey, squished_pc, buffer );
5145 TRACE("Reboot command %s\n",debugstr_w(buffer));
5147 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5148 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5150 msi_reg_set_val_str( hkey, squished_pc, buffer );
5153 return ERROR_INSTALL_SUSPEND;
5156 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5158 static const WCHAR query[] =
5159 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5160 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5161 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5162 MSIRECORD *rec, *row;
5168 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5170 rec = MSI_CreateRecord( count + 2 );
5171 str = MSI_RecordGetString( row, 1 );
5172 MSI_RecordSetStringW( rec, 0, str );
5173 msiobj_release( &row->hdr );
5174 MSI_RecordSetInteger( rec, 1, error );
5176 va_start( va, count );
5177 for (i = 0; i < count; i++)
5179 str = va_arg( va, const WCHAR *);
5180 MSI_RecordSetStringW( rec, i + 2, str );
5184 MSI_FormatRecordW( package, rec, NULL, &size );
5186 data = msi_alloc( size * sizeof(WCHAR) );
5187 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5189 msiobj_release( &rec->hdr );
5193 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5199 * We are currently doing what should be done here in the top level Install
5200 * however for Administrative and uninstalls this step will be needed
5202 if (!package->PackagePath)
5203 return ERROR_SUCCESS;
5205 msi_set_sourcedir_props(package, TRUE);
5207 attrib = GetFileAttributesW(package->db->path);
5208 if (attrib == INVALID_FILE_ATTRIBUTES)
5213 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5214 package->Context, MSICODE_PRODUCT,
5215 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5216 if (rc == ERROR_MORE_DATA)
5218 prompt = msi_alloc(size * sizeof(WCHAR));
5219 MsiSourceListGetInfoW(package->ProductCode, NULL,
5220 package->Context, MSICODE_PRODUCT,
5221 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5224 prompt = strdupW(package->db->path);
5226 msg = msi_build_error_string(package, 1302, 1, prompt);
5228 while(attrib == INVALID_FILE_ATTRIBUTES)
5230 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5234 return ERROR_INSTALL_USEREXIT;
5236 attrib = GetFileAttributesW(package->db->path);
5242 return ERROR_SUCCESS;
5247 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5250 LPWSTR buffer, productid = NULL;
5251 UINT i, rc = ERROR_SUCCESS;
5254 static const WCHAR szPropKeys[][80] =
5256 {'P','r','o','d','u','c','t','I','D',0},
5257 {'U','S','E','R','N','A','M','E',0},
5258 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5262 static const WCHAR szRegKeys[][80] =
5264 {'P','r','o','d','u','c','t','I','D',0},
5265 {'R','e','g','O','w','n','e','r',0},
5266 {'R','e','g','C','o','m','p','a','n','y',0},
5270 if (msi_check_unpublish(package))
5272 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5276 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5280 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5282 if (rc != ERROR_SUCCESS)
5285 for( i = 0; szPropKeys[i][0]; i++ )
5287 buffer = msi_dup_property( package->db, szPropKeys[i] );
5288 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5293 uirow = MSI_CreateRecord( 1 );
5294 MSI_RecordSetStringW( uirow, 1, productid );
5295 msi_ui_actiondata( package, szRegisterUser, uirow );
5296 msiobj_release( &uirow->hdr );
5298 msi_free(productid);
5304 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5308 package->script->InWhatSequence |= SEQUENCE_EXEC;
5309 rc = ACTION_ProcessExecSequence(package,FALSE);
5313 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5315 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5316 WCHAR productid_85[21], component_85[21], *ret;
5320 /* > is used if there is a component GUID and < if not. */
5322 productid_85[0] = 0;
5323 component_85[0] = 0;
5324 CLSIDFromString( package->ProductCode, &clsid );
5326 encode_base85_guid( &clsid, productid_85 );
5329 CLSIDFromString( component->ComponentId, &clsid );
5330 encode_base85_guid( &clsid, component_85 );
5333 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5334 debugstr_w(component_85));
5336 sz = 20 + strlenW( feature ) + 20 + 3;
5337 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5338 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5342 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5344 MSIPACKAGE *package = param;
5345 LPCWSTR compgroupid, component, feature, qualifier, text;
5346 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5355 feature = MSI_RecordGetString(rec, 5);
5356 feat = msi_get_loaded_feature(package, feature);
5358 return ERROR_SUCCESS;
5360 feat->Action = msi_get_feature_action( package, feat );
5361 if (feat->Action != INSTALLSTATE_LOCAL &&
5362 feat->Action != INSTALLSTATE_SOURCE &&
5363 feat->Action != INSTALLSTATE_ADVERTISED)
5365 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5366 return ERROR_SUCCESS;
5369 component = MSI_RecordGetString(rec, 3);
5370 comp = msi_get_loaded_component(package, component);
5372 return ERROR_SUCCESS;
5374 compgroupid = MSI_RecordGetString(rec,1);
5375 qualifier = MSI_RecordGetString(rec,2);
5377 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5378 if (rc != ERROR_SUCCESS)
5381 advertise = msi_create_component_advertise_string( package, comp, feature );
5382 text = MSI_RecordGetString( rec, 4 );
5385 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5386 strcpyW( p, advertise );
5388 msi_free( advertise );
5391 existing = msi_reg_get_val_str( hkey, qualifier );
5393 sz = strlenW( advertise ) + 1;
5396 for (p = existing; *p; p += len)
5398 len = strlenW( p ) + 1;
5399 if (strcmpW( advertise, p )) sz += len;
5402 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5404 rc = ERROR_OUTOFMEMORY;
5410 for (p = existing; *p; p += len)
5412 len = strlenW( p ) + 1;
5413 if (strcmpW( advertise, p ))
5415 memcpy( q, p, len * sizeof(WCHAR) );
5420 strcpyW( q, advertise );
5421 q[strlenW( q ) + 1] = 0;
5423 msi_reg_set_val_multi_str( hkey, qualifier, output );
5428 msi_free( advertise );
5429 msi_free( existing );
5432 uirow = MSI_CreateRecord( 2 );
5433 MSI_RecordSetStringW( uirow, 1, compgroupid );
5434 MSI_RecordSetStringW( uirow, 2, qualifier);
5435 msi_ui_actiondata( package, szPublishComponents, uirow );
5436 msiobj_release( &uirow->hdr );
5437 /* FIXME: call ui_progress? */
5443 * At present I am ignorning the advertised components part of this and only
5444 * focusing on the qualified component sets
5446 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5448 static const WCHAR query[] = {
5449 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5450 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5454 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5455 if (rc != ERROR_SUCCESS)
5456 return ERROR_SUCCESS;
5458 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5459 msiobj_release(&view->hdr);
5463 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5465 static const WCHAR szInstallerComponents[] = {
5466 'S','o','f','t','w','a','r','e','\\',
5467 'M','i','c','r','o','s','o','f','t','\\',
5468 'I','n','s','t','a','l','l','e','r','\\',
5469 'C','o','m','p','o','n','e','n','t','s','\\',0};
5471 MSIPACKAGE *package = param;
5472 LPCWSTR compgroupid, component, feature, qualifier;
5476 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5479 feature = MSI_RecordGetString( rec, 5 );
5480 feat = msi_get_loaded_feature( package, feature );
5482 return ERROR_SUCCESS;
5484 feat->Action = msi_get_feature_action( package, feat );
5485 if (feat->Action != INSTALLSTATE_ABSENT)
5487 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5488 return ERROR_SUCCESS;
5491 component = MSI_RecordGetString( rec, 3 );
5492 comp = msi_get_loaded_component( package, component );
5494 return ERROR_SUCCESS;
5496 compgroupid = MSI_RecordGetString( rec, 1 );
5497 qualifier = MSI_RecordGetString( rec, 2 );
5499 squash_guid( compgroupid, squashed );
5500 strcpyW( keypath, szInstallerComponents );
5501 strcatW( keypath, squashed );
5503 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5504 if (res != ERROR_SUCCESS)
5506 WARN("Unable to delete component key %d\n", res);
5509 uirow = MSI_CreateRecord( 2 );
5510 MSI_RecordSetStringW( uirow, 1, compgroupid );
5511 MSI_RecordSetStringW( uirow, 2, qualifier );
5512 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5513 msiobj_release( &uirow->hdr );
5515 return ERROR_SUCCESS;
5518 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5520 static const WCHAR query[] = {
5521 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5522 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5526 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5527 if (rc != ERROR_SUCCESS)
5528 return ERROR_SUCCESS;
5530 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5531 msiobj_release( &view->hdr );
5535 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5537 static const WCHAR query[] =
5538 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5539 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5540 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5541 MSIPACKAGE *package = param;
5542 MSICOMPONENT *component;
5545 SC_HANDLE hscm = NULL, service = NULL;
5547 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5548 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5549 DWORD serv_type, start_type, err_control;
5550 SERVICE_DESCRIPTIONW sd = {NULL};
5552 comp = MSI_RecordGetString( rec, 12 );
5553 component = msi_get_loaded_component( package, comp );
5556 WARN("service component not found\n");
5559 component->Action = msi_get_component_action( package, component );
5560 if (component->Action != INSTALLSTATE_LOCAL)
5562 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5565 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5568 ERR("Failed to open the SC Manager!\n");
5572 start_type = MSI_RecordGetInteger(rec, 5);
5573 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5576 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5577 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5578 serv_type = MSI_RecordGetInteger(rec, 4);
5579 err_control = MSI_RecordGetInteger(rec, 6);
5580 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5581 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5582 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5583 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5584 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5585 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5587 /* fetch the service path */
5588 row = MSI_QueryGetRecord(package->db, query, comp);
5591 ERR("Query failed\n");
5594 key = MSI_RecordGetString(row, 6);
5595 file = msi_get_loaded_file(package, key);
5596 msiobj_release(&row->hdr);
5599 ERR("Failed to load the service file\n");
5603 if (!args || !args[0]) image_path = file->TargetPath;
5606 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5607 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5608 return ERROR_OUTOFMEMORY;
5610 strcpyW(image_path, file->TargetPath);
5611 strcatW(image_path, szSpace);
5612 strcatW(image_path, args);
5614 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5615 start_type, err_control, image_path, load_order,
5616 NULL, depends, serv_name, pass);
5620 if (GetLastError() != ERROR_SERVICE_EXISTS)
5621 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5623 else if (sd.lpDescription)
5625 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5626 WARN("failed to set service description %u\n", GetLastError());
5629 if (image_path != file->TargetPath) msi_free(image_path);
5631 CloseServiceHandle(service);
5632 CloseServiceHandle(hscm);
5635 msi_free(sd.lpDescription);
5636 msi_free(load_order);
5637 msi_free(serv_name);
5642 return ERROR_SUCCESS;
5645 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5647 static const WCHAR query[] = {
5648 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5649 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5653 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5654 if (rc != ERROR_SUCCESS)
5655 return ERROR_SUCCESS;
5657 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5658 msiobj_release(&view->hdr);
5662 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5663 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5665 LPCWSTR *vector, *temp_vector;
5669 static const WCHAR separator[] = {'[','~',']',0};
5672 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5677 vector = msi_alloc(sizeof(LPWSTR));
5685 vector[*numargs - 1] = p;
5687 if ((q = strstrW(p, separator)))
5691 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5697 vector = temp_vector;
5706 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5708 MSIPACKAGE *package = param;
5711 SC_HANDLE scm = NULL, service = NULL;
5712 LPCWSTR component, *vector = NULL;
5713 LPWSTR name, args, display_name = NULL;
5714 DWORD event, numargs, len, wait, dummy;
5715 UINT r = ERROR_FUNCTION_FAILED;
5716 SERVICE_STATUS_PROCESS status;
5717 ULONGLONG start_time;
5719 component = MSI_RecordGetString(rec, 6);
5720 comp = msi_get_loaded_component(package, component);
5722 return ERROR_SUCCESS;
5724 comp->Action = msi_get_component_action( package, comp );
5725 if (comp->Action != INSTALLSTATE_LOCAL)
5727 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5728 return ERROR_SUCCESS;
5731 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5732 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5733 event = MSI_RecordGetInteger(rec, 3);
5734 wait = MSI_RecordGetInteger(rec, 5);
5736 if (!(event & msidbServiceControlEventStart))
5742 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5745 ERR("Failed to open the service control manager\n");
5750 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5751 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5753 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5754 GetServiceDisplayNameW( scm, name, display_name, &len );
5757 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5760 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5764 vector = msi_service_args_to_vector(args, &numargs);
5766 if (!StartServiceW(service, numargs, vector) &&
5767 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5769 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5776 /* wait for at most 30 seconds for the service to be up and running */
5777 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5778 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5780 TRACE("failed to query service status (%u)\n", GetLastError());
5783 start_time = GetTickCount64();
5784 while (status.dwCurrentState == SERVICE_START_PENDING)
5786 if (GetTickCount64() - start_time > 30000) break;
5788 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5789 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5791 TRACE("failed to query service status (%u)\n", GetLastError());
5795 if (status.dwCurrentState != SERVICE_RUNNING)
5797 WARN("service failed to start %u\n", status.dwCurrentState);
5798 r = ERROR_FUNCTION_FAILED;
5803 uirow = MSI_CreateRecord( 2 );
5804 MSI_RecordSetStringW( uirow, 1, display_name );
5805 MSI_RecordSetStringW( uirow, 2, name );
5806 msi_ui_actiondata( package, szStartServices, uirow );
5807 msiobj_release( &uirow->hdr );
5809 CloseServiceHandle(service);
5810 CloseServiceHandle(scm);
5815 msi_free(display_name);
5819 static UINT ACTION_StartServices( MSIPACKAGE *package )
5821 static const WCHAR query[] = {
5822 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5823 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5827 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5828 if (rc != ERROR_SUCCESS)
5829 return ERROR_SUCCESS;
5831 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5832 msiobj_release(&view->hdr);
5836 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5838 DWORD i, needed, count;
5839 ENUM_SERVICE_STATUSW *dependencies;
5843 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5844 0, &needed, &count))
5847 if (GetLastError() != ERROR_MORE_DATA)
5850 dependencies = msi_alloc(needed);
5854 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5855 needed, &needed, &count))
5858 for (i = 0; i < count; i++)
5860 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5861 SERVICE_STOP | SERVICE_QUERY_STATUS);
5865 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5872 msi_free(dependencies);
5876 static UINT stop_service( LPCWSTR name )
5878 SC_HANDLE scm = NULL, service = NULL;
5879 SERVICE_STATUS status;
5880 SERVICE_STATUS_PROCESS ssp;
5883 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5886 WARN("Failed to open the SCM: %d\n", GetLastError());
5890 service = OpenServiceW(scm, name,
5892 SERVICE_QUERY_STATUS |
5893 SERVICE_ENUMERATE_DEPENDENTS);
5896 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5900 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5901 sizeof(SERVICE_STATUS_PROCESS), &needed))
5903 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5907 if (ssp.dwCurrentState == SERVICE_STOPPED)
5910 stop_service_dependents(scm, service);
5912 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5913 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5916 CloseServiceHandle(service);
5917 CloseServiceHandle(scm);
5919 return ERROR_SUCCESS;
5922 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5924 MSIPACKAGE *package = param;
5928 LPWSTR name = NULL, display_name = NULL;
5932 event = MSI_RecordGetInteger( rec, 3 );
5933 if (!(event & msidbServiceControlEventStop))
5934 return ERROR_SUCCESS;
5936 component = MSI_RecordGetString( rec, 6 );
5937 comp = msi_get_loaded_component( package, component );
5939 return ERROR_SUCCESS;
5941 comp->Action = msi_get_component_action( package, comp );
5942 if (comp->Action != INSTALLSTATE_ABSENT)
5944 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5945 return ERROR_SUCCESS;
5948 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5951 ERR("Failed to open the service control manager\n");
5956 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5957 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5959 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5960 GetServiceDisplayNameW( scm, name, display_name, &len );
5962 CloseServiceHandle( scm );
5964 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5965 stop_service( name );
5968 uirow = MSI_CreateRecord( 2 );
5969 MSI_RecordSetStringW( uirow, 1, display_name );
5970 MSI_RecordSetStringW( uirow, 2, name );
5971 msi_ui_actiondata( package, szStopServices, uirow );
5972 msiobj_release( &uirow->hdr );
5975 msi_free( display_name );
5976 return ERROR_SUCCESS;
5979 static UINT ACTION_StopServices( MSIPACKAGE *package )
5981 static const WCHAR query[] = {
5982 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5983 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5987 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5988 if (rc != ERROR_SUCCESS)
5989 return ERROR_SUCCESS;
5991 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5992 msiobj_release(&view->hdr);
5996 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5998 MSIPACKAGE *package = param;
6001 LPWSTR name = NULL, display_name = NULL;
6003 SC_HANDLE scm = NULL, service = NULL;
6005 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6007 return ERROR_SUCCESS;
6009 event = MSI_RecordGetInteger( rec, 3 );
6010 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6012 comp->Action = msi_get_component_action( package, comp );
6013 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6014 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6016 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6018 return ERROR_SUCCESS;
6020 stop_service( name );
6022 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6025 WARN("Failed to open the SCM: %d\n", GetLastError());
6030 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6031 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6033 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6034 GetServiceDisplayNameW( scm, name, display_name, &len );
6037 service = OpenServiceW( scm, name, DELETE );
6040 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6044 if (!DeleteService( service ))
6045 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6048 uirow = MSI_CreateRecord( 2 );
6049 MSI_RecordSetStringW( uirow, 1, display_name );
6050 MSI_RecordSetStringW( uirow, 2, name );
6051 msi_ui_actiondata( package, szDeleteServices, uirow );
6052 msiobj_release( &uirow->hdr );
6054 CloseServiceHandle( service );
6055 CloseServiceHandle( scm );
6057 msi_free( display_name );
6059 return ERROR_SUCCESS;
6062 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6064 static const WCHAR query[] = {
6065 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6066 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6070 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6071 if (rc != ERROR_SUCCESS)
6072 return ERROR_SUCCESS;
6074 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6075 msiobj_release( &view->hdr );
6079 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6081 MSIPACKAGE *package = param;
6082 LPWSTR driver, driver_path, ptr;
6083 WCHAR outpath[MAX_PATH];
6084 MSIFILE *driver_file = NULL, *setup_file = NULL;
6087 LPCWSTR desc, file_key, component;
6089 UINT r = ERROR_SUCCESS;
6091 static const WCHAR driver_fmt[] = {
6092 'D','r','i','v','e','r','=','%','s',0};
6093 static const WCHAR setup_fmt[] = {
6094 'S','e','t','u','p','=','%','s',0};
6095 static const WCHAR usage_fmt[] = {
6096 'F','i','l','e','U','s','a','g','e','=','1',0};
6098 component = MSI_RecordGetString( rec, 2 );
6099 comp = msi_get_loaded_component( package, component );
6101 return ERROR_SUCCESS;
6103 comp->Action = msi_get_component_action( package, comp );
6104 if (comp->Action != INSTALLSTATE_LOCAL)
6106 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6107 return ERROR_SUCCESS;
6109 desc = MSI_RecordGetString(rec, 3);
6111 file_key = MSI_RecordGetString( rec, 4 );
6112 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6114 file_key = MSI_RecordGetString( rec, 5 );
6115 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6119 ERR("ODBC Driver entry not found!\n");
6120 return ERROR_FUNCTION_FAILED;
6123 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6125 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6126 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6128 driver = msi_alloc(len * sizeof(WCHAR));
6130 return ERROR_OUTOFMEMORY;
6133 lstrcpyW(ptr, desc);
6134 ptr += lstrlenW(ptr) + 1;
6136 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6141 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6145 lstrcpyW(ptr, usage_fmt);
6146 ptr += lstrlenW(ptr) + 1;
6149 if (!driver_file->TargetPath)
6151 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6152 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6154 driver_path = strdupW(driver_file->TargetPath);
6155 ptr = strrchrW(driver_path, '\\');
6156 if (ptr) *ptr = '\0';
6158 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6159 NULL, ODBC_INSTALL_COMPLETE, &usage))
6161 ERR("Failed to install SQL driver!\n");
6162 r = ERROR_FUNCTION_FAILED;
6165 uirow = MSI_CreateRecord( 5 );
6166 MSI_RecordSetStringW( uirow, 1, desc );
6167 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6168 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6169 msi_ui_actiondata( package, szInstallODBC, uirow );
6170 msiobj_release( &uirow->hdr );
6173 msi_free(driver_path);
6178 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6180 MSIPACKAGE *package = param;
6181 LPWSTR translator, translator_path, ptr;
6182 WCHAR outpath[MAX_PATH];
6183 MSIFILE *translator_file = NULL, *setup_file = NULL;
6186 LPCWSTR desc, file_key, component;
6188 UINT r = ERROR_SUCCESS;
6190 static const WCHAR translator_fmt[] = {
6191 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6192 static const WCHAR setup_fmt[] = {
6193 'S','e','t','u','p','=','%','s',0};
6195 component = MSI_RecordGetString( rec, 2 );
6196 comp = msi_get_loaded_component( package, component );
6198 return ERROR_SUCCESS;
6200 comp->Action = msi_get_component_action( package, comp );
6201 if (comp->Action != INSTALLSTATE_LOCAL)
6203 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6204 return ERROR_SUCCESS;
6206 desc = MSI_RecordGetString(rec, 3);
6208 file_key = MSI_RecordGetString( rec, 4 );
6209 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6211 file_key = MSI_RecordGetString( rec, 5 );
6212 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6214 if (!translator_file)
6216 ERR("ODBC Translator entry not found!\n");
6217 return ERROR_FUNCTION_FAILED;
6220 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6222 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6224 translator = msi_alloc(len * sizeof(WCHAR));
6226 return ERROR_OUTOFMEMORY;
6229 lstrcpyW(ptr, desc);
6230 ptr += lstrlenW(ptr) + 1;
6232 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6237 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6242 translator_path = strdupW(translator_file->TargetPath);
6243 ptr = strrchrW(translator_path, '\\');
6244 if (ptr) *ptr = '\0';
6246 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6247 NULL, ODBC_INSTALL_COMPLETE, &usage))
6249 ERR("Failed to install SQL translator!\n");
6250 r = ERROR_FUNCTION_FAILED;
6253 uirow = MSI_CreateRecord( 5 );
6254 MSI_RecordSetStringW( uirow, 1, desc );
6255 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6256 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6257 msi_ui_actiondata( package, szInstallODBC, uirow );
6258 msiobj_release( &uirow->hdr );
6260 msi_free(translator);
6261 msi_free(translator_path);
6266 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6268 MSIPACKAGE *package = param;
6271 LPCWSTR desc, driver, component;
6272 WORD request = ODBC_ADD_SYS_DSN;
6275 UINT r = ERROR_SUCCESS;
6278 static const WCHAR attrs_fmt[] = {
6279 'D','S','N','=','%','s',0 };
6281 component = MSI_RecordGetString( rec, 2 );
6282 comp = msi_get_loaded_component( package, component );
6284 return ERROR_SUCCESS;
6286 comp->Action = msi_get_component_action( package, comp );
6287 if (comp->Action != INSTALLSTATE_LOCAL)
6289 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6290 return ERROR_SUCCESS;
6293 desc = MSI_RecordGetString(rec, 3);
6294 driver = MSI_RecordGetString(rec, 4);
6295 registration = MSI_RecordGetInteger(rec, 5);
6297 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6298 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6300 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6301 attrs = msi_alloc(len * sizeof(WCHAR));
6303 return ERROR_OUTOFMEMORY;
6305 len = sprintfW(attrs, attrs_fmt, desc);
6308 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6310 ERR("Failed to install SQL data source!\n");
6311 r = ERROR_FUNCTION_FAILED;
6314 uirow = MSI_CreateRecord( 5 );
6315 MSI_RecordSetStringW( uirow, 1, desc );
6316 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6317 MSI_RecordSetInteger( uirow, 3, request );
6318 msi_ui_actiondata( package, szInstallODBC, uirow );
6319 msiobj_release( &uirow->hdr );
6326 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6328 static const WCHAR driver_query[] = {
6329 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6330 'O','D','B','C','D','r','i','v','e','r',0};
6331 static const WCHAR translator_query[] = {
6332 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6333 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6334 static const WCHAR source_query[] = {
6335 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6336 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6340 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6341 if (rc == ERROR_SUCCESS)
6343 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6344 msiobj_release(&view->hdr);
6345 if (rc != ERROR_SUCCESS)
6348 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6349 if (rc == ERROR_SUCCESS)
6351 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6352 msiobj_release(&view->hdr);
6353 if (rc != ERROR_SUCCESS)
6356 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6357 if (rc == ERROR_SUCCESS)
6359 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6360 msiobj_release(&view->hdr);
6361 if (rc != ERROR_SUCCESS)
6364 return ERROR_SUCCESS;
6367 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6369 MSIPACKAGE *package = param;
6373 LPCWSTR desc, component;
6375 component = MSI_RecordGetString( rec, 2 );
6376 comp = msi_get_loaded_component( package, component );
6378 return ERROR_SUCCESS;
6380 comp->Action = msi_get_component_action( package, comp );
6381 if (comp->Action != INSTALLSTATE_ABSENT)
6383 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6384 return ERROR_SUCCESS;
6387 desc = MSI_RecordGetString( rec, 3 );
6388 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6390 WARN("Failed to remove ODBC driver\n");
6394 FIXME("Usage count reached 0\n");
6397 uirow = MSI_CreateRecord( 2 );
6398 MSI_RecordSetStringW( uirow, 1, desc );
6399 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6400 msi_ui_actiondata( package, szRemoveODBC, uirow );
6401 msiobj_release( &uirow->hdr );
6403 return ERROR_SUCCESS;
6406 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6408 MSIPACKAGE *package = param;
6412 LPCWSTR desc, component;
6414 component = MSI_RecordGetString( rec, 2 );
6415 comp = msi_get_loaded_component( package, component );
6417 return ERROR_SUCCESS;
6419 comp->Action = msi_get_component_action( package, comp );
6420 if (comp->Action != INSTALLSTATE_ABSENT)
6422 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6423 return ERROR_SUCCESS;
6426 desc = MSI_RecordGetString( rec, 3 );
6427 if (!SQLRemoveTranslatorW( desc, &usage ))
6429 WARN("Failed to remove ODBC translator\n");
6433 FIXME("Usage count reached 0\n");
6436 uirow = MSI_CreateRecord( 2 );
6437 MSI_RecordSetStringW( uirow, 1, desc );
6438 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6439 msi_ui_actiondata( package, szRemoveODBC, uirow );
6440 msiobj_release( &uirow->hdr );
6442 return ERROR_SUCCESS;
6445 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6447 MSIPACKAGE *package = param;
6451 LPCWSTR desc, driver, component;
6452 WORD request = ODBC_REMOVE_SYS_DSN;
6456 static const WCHAR attrs_fmt[] = {
6457 'D','S','N','=','%','s',0 };
6459 component = MSI_RecordGetString( rec, 2 );
6460 comp = msi_get_loaded_component( package, component );
6462 return ERROR_SUCCESS;
6464 comp->Action = msi_get_component_action( package, comp );
6465 if (comp->Action != INSTALLSTATE_ABSENT)
6467 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6468 return ERROR_SUCCESS;
6471 desc = MSI_RecordGetString( rec, 3 );
6472 driver = MSI_RecordGetString( rec, 4 );
6473 registration = MSI_RecordGetInteger( rec, 5 );
6475 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6476 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6478 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6479 attrs = msi_alloc( len * sizeof(WCHAR) );
6481 return ERROR_OUTOFMEMORY;
6483 FIXME("Use ODBCSourceAttribute table\n");
6485 len = sprintfW( attrs, attrs_fmt, desc );
6488 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6490 WARN("Failed to remove ODBC data source\n");
6494 uirow = MSI_CreateRecord( 3 );
6495 MSI_RecordSetStringW( uirow, 1, desc );
6496 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6497 MSI_RecordSetInteger( uirow, 3, request );
6498 msi_ui_actiondata( package, szRemoveODBC, uirow );
6499 msiobj_release( &uirow->hdr );
6501 return ERROR_SUCCESS;
6504 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6506 static const WCHAR driver_query[] = {
6507 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6508 'O','D','B','C','D','r','i','v','e','r',0};
6509 static const WCHAR translator_query[] = {
6510 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6511 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6512 static const WCHAR source_query[] = {
6513 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6514 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6518 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6519 if (rc == ERROR_SUCCESS)
6521 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6522 msiobj_release( &view->hdr );
6523 if (rc != ERROR_SUCCESS)
6526 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6527 if (rc == ERROR_SUCCESS)
6529 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6530 msiobj_release( &view->hdr );
6531 if (rc != ERROR_SUCCESS)
6534 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6535 if (rc == ERROR_SUCCESS)
6537 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6538 msiobj_release( &view->hdr );
6539 if (rc != ERROR_SUCCESS)
6542 return ERROR_SUCCESS;
6545 #define ENV_ACT_SETALWAYS 0x1
6546 #define ENV_ACT_SETABSENT 0x2
6547 #define ENV_ACT_REMOVE 0x4
6548 #define ENV_ACT_REMOVEMATCH 0x8
6550 #define ENV_MOD_MACHINE 0x20000000
6551 #define ENV_MOD_APPEND 0x40000000
6552 #define ENV_MOD_PREFIX 0x80000000
6553 #define ENV_MOD_MASK 0xC0000000
6555 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6557 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6559 LPCWSTR cptr = *name;
6561 static const WCHAR prefix[] = {'[','~',']',0};
6562 static const int prefix_len = 3;
6568 *flags |= ENV_ACT_SETALWAYS;
6569 else if (*cptr == '+')
6570 *flags |= ENV_ACT_SETABSENT;
6571 else if (*cptr == '-')
6572 *flags |= ENV_ACT_REMOVE;
6573 else if (*cptr == '!')
6574 *flags |= ENV_ACT_REMOVEMATCH;
6575 else if (*cptr == '*')
6576 *flags |= ENV_MOD_MACHINE;
6586 ERR("Missing environment variable\n");
6587 return ERROR_FUNCTION_FAILED;
6592 LPCWSTR ptr = *value;
6593 if (!strncmpW(ptr, prefix, prefix_len))
6595 if (ptr[prefix_len] == szSemiColon[0])
6597 *flags |= ENV_MOD_APPEND;
6598 *value += lstrlenW(prefix);
6605 else if (lstrlenW(*value) >= prefix_len)
6607 ptr += lstrlenW(ptr) - prefix_len;
6608 if (!strcmpW( ptr, prefix ))
6610 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6612 *flags |= ENV_MOD_PREFIX;
6613 /* the "[~]" will be removed by deformat_string */;
6623 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6624 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6625 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6626 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6628 ERR("Invalid flags: %08x\n", *flags);
6629 return ERROR_FUNCTION_FAILED;
6633 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6635 return ERROR_SUCCESS;
6638 static UINT open_env_key( DWORD flags, HKEY *key )
6640 static const WCHAR user_env[] =
6641 {'E','n','v','i','r','o','n','m','e','n','t',0};
6642 static const WCHAR machine_env[] =
6643 {'S','y','s','t','e','m','\\',
6644 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6645 'C','o','n','t','r','o','l','\\',
6646 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6647 'E','n','v','i','r','o','n','m','e','n','t',0};
6652 if (flags & ENV_MOD_MACHINE)
6655 root = HKEY_LOCAL_MACHINE;
6660 root = HKEY_CURRENT_USER;
6663 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6664 if (res != ERROR_SUCCESS)
6666 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6667 return ERROR_FUNCTION_FAILED;
6670 return ERROR_SUCCESS;
6673 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6675 MSIPACKAGE *package = param;
6676 LPCWSTR name, value, component;
6677 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6678 DWORD flags, type, size;
6685 component = MSI_RecordGetString(rec, 4);
6686 comp = msi_get_loaded_component(package, component);
6688 return ERROR_SUCCESS;
6690 comp->Action = msi_get_component_action( package, comp );
6691 if (comp->Action != INSTALLSTATE_LOCAL)
6693 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6694 return ERROR_SUCCESS;
6696 name = MSI_RecordGetString(rec, 2);
6697 value = MSI_RecordGetString(rec, 3);
6699 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6701 res = env_parse_flags(&name, &value, &flags);
6702 if (res != ERROR_SUCCESS || !value)
6705 if (value && !deformat_string(package, value, &deformatted))
6707 res = ERROR_OUTOFMEMORY;
6711 value = deformatted;
6713 res = open_env_key( flags, &env );
6714 if (res != ERROR_SUCCESS)
6717 if (flags & ENV_MOD_MACHINE)
6718 action |= 0x20000000;
6722 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6723 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6724 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6727 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6731 /* Nothing to do. */
6734 res = ERROR_SUCCESS;
6738 /* If we are appending but the string was empty, strip ; */
6739 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6741 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6742 newval = strdupW(value);
6745 res = ERROR_OUTOFMEMORY;
6753 /* Contrary to MSDN, +-variable to [~];path works */
6754 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6756 res = ERROR_SUCCESS;
6760 data = msi_alloc(size);
6764 return ERROR_OUTOFMEMORY;
6767 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6768 if (res != ERROR_SUCCESS)
6771 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6774 res = RegDeleteValueW(env, name);
6775 if (res != ERROR_SUCCESS)
6776 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6780 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6781 if (flags & ENV_MOD_MASK)
6785 if (flags & ENV_MOD_APPEND) multiplier++;
6786 if (flags & ENV_MOD_PREFIX) multiplier++;
6787 mod_size = lstrlenW(value) * multiplier;
6788 size += mod_size * sizeof(WCHAR);
6791 newval = msi_alloc(size);
6795 res = ERROR_OUTOFMEMORY;
6799 if (flags & ENV_MOD_PREFIX)
6801 lstrcpyW(newval, value);
6802 ptr = newval + lstrlenW(value);
6803 action |= 0x80000000;
6806 lstrcpyW(ptr, data);
6808 if (flags & ENV_MOD_APPEND)
6810 lstrcatW(newval, value);
6811 action |= 0x40000000;
6814 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6815 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6818 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6822 uirow = MSI_CreateRecord( 3 );
6823 MSI_RecordSetStringW( uirow, 1, name );
6824 MSI_RecordSetStringW( uirow, 2, newval );
6825 MSI_RecordSetInteger( uirow, 3, action );
6826 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6827 msiobj_release( &uirow->hdr );
6829 if (env) RegCloseKey(env);
6830 msi_free(deformatted);
6836 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6838 static const WCHAR query[] = {
6839 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6840 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6844 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6845 if (rc != ERROR_SUCCESS)
6846 return ERROR_SUCCESS;
6848 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6849 msiobj_release(&view->hdr);
6853 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6855 MSIPACKAGE *package = param;
6856 LPCWSTR name, value, component;
6857 LPWSTR deformatted = NULL;
6866 component = MSI_RecordGetString( rec, 4 );
6867 comp = msi_get_loaded_component( package, component );
6869 return ERROR_SUCCESS;
6871 comp->Action = msi_get_component_action( package, comp );
6872 if (comp->Action != INSTALLSTATE_ABSENT)
6874 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6875 return ERROR_SUCCESS;
6877 name = MSI_RecordGetString( rec, 2 );
6878 value = MSI_RecordGetString( rec, 3 );
6880 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6882 r = env_parse_flags( &name, &value, &flags );
6883 if (r != ERROR_SUCCESS)
6886 if (!(flags & ENV_ACT_REMOVE))
6888 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6889 return ERROR_SUCCESS;
6892 if (value && !deformat_string( package, value, &deformatted ))
6893 return ERROR_OUTOFMEMORY;
6895 value = deformatted;
6897 r = open_env_key( flags, &env );
6898 if (r != ERROR_SUCCESS)
6904 if (flags & ENV_MOD_MACHINE)
6905 action |= 0x20000000;
6907 TRACE("Removing %s\n", debugstr_w(name));
6909 res = RegDeleteValueW( env, name );
6910 if (res != ERROR_SUCCESS)
6912 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6917 uirow = MSI_CreateRecord( 3 );
6918 MSI_RecordSetStringW( uirow, 1, name );
6919 MSI_RecordSetStringW( uirow, 2, value );
6920 MSI_RecordSetInteger( uirow, 3, action );
6921 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6922 msiobj_release( &uirow->hdr );
6924 if (env) RegCloseKey( env );
6925 msi_free( deformatted );
6929 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6931 static const WCHAR query[] = {
6932 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6933 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6937 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6938 if (rc != ERROR_SUCCESS)
6939 return ERROR_SUCCESS;
6941 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6942 msiobj_release( &view->hdr );
6946 UINT msi_validate_product_id( MSIPACKAGE *package )
6948 LPWSTR key, template, id;
6949 UINT r = ERROR_SUCCESS;
6951 id = msi_dup_property( package->db, szProductID );
6955 return ERROR_SUCCESS;
6957 template = msi_dup_property( package->db, szPIDTemplate );
6958 key = msi_dup_property( package->db, szPIDKEY );
6959 if (key && template)
6961 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6962 r = msi_set_property( package->db, szProductID, key );
6964 msi_free( template );
6969 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6971 return msi_validate_product_id( package );
6974 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6977 package->need_reboot_at_end = 1;
6978 return ERROR_SUCCESS;
6981 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6983 static const WCHAR szAvailableFreeReg[] =
6984 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6986 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6988 TRACE("%p %d kilobytes\n", package, space);
6990 uirow = MSI_CreateRecord( 1 );
6991 MSI_RecordSetInteger( uirow, 1, space );
6992 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6993 msiobj_release( &uirow->hdr );
6995 return ERROR_SUCCESS;
6998 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7000 TRACE("%p\n", package);
7002 msi_set_property( package->db, szRollbackDisabled, szOne );
7003 return ERROR_SUCCESS;
7006 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7008 FIXME("%p\n", package);
7009 return ERROR_SUCCESS;
7012 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7014 static const WCHAR driver_query[] = {
7015 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7016 'O','D','B','C','D','r','i','v','e','r',0};
7017 static const WCHAR translator_query[] = {
7018 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7019 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
7023 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7024 if (r == ERROR_SUCCESS)
7027 r = MSI_IterateRecords( view, &count, NULL, package );
7028 msiobj_release( &view->hdr );
7029 if (r != ERROR_SUCCESS)
7031 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7033 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7034 if (r == ERROR_SUCCESS)
7037 r = MSI_IterateRecords( view, &count, NULL, package );
7038 msiobj_release( &view->hdr );
7039 if (r != ERROR_SUCCESS)
7041 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7043 return ERROR_SUCCESS;
7046 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7048 MSIPACKAGE *package = param;
7049 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7052 if ((value = msi_dup_property( package->db, property )))
7054 FIXME("remove %s\n", debugstr_w(value));
7057 return ERROR_SUCCESS;
7060 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7062 static const WCHAR query[] = {
7063 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7064 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7068 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7069 if (r == ERROR_SUCCESS)
7071 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7072 msiobj_release( &view->hdr );
7073 if (r != ERROR_SUCCESS)
7076 return ERROR_SUCCESS;
7079 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7081 MSIPACKAGE *package = param;
7082 int attributes = MSI_RecordGetInteger( rec, 5 );
7084 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7086 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7087 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7088 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7089 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7093 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7095 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7096 if (r != ERROR_SUCCESS)
7097 return ERROR_SUCCESS;
7101 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7102 if (r != ERROR_SUCCESS)
7103 return ERROR_SUCCESS;
7105 RegCloseKey( hkey );
7107 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7108 debugstr_w(upgrade_code), debugstr_w(version_min),
7109 debugstr_w(version_max), debugstr_w(language));
7111 return ERROR_SUCCESS;
7114 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7116 static const WCHAR query[] = {
7117 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7118 'U','p','g','r','a','d','e',0};
7122 if (msi_get_property_int( package->db, szInstalled, 0 ))
7124 TRACE("product is installed, skipping action\n");
7125 return ERROR_SUCCESS;
7127 if (msi_get_property_int( package->db, szPreselected, 0 ))
7129 TRACE("Preselected property is set, not migrating feature states\n");
7130 return ERROR_SUCCESS;
7132 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7133 if (r == ERROR_SUCCESS)
7135 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7136 msiobj_release( &view->hdr );
7137 if (r != ERROR_SUCCESS)
7140 return ERROR_SUCCESS;
7143 static void bind_image( const char *filename, const char *path )
7145 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7147 WARN("failed to bind image %u\n", GetLastError());
7151 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7155 MSIPACKAGE *package = param;
7156 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7157 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7158 char *filenameA, *pathA;
7159 WCHAR *pathW, **path_list;
7161 if (!(file = msi_get_loaded_file( package, key )))
7163 WARN("file %s not found\n", debugstr_w(key));
7164 return ERROR_SUCCESS;
7166 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7167 path_list = msi_split_string( paths, ';' );
7168 if (!path_list) bind_image( filenameA, NULL );
7171 for (i = 0; path_list[i] && path_list[i][0]; i++)
7173 deformat_string( package, path_list[i], &pathW );
7174 if ((pathA = strdupWtoA( pathW )))
7176 bind_image( filenameA, pathA );
7182 msi_free( path_list );
7183 msi_free( filenameA );
7184 return ERROR_SUCCESS;
7187 static UINT ACTION_BindImage( MSIPACKAGE *package )
7189 static const WCHAR query[] = {
7190 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7191 'B','i','n','d','I','m','a','g','e',0};
7195 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7196 if (r == ERROR_SUCCESS)
7198 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7199 msiobj_release( &view->hdr );
7200 if (r != ERROR_SUCCESS)
7203 return ERROR_SUCCESS;
7206 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7208 static const WCHAR query[] = {
7209 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7214 r = MSI_OpenQuery( package->db, &view, query, table );
7215 if (r == ERROR_SUCCESS)
7217 r = MSI_IterateRecords(view, &count, NULL, package);
7218 msiobj_release(&view->hdr);
7219 if (r != ERROR_SUCCESS)
7222 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7223 return ERROR_SUCCESS;
7226 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7228 static const WCHAR table[] = {
7229 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7230 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7233 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7235 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7236 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7239 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7241 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7242 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7245 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7247 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7248 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7251 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7253 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7254 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7259 const WCHAR *action;
7260 UINT (*handler)(MSIPACKAGE *);
7261 const WCHAR *action_rollback;
7265 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7266 { szAppSearch, ACTION_AppSearch, NULL },
7267 { szBindImage, ACTION_BindImage, NULL },
7268 { szCCPSearch, ACTION_CCPSearch, NULL },
7269 { szCostFinalize, ACTION_CostFinalize, NULL },
7270 { szCostInitialize, ACTION_CostInitialize, NULL },
7271 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7272 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7273 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7274 { szDisableRollback, ACTION_DisableRollback, NULL },
7275 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7276 { szExecuteAction, ACTION_ExecuteAction, NULL },
7277 { szFileCost, ACTION_FileCost, NULL },
7278 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7279 { szForceReboot, ACTION_ForceReboot, NULL },
7280 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7281 { szInstallExecute, ACTION_InstallExecute, NULL },
7282 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7283 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7284 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7285 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7286 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7287 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7288 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7289 { szInstallValidate, ACTION_InstallValidate, NULL },
7290 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7291 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7292 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7293 { szMoveFiles, ACTION_MoveFiles, NULL },
7294 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7295 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7296 { szPatchFiles, ACTION_PatchFiles, NULL },
7297 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7298 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7299 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7300 { szPublishProduct, ACTION_PublishProduct, NULL },
7301 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7302 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7303 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7304 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7305 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7306 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7307 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7308 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7309 { szRegisterUser, ACTION_RegisterUser, NULL },
7310 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7311 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7312 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7313 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7314 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7315 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7316 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7317 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7318 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7319 { szResolveSource, ACTION_ResolveSource, NULL },
7320 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7321 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7322 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7323 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7324 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7325 { szStartServices, ACTION_StartServices, szStopServices },
7326 { szStopServices, ACTION_StopServices, szStartServices },
7327 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7328 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7329 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7330 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7331 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7332 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7333 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7334 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7335 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7336 { szValidateProductID, ACTION_ValidateProductID, NULL },
7337 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7338 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7339 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7340 { NULL, NULL, NULL }
7343 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7349 while (StandardActions[i].action != NULL)
7351 if (!strcmpW( StandardActions[i].action, action ))
7353 ui_actionstart( package, action );
7354 if (StandardActions[i].handler)
7356 ui_actioninfo( package, action, TRUE, 0 );
7357 *rc = StandardActions[i].handler( package );
7358 ui_actioninfo( package, action, FALSE, *rc );
7360 if (StandardActions[i].action_rollback && !package->need_rollback)
7362 TRACE("scheduling rollback action\n");
7363 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7368 FIXME("unhandled standard action %s\n", debugstr_w(action));
7369 *rc = ERROR_SUCCESS;
7379 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7381 UINT rc = ERROR_SUCCESS;
7384 TRACE("Performing action (%s)\n", debugstr_w(action));
7386 handled = ACTION_HandleStandardAction(package, action, &rc);
7389 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7393 WARN("unhandled msi action %s\n", debugstr_w(action));
7394 rc = ERROR_FUNCTION_NOT_CALLED;
7400 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7402 UINT rc = ERROR_SUCCESS;
7403 BOOL handled = FALSE;
7405 TRACE("Performing action (%s)\n", debugstr_w(action));
7407 package->action_progress_increment = 0;
7408 handled = ACTION_HandleStandardAction(package, action, &rc);
7411 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7413 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7418 WARN("unhandled msi action %s\n", debugstr_w(action));
7419 rc = ERROR_FUNCTION_NOT_CALLED;
7425 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7427 UINT rc = ERROR_SUCCESS;
7430 static const WCHAR query[] =
7431 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7432 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7433 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7434 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7435 static const WCHAR ui_query[] =
7436 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7437 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7438 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7439 ' ', '=',' ','%','i',0};
7441 if (needs_ui_sequence(package))
7442 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7444 row = MSI_QueryGetRecord(package->db, query, seq);
7448 LPCWSTR action, cond;
7450 TRACE("Running the actions\n");
7452 /* check conditions */
7453 cond = MSI_RecordGetString(row, 2);
7455 /* this is a hack to skip errors in the condition code */
7456 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7458 msiobj_release(&row->hdr);
7459 return ERROR_SUCCESS;
7462 action = MSI_RecordGetString(row, 1);
7465 ERR("failed to fetch action\n");
7466 msiobj_release(&row->hdr);
7467 return ERROR_FUNCTION_FAILED;
7470 if (needs_ui_sequence(package))
7471 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7473 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7475 msiobj_release(&row->hdr);
7481 /****************************************************
7482 * TOP level entry points
7483 *****************************************************/
7485 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7486 LPCWSTR szCommandLine )
7488 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7489 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7490 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7491 WCHAR *reinstall = NULL;
7495 msi_set_property( package->db, szAction, szInstall );
7497 package->script->InWhatSequence = SEQUENCE_INSTALL;
7504 dir = strdupW(szPackagePath);
7505 p = strrchrW(dir, '\\');
7509 file = szPackagePath + (p - dir);
7514 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7515 GetCurrentDirectoryW(MAX_PATH, dir);
7516 lstrcatW(dir, szBackSlash);
7517 file = szPackagePath;
7520 msi_free( package->PackagePath );
7521 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7522 if (!package->PackagePath)
7525 return ERROR_OUTOFMEMORY;
7528 lstrcpyW(package->PackagePath, dir);
7529 lstrcatW(package->PackagePath, file);
7532 msi_set_sourcedir_props(package, FALSE);
7535 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7536 if (rc != ERROR_SUCCESS)
7539 msi_apply_transforms( package );
7540 msi_apply_patches( package );
7542 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7544 TRACE("setting reinstall property\n");
7545 msi_set_property( package->db, szReinstall, szAll );
7548 /* properties may have been added by a transform */
7549 msi_clone_properties( package );
7551 msi_parse_command_line( package, szCommandLine, FALSE );
7552 msi_adjust_privilege_properties( package );
7553 msi_set_context( package );
7555 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7557 TRACE("disabling rollback\n");
7558 msi_set_property( package->db, szRollbackDisabled, szOne );
7561 if (needs_ui_sequence( package))
7563 package->script->InWhatSequence |= SEQUENCE_UI;
7564 rc = ACTION_ProcessUISequence(package);
7565 ui_exists = ui_sequence_exists(package);
7566 if (rc == ERROR_SUCCESS || !ui_exists)
7568 package->script->InWhatSequence |= SEQUENCE_EXEC;
7569 rc = ACTION_ProcessExecSequence(package, ui_exists);
7573 rc = ACTION_ProcessExecSequence(package, FALSE);
7575 package->script->CurrentlyScripting = FALSE;
7577 /* process the ending type action */
7578 if (rc == ERROR_SUCCESS)
7579 ACTION_PerformActionSequence(package, -1);
7580 else if (rc == ERROR_INSTALL_USEREXIT)
7581 ACTION_PerformActionSequence(package, -2);
7582 else if (rc == ERROR_INSTALL_SUSPEND)
7583 ACTION_PerformActionSequence(package, -4);
7586 ACTION_PerformActionSequence(package, -3);
7587 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7589 package->need_rollback = TRUE;
7593 /* finish up running custom actions */
7594 ACTION_FinishCustomActions(package);
7596 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7598 WARN("installation failed, running rollback script\n");
7599 execute_script( package, SCRIPT_ROLLBACK );
7601 msi_free( reinstall );
7603 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7604 return ERROR_SUCCESS_REBOOT_REQUIRED;