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);
1020 msi_destroy_assembly_caches( package );
1025 MSIPACKAGE *package;
1026 MSIFEATURE *feature;
1029 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1033 cl = msi_alloc( sizeof (*cl) );
1035 return ERROR_NOT_ENOUGH_MEMORY;
1036 cl->component = comp;
1037 list_add_tail( &feature->Components, &cl->entry );
1039 return ERROR_SUCCESS;
1042 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1046 fl = msi_alloc( sizeof(*fl) );
1048 return ERROR_NOT_ENOUGH_MEMORY;
1049 fl->feature = child;
1050 list_add_tail( &parent->Children, &fl->entry );
1052 return ERROR_SUCCESS;
1055 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1057 _ilfs* ilfs = param;
1061 component = MSI_RecordGetString(row,1);
1063 /* check to see if the component is already loaded */
1064 comp = msi_get_loaded_component( ilfs->package, component );
1067 WARN("ignoring unknown component %s\n", debugstr_w(component));
1068 return ERROR_SUCCESS;
1070 add_feature_component( ilfs->feature, comp );
1071 comp->Enabled = TRUE;
1073 return ERROR_SUCCESS;
1076 static UINT load_feature(MSIRECORD * row, LPVOID param)
1078 static const WCHAR query[] = {
1079 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1080 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1081 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1082 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1083 MSIPACKAGE *package = param;
1084 MSIFEATURE *feature;
1089 /* fill in the data */
1091 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1093 return ERROR_NOT_ENOUGH_MEMORY;
1095 list_init( &feature->Children );
1096 list_init( &feature->Components );
1098 feature->Feature = msi_dup_record_field( row, 1 );
1100 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1102 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1103 feature->Title = msi_dup_record_field( row, 3 );
1104 feature->Description = msi_dup_record_field( row, 4 );
1106 if (!MSI_RecordIsNull(row,5))
1107 feature->Display = MSI_RecordGetInteger(row,5);
1109 feature->Level= MSI_RecordGetInteger(row,6);
1110 feature->Directory = msi_dup_record_field( row, 7 );
1111 feature->Attributes = MSI_RecordGetInteger(row,8);
1113 feature->Installed = INSTALLSTATE_UNKNOWN;
1114 feature->Action = INSTALLSTATE_UNKNOWN;
1115 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1117 list_add_tail( &package->features, &feature->entry );
1119 /* load feature components */
1121 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1125 ilfs.package = package;
1126 ilfs.feature = feature;
1128 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1129 msiobj_release(&view->hdr);
1133 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1135 MSIPACKAGE *package = param;
1136 MSIFEATURE *parent, *child;
1138 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1140 return ERROR_FUNCTION_FAILED;
1142 if (!child->Feature_Parent)
1143 return ERROR_SUCCESS;
1145 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1147 return ERROR_FUNCTION_FAILED;
1149 add_feature_child( parent, child );
1150 return ERROR_SUCCESS;
1153 UINT msi_load_all_features( MSIPACKAGE *package )
1155 static const WCHAR query[] = {
1156 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1157 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1158 '`','D','i','s','p','l','a','y','`',0};
1162 if (!list_empty(&package->features))
1163 return ERROR_SUCCESS;
1165 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1166 if (r != ERROR_SUCCESS)
1169 r = MSI_IterateRecords( view, NULL, load_feature, package );
1170 if (r != ERROR_SUCCESS)
1172 msiobj_release( &view->hdr );
1175 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1176 msiobj_release( &view->hdr );
1180 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1191 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1193 static const WCHAR query[] = {
1194 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1195 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1196 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1197 MSIQUERY *view = NULL;
1198 MSIRECORD *row = NULL;
1201 TRACE("%s\n", debugstr_w(file->File));
1203 r = MSI_OpenQuery(package->db, &view, query, file->File);
1204 if (r != ERROR_SUCCESS)
1207 r = MSI_ViewExecute(view, NULL);
1208 if (r != ERROR_SUCCESS)
1211 r = MSI_ViewFetch(view, &row);
1212 if (r != ERROR_SUCCESS)
1215 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1216 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1217 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1218 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1219 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1222 if (view) msiobj_release(&view->hdr);
1223 if (row) msiobj_release(&row->hdr);
1227 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1230 static const WCHAR query[] = {
1231 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1232 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1233 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1235 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1238 WARN("query failed\n");
1239 return ERROR_FUNCTION_FAILED;
1242 file->disk_id = MSI_RecordGetInteger( row, 1 );
1243 msiobj_release( &row->hdr );
1244 return ERROR_SUCCESS;
1247 static UINT load_file(MSIRECORD *row, LPVOID param)
1249 MSIPACKAGE* package = param;
1253 /* fill in the data */
1255 file = msi_alloc_zero( sizeof (MSIFILE) );
1257 return ERROR_NOT_ENOUGH_MEMORY;
1259 file->File = msi_dup_record_field( row, 1 );
1261 component = MSI_RecordGetString( row, 2 );
1262 file->Component = msi_get_loaded_component( package, component );
1264 if (!file->Component)
1266 WARN("Component not found: %s\n", debugstr_w(component));
1267 msi_free(file->File);
1269 return ERROR_SUCCESS;
1272 file->FileName = msi_dup_record_field( row, 3 );
1273 msi_reduce_to_long_filename( file->FileName );
1275 file->ShortName = msi_dup_record_field( row, 3 );
1276 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1278 file->FileSize = MSI_RecordGetInteger( row, 4 );
1279 file->Version = msi_dup_record_field( row, 5 );
1280 file->Language = msi_dup_record_field( row, 6 );
1281 file->Attributes = MSI_RecordGetInteger( row, 7 );
1282 file->Sequence = MSI_RecordGetInteger( row, 8 );
1284 file->state = msifs_invalid;
1286 /* if the compressed bits are not set in the file attributes,
1287 * then read the information from the package word count property
1289 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1291 file->IsCompressed = FALSE;
1293 else if (file->Attributes &
1294 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1296 file->IsCompressed = TRUE;
1298 else if (file->Attributes & msidbFileAttributesNoncompressed)
1300 file->IsCompressed = FALSE;
1304 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1307 load_file_hash(package, file);
1308 load_file_disk_id(package, file);
1310 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1312 list_add_tail( &package->files, &file->entry );
1314 return ERROR_SUCCESS;
1317 static UINT load_all_files(MSIPACKAGE *package)
1319 static const WCHAR query[] = {
1320 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1321 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1322 '`','S','e','q','u','e','n','c','e','`', 0};
1326 if (!list_empty(&package->files))
1327 return ERROR_SUCCESS;
1329 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1330 if (rc != ERROR_SUCCESS)
1331 return ERROR_SUCCESS;
1333 rc = MSI_IterateRecords(view, NULL, load_file, package);
1334 msiobj_release(&view->hdr);
1338 static UINT load_media( MSIRECORD *row, LPVOID param )
1340 MSIPACKAGE *package = param;
1341 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1342 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1344 /* FIXME: load external cabinets and directory sources too */
1345 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1346 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1347 return ERROR_SUCCESS;
1350 static UINT load_all_media( MSIPACKAGE *package )
1352 static const WCHAR query[] = {
1353 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1354 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1355 '`','D','i','s','k','I','d','`',0};
1359 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1360 if (r != ERROR_SUCCESS)
1361 return ERROR_SUCCESS;
1363 r = MSI_IterateRecords( view, NULL, load_media, package );
1364 msiobj_release( &view->hdr );
1368 static UINT load_patch(MSIRECORD *row, LPVOID param)
1370 MSIPACKAGE *package = param;
1371 MSIFILEPATCH *patch;
1374 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1376 return ERROR_NOT_ENOUGH_MEMORY;
1378 file_key = msi_dup_record_field( row, 1 );
1379 patch->File = msi_get_loaded_file( package, file_key );
1384 ERR("Failed to find target for patch in File table\n");
1386 return ERROR_FUNCTION_FAILED;
1389 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1391 /* FIXME: The database should be properly transformed */
1392 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1394 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1395 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1396 patch->IsApplied = FALSE;
1399 * Header field - for patch validation.
1400 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1403 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1405 list_add_tail( &package->filepatches, &patch->entry );
1407 return ERROR_SUCCESS;
1410 static UINT load_all_patches(MSIPACKAGE *package)
1412 static const WCHAR query[] = {
1413 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1414 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1415 '`','S','e','q','u','e','n','c','e','`',0};
1419 if (!list_empty(&package->filepatches))
1420 return ERROR_SUCCESS;
1422 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1423 if (rc != ERROR_SUCCESS)
1424 return ERROR_SUCCESS;
1426 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1427 msiobj_release(&view->hdr);
1431 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1433 static const WCHAR query[] = {
1434 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1435 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1436 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1439 folder->persistent = FALSE;
1440 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1442 if (!MSI_ViewExecute( view, NULL ))
1445 if (!MSI_ViewFetch( view, &rec ))
1447 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1448 folder->persistent = TRUE;
1449 msiobj_release( &rec->hdr );
1452 msiobj_release( &view->hdr );
1454 return ERROR_SUCCESS;
1457 static UINT load_folder( MSIRECORD *row, LPVOID param )
1459 MSIPACKAGE *package = param;
1460 static WCHAR szEmpty[] = { 0 };
1461 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1464 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1465 list_init( &folder->children );
1466 folder->Directory = msi_dup_record_field( row, 1 );
1467 folder->Parent = msi_dup_record_field( row, 2 );
1468 p = msi_dup_record_field(row, 3);
1470 TRACE("%s\n", debugstr_w(folder->Directory));
1472 /* split src and target dir */
1474 src_short = folder_split_path( p, ':' );
1476 /* split the long and short paths */
1477 tgt_long = folder_split_path( tgt_short, '|' );
1478 src_long = folder_split_path( src_short, '|' );
1480 /* check for no-op dirs */
1481 if (tgt_short && !strcmpW( szDot, tgt_short ))
1482 tgt_short = szEmpty;
1483 if (src_short && !strcmpW( szDot, src_short ))
1484 src_short = szEmpty;
1487 tgt_long = tgt_short;
1490 src_short = tgt_short;
1491 src_long = tgt_long;
1495 src_long = src_short;
1497 /* FIXME: use the target short path too */
1498 folder->TargetDefault = strdupW(tgt_long);
1499 folder->SourceShortPath = strdupW(src_short);
1500 folder->SourceLongPath = strdupW(src_long);
1503 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1504 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1505 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1507 load_folder_persistence( package, folder );
1509 list_add_tail( &package->folders, &folder->entry );
1510 return ERROR_SUCCESS;
1513 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1517 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1519 list_add_tail( &parent->children, &fl->entry );
1520 return ERROR_SUCCESS;
1523 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1525 MSIPACKAGE *package = param;
1526 MSIFOLDER *parent, *child;
1528 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1529 return ERROR_FUNCTION_FAILED;
1531 if (!child->Parent) return ERROR_SUCCESS;
1533 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1534 return ERROR_FUNCTION_FAILED;
1536 return add_folder_child( parent, child );
1539 static UINT load_all_folders( MSIPACKAGE *package )
1541 static const WCHAR query[] = {
1542 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1543 '`','D','i','r','e','c','t','o','r','y','`',0};
1547 if (!list_empty(&package->folders))
1548 return ERROR_SUCCESS;
1550 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1551 if (r != ERROR_SUCCESS)
1554 r = MSI_IterateRecords( view, NULL, load_folder, package );
1555 if (r != ERROR_SUCCESS)
1557 msiobj_release( &view->hdr );
1560 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1561 msiobj_release( &view->hdr );
1565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1567 msi_set_property( package->db, szCostingComplete, szZero );
1568 msi_set_property( package->db, szRootDrive, szCRoot );
1570 load_all_folders( package );
1571 msi_load_all_components( package );
1572 msi_load_all_features( package );
1573 load_all_files( package );
1574 load_all_patches( package );
1575 load_all_media( package );
1577 return ERROR_SUCCESS;
1580 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1582 const WCHAR *action = package->script->Actions[script][index];
1583 ui_actionstart( package, action );
1584 TRACE("executing %s\n", debugstr_w(action));
1585 return ACTION_PerformAction( package, action, script );
1588 static UINT execute_script( MSIPACKAGE *package, UINT script )
1590 UINT i, rc = ERROR_SUCCESS;
1592 TRACE("executing script %u\n", script);
1594 if (!package->script)
1596 ERR("no script!\n");
1597 return ERROR_FUNCTION_FAILED;
1599 if (script == SCRIPT_ROLLBACK)
1601 for (i = package->script->ActionCount[script]; i > 0; i--)
1603 rc = execute_script_action( package, script, i - 1 );
1604 if (rc != ERROR_SUCCESS) break;
1609 for (i = 0; i < package->script->ActionCount[script]; i++)
1611 rc = execute_script_action( package, script, i );
1612 if (rc != ERROR_SUCCESS) break;
1615 msi_free_action_script(package, script);
1619 static UINT ACTION_FileCost(MSIPACKAGE *package)
1621 return ERROR_SUCCESS;
1624 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1629 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1631 if (!comp->ComponentId) continue;
1633 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1634 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1636 if (r == ERROR_SUCCESS) continue;
1638 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1639 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1641 if (r == ERROR_SUCCESS) continue;
1643 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1644 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1646 if (r == ERROR_SUCCESS) continue;
1648 comp->Installed = INSTALLSTATE_ABSENT;
1652 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1654 MSIFEATURE *feature;
1656 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1658 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1660 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1661 feature->Installed = INSTALLSTATE_ABSENT;
1663 feature->Installed = state;
1667 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1669 return (feature->Level > 0 && feature->Level <= level);
1672 static BOOL process_state_property(MSIPACKAGE* package, int level,
1673 LPCWSTR property, INSTALLSTATE state)
1676 MSIFEATURE *feature;
1678 override = msi_dup_property( package->db, property );
1682 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1684 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1687 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1689 if (!strcmpiW( override, szAll ))
1691 if (feature->Installed != state)
1693 feature->Action = state;
1694 feature->ActionRequest = state;
1699 LPWSTR ptr = override;
1700 LPWSTR ptr2 = strchrW(override,',');
1704 int len = ptr2 - ptr;
1706 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1707 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1709 if (feature->Installed != state)
1711 feature->Action = state;
1712 feature->ActionRequest = state;
1719 ptr2 = strchrW(ptr,',');
1730 static BOOL process_overrides( MSIPACKAGE *package, int level )
1732 static const WCHAR szAddLocal[] =
1733 {'A','D','D','L','O','C','A','L',0};
1734 static const WCHAR szAddSource[] =
1735 {'A','D','D','S','O','U','R','C','E',0};
1736 static const WCHAR szAdvertise[] =
1737 {'A','D','V','E','R','T','I','S','E',0};
1740 /* all these activation/deactivation things happen in order and things
1741 * later on the list override things earlier on the list.
1743 * 0 INSTALLLEVEL processing
1756 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1757 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1758 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1759 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1760 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1763 msi_set_property( package->db, szPreselected, szOne );
1768 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1771 MSICOMPONENT* component;
1772 MSIFEATURE *feature;
1774 TRACE("Checking Install Level\n");
1776 level = msi_get_property_int(package->db, szInstallLevel, 1);
1778 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1780 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1782 if (!is_feature_selected( feature, level )) continue;
1784 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1786 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1788 feature->Action = INSTALLSTATE_SOURCE;
1789 feature->ActionRequest = INSTALLSTATE_SOURCE;
1791 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1793 feature->Action = INSTALLSTATE_ADVERTISED;
1794 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1798 feature->Action = INSTALLSTATE_LOCAL;
1799 feature->ActionRequest = INSTALLSTATE_LOCAL;
1803 /* disable child features of unselected parent or follow parent */
1804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1808 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1810 if (!is_feature_selected( feature, level ))
1812 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1813 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1815 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1817 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1818 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1819 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1820 fl->feature->Action = feature->Action;
1821 fl->feature->ActionRequest = feature->ActionRequest;
1826 else /* preselected */
1828 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1830 if (!is_feature_selected( feature, level )) continue;
1832 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1834 if (feature->Installed == INSTALLSTATE_ABSENT)
1836 feature->Action = INSTALLSTATE_UNKNOWN;
1837 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1841 feature->Action = feature->Installed;
1842 feature->ActionRequest = feature->Installed;
1846 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1850 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1852 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1853 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1855 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1856 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1857 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1858 fl->feature->Action = feature->Action;
1859 fl->feature->ActionRequest = feature->ActionRequest;
1865 /* now we want to set component state based based on feature state */
1866 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1870 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1871 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1872 feature->ActionRequest, feature->Action);
1874 if (!is_feature_selected( feature, level )) continue;
1876 /* features with components that have compressed files are made local */
1877 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1879 if (cl->component->ForceLocalState &&
1880 feature->ActionRequest == INSTALLSTATE_SOURCE)
1882 feature->Action = INSTALLSTATE_LOCAL;
1883 feature->ActionRequest = INSTALLSTATE_LOCAL;
1888 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1890 component = cl->component;
1892 switch (feature->ActionRequest)
1894 case INSTALLSTATE_ABSENT:
1895 component->anyAbsent = 1;
1897 case INSTALLSTATE_ADVERTISED:
1898 component->hasAdvertiseFeature = 1;
1900 case INSTALLSTATE_SOURCE:
1901 component->hasSourceFeature = 1;
1903 case INSTALLSTATE_LOCAL:
1904 component->hasLocalFeature = 1;
1906 case INSTALLSTATE_DEFAULT:
1907 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1908 component->hasAdvertiseFeature = 1;
1909 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1910 component->hasSourceFeature = 1;
1912 component->hasLocalFeature = 1;
1920 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1922 /* check if it's local or source */
1923 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1924 (component->hasLocalFeature || component->hasSourceFeature))
1926 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1927 !component->ForceLocalState)
1929 component->Action = INSTALLSTATE_SOURCE;
1930 component->ActionRequest = INSTALLSTATE_SOURCE;
1934 component->Action = INSTALLSTATE_LOCAL;
1935 component->ActionRequest = INSTALLSTATE_LOCAL;
1940 /* if any feature is local, the component must be local too */
1941 if (component->hasLocalFeature)
1943 component->Action = INSTALLSTATE_LOCAL;
1944 component->ActionRequest = INSTALLSTATE_LOCAL;
1947 if (component->hasSourceFeature)
1949 component->Action = INSTALLSTATE_SOURCE;
1950 component->ActionRequest = INSTALLSTATE_SOURCE;
1953 if (component->hasAdvertiseFeature)
1955 component->Action = INSTALLSTATE_ADVERTISED;
1956 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1959 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1960 if (component->anyAbsent &&
1961 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1963 component->Action = INSTALLSTATE_ABSENT;
1964 component->ActionRequest = INSTALLSTATE_ABSENT;
1968 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1970 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1972 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1973 component->Action = INSTALLSTATE_LOCAL;
1974 component->ActionRequest = INSTALLSTATE_LOCAL;
1977 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1978 component->Installed == INSTALLSTATE_SOURCE &&
1979 component->hasSourceFeature)
1981 component->Action = INSTALLSTATE_UNKNOWN;
1982 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1985 TRACE("component %s (installed %d request %d action %d)\n",
1986 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1989 return ERROR_SUCCESS;
1992 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1994 MSIPACKAGE *package = param;
1996 MSIFEATURE *feature;
1998 name = MSI_RecordGetString( row, 1 );
2000 feature = msi_get_loaded_feature( package, name );
2002 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2006 Condition = MSI_RecordGetString(row,3);
2008 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2010 int level = MSI_RecordGetInteger(row,2);
2011 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2012 feature->Level = level;
2015 return ERROR_SUCCESS;
2018 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2020 static const WCHAR name[] = {'\\',0};
2021 VS_FIXEDFILEINFO *ptr, *ret;
2023 DWORD versize, handle;
2026 versize = GetFileVersionInfoSizeW( filename, &handle );
2030 version = msi_alloc( versize );
2034 GetFileVersionInfoW( filename, 0, versize, version );
2036 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2038 msi_free( version );
2042 ret = msi_alloc( sz );
2043 memcpy( ret, ptr, sz );
2045 msi_free( version );
2049 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2053 msi_parse_version_string( version, &ms, &ls );
2055 if (fi->dwFileVersionMS > ms) return 1;
2056 else if (fi->dwFileVersionMS < ms) return -1;
2057 else if (fi->dwFileVersionLS > ls) return 1;
2058 else if (fi->dwFileVersionLS < ls) return -1;
2062 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2066 msi_parse_version_string( ver1, &ms1, NULL );
2067 msi_parse_version_string( ver2, &ms2, NULL );
2069 if (ms1 > ms2) return 1;
2070 else if (ms1 < ms2) return -1;
2074 DWORD msi_get_disk_file_size( LPCWSTR filename )
2079 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2080 if (file == INVALID_HANDLE_VALUE)
2081 return INVALID_FILE_SIZE;
2083 size = GetFileSize( file, NULL );
2084 TRACE("size is %u\n", size);
2085 CloseHandle( file );
2089 BOOL msi_file_hash_matches( MSIFILE *file )
2092 MSIFILEHASHINFO hash;
2094 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2095 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2096 if (r != ERROR_SUCCESS)
2099 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2102 static WCHAR *get_temp_dir( void )
2105 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2107 GetTempPathW( MAX_PATH, tmp );
2110 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2111 if (CreateDirectoryW( dir, NULL )) break;
2113 return strdupW( dir );
2117 * msi_build_directory_name()
2119 * This function is to save messing round with directory names
2120 * It handles adding backslashes between path segments,
2121 * and can add \ at the end of the directory name if told to.
2123 * It takes a variable number of arguments.
2124 * It always allocates a new string for the result, so make sure
2125 * to free the return value when finished with it.
2127 * The first arg is the number of path segments that follow.
2128 * The arguments following count are a list of path segments.
2129 * A path segment may be NULL.
2131 * Path segments will be added with a \ separating them.
2132 * A \ will not be added after the last segment, however if the
2133 * last segment is NULL, then the last character will be a \
2135 WCHAR *msi_build_directory_name( DWORD count, ... )
2141 va_start( va, count );
2142 for (i = 0; i < count; i++)
2144 const WCHAR *str = va_arg( va, const WCHAR * );
2145 if (str) sz += strlenW( str ) + 1;
2149 dir = msi_alloc( sz * sizeof(WCHAR) );
2152 va_start( va, count );
2153 for (i = 0; i < count; i++)
2155 const WCHAR *str = va_arg( va, const WCHAR * );
2157 strcatW( dir, str );
2158 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2166 MSIASSEMBLY *assembly = file->Component->assembly;
2168 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2170 msi_free( file->TargetPath );
2171 if (assembly && !assembly->application)
2173 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2174 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2175 msi_track_tempfile( package, file->TargetPath );
2179 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2180 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2183 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2186 static UINT calculate_file_cost( MSIPACKAGE *package )
2188 VS_FIXEDFILEINFO *file_version;
2189 WCHAR *font_version;
2192 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2194 MSICOMPONENT *comp = file->Component;
2197 if (!comp->Enabled) continue;
2199 if (file->IsCompressed)
2200 comp->ForceLocalState = TRUE;
2202 set_target_path( package, file );
2204 if ((comp->assembly && !comp->assembly->installed) ||
2205 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2207 comp->Cost += file->FileSize;
2210 file_size = msi_get_disk_file_size( file->TargetPath );
2214 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2216 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2218 comp->Cost += file->FileSize - file_size;
2220 msi_free( file_version );
2223 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2225 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2227 comp->Cost += file->FileSize - file_size;
2229 msi_free( font_version );
2233 if (file_size != file->FileSize)
2235 comp->Cost += file->FileSize - file_size;
2238 return ERROR_SUCCESS;
2241 WCHAR *msi_normalize_path( const WCHAR *in )
2243 const WCHAR *p = in;
2245 int n, len = strlenW( in ) + 2;
2247 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2252 /* copy until the end of the string or a space */
2253 while (*p != ' ' && (*q = *p))
2256 /* reduce many backslashes to one */
2257 if (*p != '\\' || *q != '\\')
2261 /* quit at the end of the string */
2265 /* count the number of spaces */
2270 /* if it's leading or trailing space, skip it */
2271 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2273 else /* copy n spaces */
2274 while (n && (*q++ = *p++)) n--;
2276 while (q - ret > 0 && q[-1] == ' ') q--;
2277 if (q - ret > 0 && q[-1] != '\\')
2285 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2288 MSIFOLDER *folder, *parent, *child;
2289 WCHAR *path, *normalized_path;
2291 TRACE("resolving %s\n", debugstr_w(name));
2293 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2295 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2297 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2299 path = msi_dup_property( package->db, szRootDrive );
2302 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2304 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2306 parent = msi_get_loaded_folder( package, folder->Parent );
2307 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2310 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2312 normalized_path = msi_normalize_path( path );
2314 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2316 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2317 msi_free( normalized_path );
2320 msi_set_property( package->db, folder->Directory, normalized_path );
2321 msi_free( folder->ResolvedTarget );
2322 folder->ResolvedTarget = normalized_path;
2324 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2327 msi_resolve_target_folder( package, child->Directory, load_prop );
2329 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2332 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2334 static const WCHAR query[] = {
2335 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2336 '`','C','o','n','d','i','t','i','o','n','`',0};
2337 static const WCHAR szOutOfDiskSpace[] = {
2338 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2344 TRACE("Building directory properties\n");
2345 msi_resolve_target_folder( package, szTargetDir, TRUE );
2347 TRACE("Evaluating component conditions\n");
2348 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2350 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2352 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2353 comp->Enabled = FALSE;
2356 comp->Enabled = TRUE;
2359 /* read components states from the registry */
2360 ACTION_GetComponentInstallStates(package);
2361 ACTION_GetFeatureInstallStates(package);
2363 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2365 TRACE("Evaluating feature conditions\n");
2367 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2368 if (rc == ERROR_SUCCESS)
2370 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2371 msiobj_release( &view->hdr );
2372 if (rc != ERROR_SUCCESS)
2377 TRACE("Calculating file cost\n");
2378 calculate_file_cost( package );
2380 msi_set_property( package->db, szCostingComplete, szOne );
2381 /* set default run level if not set */
2382 level = msi_dup_property( package->db, szInstallLevel );
2384 msi_set_property( package->db, szInstallLevel, szOne );
2387 /* FIXME: check volume disk space */
2388 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2390 return MSI_SetFeatureStates(package);
2393 /* OK this value is "interpreted" and then formatted based on the
2394 first few characters */
2395 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2400 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2406 LPWSTR deformated = NULL;
2409 deformat_string(package, &value[2], &deformated);
2411 /* binary value type */
2415 *size = (strlenW(ptr)/2)+1;
2417 *size = strlenW(ptr)/2;
2419 data = msi_alloc(*size);
2425 /* if uneven pad with a zero in front */
2431 data[count] = (BYTE)strtol(byte,NULL,0);
2433 TRACE("Uneven byte count\n");
2441 data[count] = (BYTE)strtol(byte,NULL,0);
2444 msi_free(deformated);
2446 TRACE("Data %i bytes(%i)\n",*size,count);
2453 deformat_string(package, &value[1], &deformated);
2456 *size = sizeof(DWORD);
2457 data = msi_alloc(*size);
2463 if ( (*p < '0') || (*p > '9') )
2469 if (deformated[0] == '-')
2472 TRACE("DWORD %i\n",*(LPDWORD)data);
2474 msi_free(deformated);
2479 static const WCHAR szMulti[] = {'[','~',']',0};
2488 *type=REG_EXPAND_SZ;
2496 if (strstrW(value, szMulti))
2497 *type = REG_MULTI_SZ;
2499 /* remove initial delimiter */
2500 if (!strncmpW(value, szMulti, 3))
2503 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2505 /* add double NULL terminator */
2506 if (*type == REG_MULTI_SZ)
2508 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2509 data = msi_realloc_zero(data, *size);
2515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2522 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2524 *root_key = HKEY_LOCAL_MACHINE;
2529 *root_key = HKEY_CURRENT_USER;
2534 *root_key = HKEY_CLASSES_ROOT;
2538 *root_key = HKEY_CURRENT_USER;
2542 *root_key = HKEY_LOCAL_MACHINE;
2546 *root_key = HKEY_USERS;
2550 ERR("Unknown root %i\n", root);
2557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2559 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2560 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2562 if (is_64bit && package->platform == PLATFORM_INTEL &&
2563 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2568 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2569 if (!(path_32node = msi_alloc( size ))) return NULL;
2571 memcpy( path_32node, path, len * sizeof(WCHAR) );
2572 strcpyW( path_32node + len, szWow6432Node );
2573 strcatW( path_32node, szBackSlash );
2574 strcatW( path_32node, path + len );
2578 return strdupW( path );
2581 static BOOL is_special_entry( const WCHAR *name, const WCHAR *value )
2583 return (name && (name[0] == '*' || name[0] == '+') && !name[1] && !value);
2586 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2588 MSIPACKAGE *package = param;
2589 LPSTR value_data = NULL;
2590 HKEY root_key, hkey;
2592 LPWSTR deformated, uikey, keypath;
2593 LPCWSTR szRoot, component, name, key, value;
2597 BOOL check_first = FALSE;
2600 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2602 component = MSI_RecordGetString(row, 6);
2603 comp = msi_get_loaded_component(package,component);
2605 return ERROR_SUCCESS;
2607 comp->Action = msi_get_component_action( package, comp );
2608 if (comp->Action != INSTALLSTATE_LOCAL)
2610 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2611 return ERROR_SUCCESS;
2614 name = MSI_RecordGetString(row, 4);
2615 if( MSI_RecordIsNull(row,5) && name )
2617 /* null values can have special meanings */
2618 if (name[0]=='-' && name[1] == 0)
2619 return ERROR_SUCCESS;
2620 if ((name[0] == '+' || name[0] == '*') && !name[1])
2624 root = MSI_RecordGetInteger(row,2);
2625 key = MSI_RecordGetString(row, 3);
2627 szRoot = get_root_key( package, root, &root_key );
2629 return ERROR_SUCCESS;
2631 deformat_string(package, key , &deformated);
2632 size = strlenW(deformated) + strlenW(szRoot) + 1;
2633 uikey = msi_alloc(size*sizeof(WCHAR));
2634 strcpyW(uikey,szRoot);
2635 strcatW(uikey,deformated);
2637 keypath = get_keypath( package, root_key, deformated );
2638 msi_free( deformated );
2639 if (RegCreateKeyW( root_key, keypath, &hkey ))
2641 ERR("Could not create key %s\n", debugstr_w(keypath));
2644 return ERROR_SUCCESS;
2647 value = MSI_RecordGetString(row,5);
2649 value_data = parse_value(package, value, &type, &size);
2652 value_data = (LPSTR)strdupW(szEmpty);
2653 size = sizeof(szEmpty);
2657 deformat_string(package, name, &deformated);
2658 if (!is_special_entry( name , value ))
2662 TRACE("Setting value %s of %s\n", debugstr_w(deformated),
2664 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2669 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2670 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2672 TRACE("value %s of %s checked already exists\n", debugstr_w(deformated),
2677 TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated),
2679 if (deformated || size)
2680 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2686 uirow = MSI_CreateRecord(3);
2687 MSI_RecordSetStringW(uirow,2,deformated);
2688 MSI_RecordSetStringW(uirow,1,uikey);
2689 if (type == REG_SZ || type == REG_EXPAND_SZ)
2690 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2691 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2692 msiobj_release( &uirow->hdr );
2694 msi_free(value_data);
2695 msi_free(deformated);
2699 return ERROR_SUCCESS;
2702 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2704 static const WCHAR query[] = {
2705 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2706 '`','R','e','g','i','s','t','r','y','`',0};
2710 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2711 if (rc != ERROR_SUCCESS)
2712 return ERROR_SUCCESS;
2714 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2715 msiobj_release(&view->hdr);
2719 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2723 DWORD num_subkeys, num_values;
2725 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2727 if ((res = RegDeleteValueW( hkey, value )))
2729 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2731 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2732 NULL, NULL, NULL, NULL );
2733 RegCloseKey( hkey );
2734 if (!res && !num_subkeys && !num_values)
2736 TRACE("removing empty key %s\n", debugstr_w(keypath));
2737 RegDeleteKeyW( root, keypath );
2741 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2744 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2746 LONG res = RegDeleteTreeW( root, keypath );
2747 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2750 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2752 MSIPACKAGE *package = param;
2753 LPCWSTR component, name, key_str, root_key_str;
2754 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2757 BOOL delete_key = FALSE;
2762 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2764 component = MSI_RecordGetString( row, 6 );
2765 comp = msi_get_loaded_component( package, component );
2767 return ERROR_SUCCESS;
2769 comp->Action = msi_get_component_action( package, comp );
2770 if (comp->Action != INSTALLSTATE_ABSENT)
2772 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2773 return ERROR_SUCCESS;
2776 name = MSI_RecordGetString( row, 4 );
2777 if (MSI_RecordIsNull( row, 5 ) && name )
2779 if (name[0] == '+' && !name[1])
2780 return ERROR_SUCCESS;
2781 if ((name[0] == '-' || name[0] == '*') && !name[1])
2788 root = MSI_RecordGetInteger( row, 2 );
2789 key_str = MSI_RecordGetString( row, 3 );
2791 root_key_str = get_root_key( package, root, &hkey_root );
2793 return ERROR_SUCCESS;
2795 deformat_string( package, key_str, &deformated_key );
2796 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2797 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2798 strcpyW( ui_key_str, root_key_str );
2799 strcatW( ui_key_str, deformated_key );
2801 deformat_string( package, name, &deformated_name );
2803 keypath = get_keypath( package, hkey_root, deformated_key );
2804 msi_free( deformated_key );
2805 if (delete_key) delete_reg_key( hkey_root, keypath );
2806 else delete_reg_value( hkey_root, keypath, deformated_name );
2807 msi_free( keypath );
2809 uirow = MSI_CreateRecord( 2 );
2810 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2811 MSI_RecordSetStringW( uirow, 2, deformated_name );
2812 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2813 msiobj_release( &uirow->hdr );
2815 msi_free( ui_key_str );
2816 msi_free( deformated_name );
2817 return ERROR_SUCCESS;
2820 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2822 MSIPACKAGE *package = param;
2823 LPCWSTR component, name, key_str, root_key_str;
2824 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2827 BOOL delete_key = FALSE;
2832 component = MSI_RecordGetString( row, 5 );
2833 comp = msi_get_loaded_component( package, component );
2835 return ERROR_SUCCESS;
2837 comp->Action = msi_get_component_action( package, comp );
2838 if (comp->Action != INSTALLSTATE_LOCAL)
2840 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2841 return ERROR_SUCCESS;
2844 if ((name = MSI_RecordGetString( row, 4 )))
2846 if (name[0] == '-' && !name[1])
2853 root = MSI_RecordGetInteger( row, 2 );
2854 key_str = MSI_RecordGetString( row, 3 );
2856 root_key_str = get_root_key( package, root, &hkey_root );
2858 return ERROR_SUCCESS;
2860 deformat_string( package, key_str, &deformated_key );
2861 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2862 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2863 strcpyW( ui_key_str, root_key_str );
2864 strcatW( ui_key_str, deformated_key );
2866 deformat_string( package, name, &deformated_name );
2868 keypath = get_keypath( package, hkey_root, deformated_key );
2869 msi_free( deformated_key );
2870 if (delete_key) delete_reg_key( hkey_root, keypath );
2871 else delete_reg_value( hkey_root, keypath, deformated_name );
2872 msi_free( keypath );
2874 uirow = MSI_CreateRecord( 2 );
2875 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2876 MSI_RecordSetStringW( uirow, 2, deformated_name );
2877 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2878 msiobj_release( &uirow->hdr );
2880 msi_free( ui_key_str );
2881 msi_free( deformated_name );
2882 return ERROR_SUCCESS;
2885 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2887 static const WCHAR registry_query[] = {
2888 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2889 '`','R','e','g','i','s','t','r','y','`',0};
2890 static const WCHAR remove_registry_query[] = {
2891 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2892 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2896 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2897 if (rc == ERROR_SUCCESS)
2899 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2900 msiobj_release( &view->hdr );
2901 if (rc != ERROR_SUCCESS)
2904 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2905 if (rc == ERROR_SUCCESS)
2907 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2908 msiobj_release( &view->hdr );
2909 if (rc != ERROR_SUCCESS)
2912 return ERROR_SUCCESS;
2915 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2917 package->script->CurrentlyScripting = TRUE;
2919 return ERROR_SUCCESS;
2923 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2925 static const WCHAR query[]= {
2926 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2927 '`','R','e','g','i','s','t','r','y','`',0};
2929 DWORD total = 0, count = 0;
2931 MSIFEATURE *feature;
2935 TRACE("InstallValidate\n");
2937 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2938 if (rc == ERROR_SUCCESS)
2940 rc = MSI_IterateRecords( view, &count, NULL, package );
2941 msiobj_release( &view->hdr );
2942 if (rc != ERROR_SUCCESS)
2944 total += count * REG_PROGRESS_VALUE;
2946 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2947 total += COMPONENT_PROGRESS_VALUE;
2949 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2950 total += file->FileSize;
2952 msi_ui_progress( package, 0, total, 0, 0 );
2954 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2956 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2957 debugstr_w(feature->Feature), feature->Installed,
2958 feature->ActionRequest, feature->Action);
2960 return ERROR_SUCCESS;
2963 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2965 MSIPACKAGE* package = param;
2966 LPCWSTR cond = NULL;
2967 LPCWSTR message = NULL;
2970 static const WCHAR title[]=
2971 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2973 cond = MSI_RecordGetString(row,1);
2975 r = MSI_EvaluateConditionW(package,cond);
2976 if (r == MSICONDITION_FALSE)
2978 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2981 message = MSI_RecordGetString(row,2);
2982 deformat_string(package,message,&deformated);
2983 MessageBoxW(NULL,deformated,title,MB_OK);
2984 msi_free(deformated);
2987 return ERROR_INSTALL_FAILURE;
2990 return ERROR_SUCCESS;
2993 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2995 static const WCHAR query[] = {
2996 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2997 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3001 TRACE("Checking launch conditions\n");
3003 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3004 if (rc != ERROR_SUCCESS)
3005 return ERROR_SUCCESS;
3007 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3008 msiobj_release(&view->hdr);
3012 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3016 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3018 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3020 static const WCHAR query[] = {
3021 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3022 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3023 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3024 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3025 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3028 LPWSTR deformated, buffer, deformated_name;
3031 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3035 root = MSI_RecordGetInteger(row,2);
3036 key = MSI_RecordGetString(row, 3);
3037 name = MSI_RecordGetString(row, 4);
3038 deformat_string(package, key , &deformated);
3039 deformat_string(package, name, &deformated_name);
3041 len = strlenW(deformated) + 6;
3042 if (deformated_name)
3043 len+=strlenW(deformated_name);
3045 buffer = msi_alloc( len *sizeof(WCHAR));
3047 if (deformated_name)
3048 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3050 sprintfW(buffer,fmt,root,deformated);
3052 msi_free(deformated);
3053 msi_free(deformated_name);
3054 msiobj_release(&row->hdr);
3058 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3060 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3065 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3068 return strdupW( file->TargetPath );
3073 static HKEY openSharedDLLsKey(void)
3076 static const WCHAR path[] =
3077 {'S','o','f','t','w','a','r','e','\\',
3078 'M','i','c','r','o','s','o','f','t','\\',
3079 'W','i','n','d','o','w','s','\\',
3080 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3081 'S','h','a','r','e','d','D','L','L','s',0};
3083 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3087 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3092 DWORD sz = sizeof(count);
3095 hkey = openSharedDLLsKey();
3096 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3097 if (rc != ERROR_SUCCESS)
3103 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3107 hkey = openSharedDLLsKey();
3109 msi_reg_set_val_dword( hkey, path, count );
3111 RegDeleteValueW(hkey,path);
3116 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3118 MSIFEATURE *feature;
3122 /* only refcount DLLs */
3123 if (comp->KeyPath == NULL ||
3125 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3126 comp->Attributes & msidbComponentAttributesODBCDataSource)
3130 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3131 write = (count > 0);
3133 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3137 /* increment counts */
3138 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3142 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3145 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3147 if ( cl->component == comp )
3152 /* decrement counts */
3153 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3157 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3160 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3162 if ( cl->component == comp )
3167 /* ref count all the files in the component */
3172 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3174 if (file->Component == comp)
3175 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3179 /* add a count for permanent */
3180 if (comp->Attributes & msidbComponentAttributesPermanent)
3183 comp->RefCount = count;
3186 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3189 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3193 const WCHAR prefixW[] = {'<','\\',0};
3194 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3195 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3199 strcpyW( keypath, prefixW );
3200 strcatW( keypath, comp->assembly->display_name );
3204 return resolve_keypath( package, comp );
3207 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3209 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3216 squash_guid(package->ProductCode,squished_pc);
3217 msi_set_sourcedir_props(package, FALSE);
3219 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3222 INSTALLSTATE action;
3224 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3225 if (!comp->ComponentId)
3228 squash_guid( comp->ComponentId, squished_cc );
3229 msi_free( comp->FullKeypath );
3230 comp->FullKeypath = build_full_keypath( package, comp );
3232 ACTION_RefCountComponent( package, comp );
3234 if (package->need_rollback) action = comp->Installed;
3235 else action = comp->ActionRequest;
3237 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3238 debugstr_w(comp->Component), debugstr_w(squished_cc),
3239 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3241 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3243 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3244 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3246 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3248 if (rc != ERROR_SUCCESS)
3251 if (comp->Attributes & msidbComponentAttributesPermanent)
3253 static const WCHAR szPermKey[] =
3254 { '0','0','0','0','0','0','0','0','0','0','0','0',
3255 '0','0','0','0','0','0','0','0','0','0','0','0',
3256 '0','0','0','0','0','0','0','0',0 };
3258 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3260 if (action == INSTALLSTATE_LOCAL)
3261 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3267 WCHAR source[MAX_PATH];
3268 WCHAR base[MAX_PATH];
3271 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3272 static const WCHAR query[] = {
3273 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3274 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3275 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3276 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3277 '`','D','i','s','k','I','d','`',0};
3279 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3282 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3283 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3284 ptr2 = strrchrW(source, '\\') + 1;
3285 msiobj_release(&row->hdr);
3287 lstrcpyW(base, package->PackagePath);
3288 ptr = strrchrW(base, '\\');
3291 sourcepath = msi_resolve_file_source(package, file);
3292 ptr = sourcepath + lstrlenW(base);
3293 lstrcpyW(ptr2, ptr);
3294 msi_free(sourcepath);
3296 msi_reg_set_val_str(hkey, squished_pc, source);
3300 else if (action == INSTALLSTATE_ABSENT)
3302 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3303 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3305 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3309 uirow = MSI_CreateRecord(3);
3310 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3311 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3312 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3313 msi_ui_actiondata( package, szProcessComponents, uirow );
3314 msiobj_release( &uirow->hdr );
3316 return ERROR_SUCCESS;
3327 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3328 LPWSTR lpszName, LONG_PTR lParam)
3331 typelib_struct *tl_struct = (typelib_struct*) lParam;
3332 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3336 if (!IS_INTRESOURCE(lpszName))
3338 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3342 sz = strlenW(tl_struct->source)+4;
3343 sz *= sizeof(WCHAR);
3345 if ((INT_PTR)lpszName == 1)
3346 tl_struct->path = strdupW(tl_struct->source);
3349 tl_struct->path = msi_alloc(sz);
3350 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3353 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3354 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3357 msi_free(tl_struct->path);
3358 tl_struct->path = NULL;
3363 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3364 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3366 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3370 msi_free(tl_struct->path);
3371 tl_struct->path = NULL;
3373 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3374 ITypeLib_Release(tl_struct->ptLib);
3379 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3381 MSIPACKAGE* package = param;
3385 typelib_struct tl_struct;
3390 component = MSI_RecordGetString(row,3);
3391 comp = msi_get_loaded_component(package,component);
3393 return ERROR_SUCCESS;
3395 comp->Action = msi_get_component_action( package, comp );
3396 if (comp->Action != INSTALLSTATE_LOCAL)
3398 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3399 return ERROR_SUCCESS;
3402 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3404 TRACE("component has no key path\n");
3405 return ERROR_SUCCESS;
3407 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3409 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3413 guid = MSI_RecordGetString(row,1);
3414 CLSIDFromString( guid, &tl_struct.clsid);
3415 tl_struct.source = strdupW( file->TargetPath );
3416 tl_struct.path = NULL;
3418 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3419 (LONG_PTR)&tl_struct);
3423 LPCWSTR helpid, help_path = NULL;
3426 helpid = MSI_RecordGetString(row,6);
3428 if (helpid) help_path = msi_get_target_folder( package, helpid );
3429 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3432 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3434 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3436 ITypeLib_Release(tl_struct.ptLib);
3437 msi_free(tl_struct.path);
3439 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3441 FreeLibrary(module);
3442 msi_free(tl_struct.source);
3446 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3449 ERR("Failed to load type library: %08x\n", hr);
3450 return ERROR_INSTALL_FAILURE;
3453 ITypeLib_Release(tlib);
3456 return ERROR_SUCCESS;
3459 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3461 static const WCHAR query[] = {
3462 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3463 '`','T','y','p','e','L','i','b','`',0};
3467 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3468 if (rc != ERROR_SUCCESS)
3469 return ERROR_SUCCESS;
3471 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3472 msiobj_release(&view->hdr);
3476 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3478 MSIPACKAGE *package = param;
3479 LPCWSTR component, guid;
3487 component = MSI_RecordGetString( row, 3 );
3488 comp = msi_get_loaded_component( package, component );
3490 return ERROR_SUCCESS;
3492 comp->Action = msi_get_component_action( package, comp );
3493 if (comp->Action != INSTALLSTATE_ABSENT)
3495 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3496 return ERROR_SUCCESS;
3498 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3500 guid = MSI_RecordGetString( row, 1 );
3501 CLSIDFromString( guid, &libid );
3502 version = MSI_RecordGetInteger( row, 4 );
3503 language = MSI_RecordGetInteger( row, 2 );
3506 syskind = SYS_WIN64;
3508 syskind = SYS_WIN32;
3511 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3514 WARN("Failed to unregister typelib: %08x\n", hr);
3517 return ERROR_SUCCESS;
3520 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3522 static const WCHAR query[] = {
3523 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3524 '`','T','y','p','e','L','i','b','`',0};
3528 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3529 if (rc != ERROR_SUCCESS)
3530 return ERROR_SUCCESS;
3532 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3533 msiobj_release( &view->hdr );
3537 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3539 static const WCHAR szlnk[] = {'.','l','n','k',0};
3540 LPCWSTR directory, extension, link_folder;
3541 LPWSTR link_file, filename;
3543 directory = MSI_RecordGetString( row, 2 );
3544 link_folder = msi_get_target_folder( package, directory );
3547 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3550 /* may be needed because of a bug somewhere else */
3551 msi_create_full_path( link_folder );
3553 filename = msi_dup_record_field( row, 3 );
3554 msi_reduce_to_long_filename( filename );
3556 extension = strchrW( filename, '.' );
3557 if (!extension || strcmpiW( extension, szlnk ))
3559 int len = strlenW( filename );
3560 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3561 memcpy( filename + len, szlnk, sizeof(szlnk) );
3563 link_file = msi_build_directory_name( 2, link_folder, filename );
3564 msi_free( filename );
3569 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3571 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3572 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3573 WCHAR *folder, *dest, *path;
3575 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3576 folder = msi_dup_property( package->db, szWindowsFolder );
3579 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3580 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3581 msi_free( appdata );
3583 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3584 msi_create_full_path( dest );
3585 path = msi_build_directory_name( 2, dest, icon_name );
3591 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3593 MSIPACKAGE *package = param;
3594 LPWSTR link_file, deformated, path;
3595 LPCWSTR component, target;
3597 IShellLinkW *sl = NULL;
3598 IPersistFile *pf = NULL;
3601 component = MSI_RecordGetString(row, 4);
3602 comp = msi_get_loaded_component(package, component);
3604 return ERROR_SUCCESS;
3606 comp->Action = msi_get_component_action( package, comp );
3607 if (comp->Action != INSTALLSTATE_LOCAL)
3609 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3610 return ERROR_SUCCESS;
3612 msi_ui_actiondata( package, szCreateShortcuts, row );
3614 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3615 &IID_IShellLinkW, (LPVOID *) &sl );
3619 ERR("CLSID_ShellLink not available\n");
3623 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3626 ERR("QueryInterface(IID_IPersistFile) failed\n");
3630 target = MSI_RecordGetString(row, 5);
3631 if (strchrW(target, '['))
3633 deformat_string( package, target, &path );
3634 TRACE("target path is %s\n", debugstr_w(path));
3635 IShellLinkW_SetPath( sl, path );
3640 FIXME("poorly handled shortcut format, advertised shortcut\n");
3641 IShellLinkW_SetPath(sl,comp->FullKeypath);
3644 if (!MSI_RecordIsNull(row,6))
3646 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3647 deformat_string(package, arguments, &deformated);
3648 IShellLinkW_SetArguments(sl,deformated);
3649 msi_free(deformated);
3652 if (!MSI_RecordIsNull(row,7))
3654 LPCWSTR description = MSI_RecordGetString(row, 7);
3655 IShellLinkW_SetDescription(sl, description);
3658 if (!MSI_RecordIsNull(row,8))
3659 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3661 if (!MSI_RecordIsNull(row,9))
3664 LPCWSTR icon = MSI_RecordGetString(row, 9);
3666 path = msi_build_icon_path(package, icon);
3667 index = MSI_RecordGetInteger(row,10);
3669 /* no value means 0 */
3670 if (index == MSI_NULL_INTEGER)
3673 IShellLinkW_SetIconLocation(sl, path, index);
3677 if (!MSI_RecordIsNull(row,11))
3678 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3680 if (!MSI_RecordIsNull(row,12))
3682 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3683 full_path = msi_get_target_folder( package, wkdir );
3684 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3686 link_file = get_link_file(package, row);
3688 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3689 IPersistFile_Save(pf, link_file, FALSE);
3690 msi_free(link_file);
3694 IPersistFile_Release( pf );
3696 IShellLinkW_Release( sl );
3698 return ERROR_SUCCESS;
3701 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3703 static const WCHAR query[] = {
3704 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3705 '`','S','h','o','r','t','c','u','t','`',0};
3710 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3711 if (rc != ERROR_SUCCESS)
3712 return ERROR_SUCCESS;
3714 res = CoInitialize( NULL );
3716 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3717 msiobj_release(&view->hdr);
3719 if (SUCCEEDED(res)) CoUninitialize();
3723 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3725 MSIPACKAGE *package = param;
3730 component = MSI_RecordGetString( row, 4 );
3731 comp = msi_get_loaded_component( package, component );
3733 return ERROR_SUCCESS;
3735 comp->Action = msi_get_component_action( package, comp );
3736 if (comp->Action != INSTALLSTATE_ABSENT)
3738 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3739 return ERROR_SUCCESS;
3741 msi_ui_actiondata( package, szRemoveShortcuts, row );
3743 link_file = get_link_file( package, row );
3745 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3746 if (!DeleteFileW( link_file ))
3748 WARN("Failed to remove shortcut file %u\n", GetLastError());
3750 msi_free( link_file );
3752 return ERROR_SUCCESS;
3755 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3757 static const WCHAR query[] = {
3758 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3759 '`','S','h','o','r','t','c','u','t','`',0};
3763 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3764 if (rc != ERROR_SUCCESS)
3765 return ERROR_SUCCESS;
3767 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3768 msiobj_release( &view->hdr );
3772 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3774 MSIPACKAGE* package = param;
3782 FileName = MSI_RecordGetString(row,1);
3785 ERR("Unable to get FileName\n");
3786 return ERROR_SUCCESS;
3789 FilePath = msi_build_icon_path(package, FileName);
3791 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3793 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3794 FILE_ATTRIBUTE_NORMAL, NULL);
3796 if (the_file == INVALID_HANDLE_VALUE)
3798 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3800 return ERROR_SUCCESS;
3807 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3808 if (rc != ERROR_SUCCESS)
3810 ERR("Failed to get stream\n");
3811 CloseHandle(the_file);
3812 DeleteFileW(FilePath);
3815 WriteFile(the_file,buffer,sz,&write,NULL);
3816 } while (sz == 1024);
3819 CloseHandle(the_file);
3821 return ERROR_SUCCESS;
3824 static UINT msi_publish_icons(MSIPACKAGE *package)
3826 static const WCHAR query[]= {
3827 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3828 '`','I','c','o','n','`',0};
3832 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3833 if (r == ERROR_SUCCESS)
3835 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3836 msiobj_release(&view->hdr);
3837 if (r != ERROR_SUCCESS)
3840 return ERROR_SUCCESS;
3843 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3849 MSISOURCELISTINFO *info;
3851 r = RegCreateKeyW(hkey, szSourceList, &source);
3852 if (r != ERROR_SUCCESS)
3855 RegCloseKey(source);
3857 buffer = strrchrW(package->PackagePath, '\\') + 1;
3858 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3859 package->Context, MSICODE_PRODUCT,
3860 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3861 if (r != ERROR_SUCCESS)
3864 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3865 package->Context, MSICODE_PRODUCT,
3866 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3867 if (r != ERROR_SUCCESS)
3870 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3871 package->Context, MSICODE_PRODUCT,
3872 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3873 if (r != ERROR_SUCCESS)
3876 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3878 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3879 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3880 info->options, info->value);
3882 MsiSourceListSetInfoW(package->ProductCode, NULL,
3883 info->context, info->options,
3884 info->property, info->value);
3887 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3889 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3890 disk->context, disk->options,
3891 disk->disk_id, disk->volume_label, disk->disk_prompt);
3894 return ERROR_SUCCESS;
3897 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3899 MSIHANDLE hdb, suminfo;
3900 WCHAR guids[MAX_PATH];
3901 WCHAR packcode[SQUISH_GUID_SIZE];
3908 static const WCHAR szARPProductIcon[] =
3909 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3910 static const WCHAR szAssignment[] =
3911 {'A','s','s','i','g','n','m','e','n','t',0};
3912 static const WCHAR szAdvertiseFlags[] =
3913 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3914 static const WCHAR szClients[] =
3915 {'C','l','i','e','n','t','s',0};
3916 static const WCHAR szColon[] = {':',0};
3918 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3919 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3922 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3923 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3926 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3928 buffer = msi_dup_property(package->db, szARPProductIcon);
3931 LPWSTR path = msi_build_icon_path(package, buffer);
3932 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3937 buffer = msi_dup_property(package->db, szProductVersion);
3940 DWORD verdword = msi_version_str_to_dword(buffer);
3941 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3945 msi_reg_set_val_dword(hkey, szAssignment, 0);
3946 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3947 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3948 msi_reg_set_val_str(hkey, szClients, szColon);
3950 hdb = alloc_msihandle(&package->db->hdr);
3952 return ERROR_NOT_ENOUGH_MEMORY;
3954 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3955 MsiCloseHandle(hdb);
3956 if (r != ERROR_SUCCESS)
3960 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3961 NULL, guids, &size);
3962 if (r != ERROR_SUCCESS)
3965 ptr = strchrW(guids, ';');
3967 squash_guid(guids, packcode);
3968 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3971 MsiCloseHandle(suminfo);
3972 return ERROR_SUCCESS;
3975 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3980 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3982 upgrade = msi_dup_property(package->db, szUpgradeCode);
3984 return ERROR_SUCCESS;
3986 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3987 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3989 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3991 if (r != ERROR_SUCCESS)
3993 WARN("failed to open upgrade code key\n");
3995 return ERROR_SUCCESS;
3997 squash_guid(package->ProductCode, squashed_pc);
3998 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4001 return ERROR_SUCCESS;
4004 static BOOL msi_check_publish(MSIPACKAGE *package)
4006 MSIFEATURE *feature;
4008 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4010 feature->Action = msi_get_feature_action( package, feature );
4011 if (feature->Action == INSTALLSTATE_LOCAL)
4018 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4020 MSIFEATURE *feature;
4022 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4024 feature->Action = msi_get_feature_action( package, feature );
4025 if (feature->Action != INSTALLSTATE_ABSENT)
4032 static UINT msi_publish_patches( MSIPACKAGE *package )
4034 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4035 WCHAR patch_squashed[GUID_SIZE];
4036 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4038 MSIPATCHINFO *patch;
4040 WCHAR *p, *all_patches = NULL;
4043 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4044 if (r != ERROR_SUCCESS)
4045 return ERROR_FUNCTION_FAILED;
4047 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4048 if (res != ERROR_SUCCESS)
4050 r = ERROR_FUNCTION_FAILED;
4054 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4055 if (r != ERROR_SUCCESS)
4058 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4060 squash_guid( patch->patchcode, patch_squashed );
4061 len += strlenW( patch_squashed ) + 1;
4064 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4068 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4072 squash_guid( patch->patchcode, p );
4073 p += strlenW( p ) + 1;
4075 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4076 (const BYTE *)patch->transforms,
4077 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4078 if (res != ERROR_SUCCESS)
4081 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4082 if (r != ERROR_SUCCESS)
4085 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4086 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4087 RegCloseKey( patch_key );
4088 if (res != ERROR_SUCCESS)
4091 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4093 res = GetLastError();
4094 ERR("Unable to copy patch package %d\n", res);
4097 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4098 if (res != ERROR_SUCCESS)
4101 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4102 RegCloseKey( patch_key );
4103 if (res != ERROR_SUCCESS)
4107 all_patches[len] = 0;
4108 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4109 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4110 if (res != ERROR_SUCCESS)
4113 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4114 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4115 if (res != ERROR_SUCCESS)
4116 r = ERROR_FUNCTION_FAILED;
4119 RegCloseKey( product_patches_key );
4120 RegCloseKey( patches_key );
4121 RegCloseKey( product_key );
4122 msi_free( all_patches );
4126 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4129 HKEY hukey = NULL, hudkey = NULL;
4132 if (!list_empty(&package->patches))
4134 rc = msi_publish_patches(package);
4135 if (rc != ERROR_SUCCESS)
4139 /* FIXME: also need to publish if the product is in advertise mode */
4140 if (!msi_check_publish(package))
4141 return ERROR_SUCCESS;
4143 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4145 if (rc != ERROR_SUCCESS)
4148 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4149 NULL, &hudkey, TRUE);
4150 if (rc != ERROR_SUCCESS)
4153 rc = msi_publish_upgrade_code(package);
4154 if (rc != ERROR_SUCCESS)
4157 rc = msi_publish_product_properties(package, hukey);
4158 if (rc != ERROR_SUCCESS)
4161 rc = msi_publish_sourcelist(package, hukey);
4162 if (rc != ERROR_SUCCESS)
4165 rc = msi_publish_icons(package);
4168 uirow = MSI_CreateRecord( 1 );
4169 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4170 msi_ui_actiondata( package, szPublishProduct, uirow );
4171 msiobj_release( &uirow->hdr );
4174 RegCloseKey(hudkey);
4178 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4180 WCHAR *filename, *ptr, *folder, *ret;
4181 const WCHAR *dirprop;
4183 filename = msi_dup_record_field( row, 2 );
4184 if (filename && (ptr = strchrW( filename, '|' )))
4189 dirprop = MSI_RecordGetString( row, 3 );
4192 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4193 if (!folder) folder = msi_dup_property( package->db, dirprop );
4196 folder = msi_dup_property( package->db, szWindowsFolder );
4200 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4201 msi_free( filename );
4205 ret = msi_build_directory_name( 2, folder, ptr );
4207 msi_free( filename );
4212 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4214 MSIPACKAGE *package = param;
4215 LPCWSTR component, section, key, value, identifier;
4216 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4221 component = MSI_RecordGetString(row, 8);
4222 comp = msi_get_loaded_component(package,component);
4224 return ERROR_SUCCESS;
4226 comp->Action = msi_get_component_action( package, comp );
4227 if (comp->Action != INSTALLSTATE_LOCAL)
4229 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4230 return ERROR_SUCCESS;
4233 identifier = MSI_RecordGetString(row,1);
4234 section = MSI_RecordGetString(row,4);
4235 key = MSI_RecordGetString(row,5);
4236 value = MSI_RecordGetString(row,6);
4237 action = MSI_RecordGetInteger(row,7);
4239 deformat_string(package,section,&deformated_section);
4240 deformat_string(package,key,&deformated_key);
4241 deformat_string(package,value,&deformated_value);
4243 fullname = get_ini_file_name(package, row);
4247 TRACE("Adding value %s to section %s in %s\n",
4248 debugstr_w(deformated_key), debugstr_w(deformated_section),
4249 debugstr_w(fullname));
4250 WritePrivateProfileStringW(deformated_section, deformated_key,
4251 deformated_value, fullname);
4253 else if (action == 1)
4256 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4257 returned, 10, fullname);
4258 if (returned[0] == 0)
4260 TRACE("Adding value %s to section %s in %s\n",
4261 debugstr_w(deformated_key), debugstr_w(deformated_section),
4262 debugstr_w(fullname));
4264 WritePrivateProfileStringW(deformated_section, deformated_key,
4265 deformated_value, fullname);
4268 else if (action == 3)
4269 FIXME("Append to existing section not yet implemented\n");
4271 uirow = MSI_CreateRecord(4);
4272 MSI_RecordSetStringW(uirow,1,identifier);
4273 MSI_RecordSetStringW(uirow,2,deformated_section);
4274 MSI_RecordSetStringW(uirow,3,deformated_key);
4275 MSI_RecordSetStringW(uirow,4,deformated_value);
4276 msi_ui_actiondata( package, szWriteIniValues, uirow );
4277 msiobj_release( &uirow->hdr );
4280 msi_free(deformated_key);
4281 msi_free(deformated_value);
4282 msi_free(deformated_section);
4283 return ERROR_SUCCESS;
4286 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4288 static const WCHAR query[] = {
4289 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4290 '`','I','n','i','F','i','l','e','`',0};
4294 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4295 if (rc != ERROR_SUCCESS)
4296 return ERROR_SUCCESS;
4298 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4299 msiobj_release(&view->hdr);
4303 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4305 MSIPACKAGE *package = param;
4306 LPCWSTR component, section, key, value, identifier;
4307 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4312 component = MSI_RecordGetString( row, 8 );
4313 comp = msi_get_loaded_component( package, component );
4315 return ERROR_SUCCESS;
4317 comp->Action = msi_get_component_action( package, comp );
4318 if (comp->Action != INSTALLSTATE_ABSENT)
4320 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4321 return ERROR_SUCCESS;
4324 identifier = MSI_RecordGetString( row, 1 );
4325 section = MSI_RecordGetString( row, 4 );
4326 key = MSI_RecordGetString( row, 5 );
4327 value = MSI_RecordGetString( row, 6 );
4328 action = MSI_RecordGetInteger( row, 7 );
4330 deformat_string( package, section, &deformated_section );
4331 deformat_string( package, key, &deformated_key );
4332 deformat_string( package, value, &deformated_value );
4334 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4336 filename = get_ini_file_name( package, row );
4338 TRACE("Removing key %s from section %s in %s\n",
4339 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4341 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4343 WARN("Unable to remove key %u\n", GetLastError());
4345 msi_free( filename );
4348 FIXME("Unsupported action %d\n", action);
4351 uirow = MSI_CreateRecord( 4 );
4352 MSI_RecordSetStringW( uirow, 1, identifier );
4353 MSI_RecordSetStringW( uirow, 2, deformated_section );
4354 MSI_RecordSetStringW( uirow, 3, deformated_key );
4355 MSI_RecordSetStringW( uirow, 4, deformated_value );
4356 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4357 msiobj_release( &uirow->hdr );
4359 msi_free( deformated_key );
4360 msi_free( deformated_value );
4361 msi_free( deformated_section );
4362 return ERROR_SUCCESS;
4365 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4367 MSIPACKAGE *package = param;
4368 LPCWSTR component, section, key, value, identifier;
4369 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4374 component = MSI_RecordGetString( row, 8 );
4375 comp = msi_get_loaded_component( package, component );
4377 return ERROR_SUCCESS;
4379 comp->Action = msi_get_component_action( package, comp );
4380 if (comp->Action != INSTALLSTATE_LOCAL)
4382 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4383 return ERROR_SUCCESS;
4386 identifier = MSI_RecordGetString( row, 1 );
4387 section = MSI_RecordGetString( row, 4 );
4388 key = MSI_RecordGetString( row, 5 );
4389 value = MSI_RecordGetString( row, 6 );
4390 action = MSI_RecordGetInteger( row, 7 );
4392 deformat_string( package, section, &deformated_section );
4393 deformat_string( package, key, &deformated_key );
4394 deformat_string( package, value, &deformated_value );
4396 if (action == msidbIniFileActionRemoveLine)
4398 filename = get_ini_file_name( package, row );
4400 TRACE("Removing key %s from section %s in %s\n",
4401 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4403 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4405 WARN("Unable to remove key %u\n", GetLastError());
4407 msi_free( filename );
4410 FIXME("Unsupported action %d\n", action);
4412 uirow = MSI_CreateRecord( 4 );
4413 MSI_RecordSetStringW( uirow, 1, identifier );
4414 MSI_RecordSetStringW( uirow, 2, deformated_section );
4415 MSI_RecordSetStringW( uirow, 3, deformated_key );
4416 MSI_RecordSetStringW( uirow, 4, deformated_value );
4417 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4418 msiobj_release( &uirow->hdr );
4420 msi_free( deformated_key );
4421 msi_free( deformated_value );
4422 msi_free( deformated_section );
4423 return ERROR_SUCCESS;
4426 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4428 static const WCHAR query[] = {
4429 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4430 '`','I','n','i','F','i','l','e','`',0};
4431 static const WCHAR remove_query[] = {
4432 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4433 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4437 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4438 if (rc == ERROR_SUCCESS)
4440 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4441 msiobj_release( &view->hdr );
4442 if (rc != ERROR_SUCCESS)
4445 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4446 if (rc == ERROR_SUCCESS)
4448 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4449 msiobj_release( &view->hdr );
4450 if (rc != ERROR_SUCCESS)
4453 return ERROR_SUCCESS;
4456 static void register_dll( const WCHAR *dll, BOOL unregister )
4460 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4463 HRESULT (WINAPI *func_ptr)( void );
4464 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4466 func_ptr = (void *)GetProcAddress( hmod, func );
4469 HRESULT hr = func_ptr();
4471 WARN("failed to register dll 0x%08x\n", hr);
4474 WARN("entry point %s not found\n", func);
4475 FreeLibrary( hmod );
4478 WARN("failed to load library %u\n", GetLastError());
4481 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4483 MSIPACKAGE *package = param;
4488 filename = MSI_RecordGetString( row, 1 );
4489 file = msi_get_loaded_file( package, filename );
4492 WARN("unable to find file %s\n", debugstr_w(filename));
4493 return ERROR_SUCCESS;
4495 file->Component->Action = msi_get_component_action( package, file->Component );
4496 if (file->Component->Action != INSTALLSTATE_LOCAL)
4498 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4499 return ERROR_SUCCESS;
4502 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4503 register_dll( file->TargetPath, FALSE );
4505 uirow = MSI_CreateRecord( 2 );
4506 MSI_RecordSetStringW( uirow, 1, file->File );
4507 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4508 msi_ui_actiondata( package, szSelfRegModules, uirow );
4509 msiobj_release( &uirow->hdr );
4511 return ERROR_SUCCESS;
4514 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4516 static const WCHAR query[] = {
4517 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4518 '`','S','e','l','f','R','e','g','`',0};
4522 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4523 if (rc != ERROR_SUCCESS)
4524 return ERROR_SUCCESS;
4526 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4527 msiobj_release(&view->hdr);
4531 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4533 MSIPACKAGE *package = param;
4538 filename = MSI_RecordGetString( row, 1 );
4539 file = msi_get_loaded_file( package, filename );
4542 WARN("unable to find file %s\n", debugstr_w(filename));
4543 return ERROR_SUCCESS;
4545 file->Component->Action = msi_get_component_action( package, file->Component );
4546 if (file->Component->Action != INSTALLSTATE_ABSENT)
4548 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4549 return ERROR_SUCCESS;
4552 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4553 register_dll( file->TargetPath, TRUE );
4555 uirow = MSI_CreateRecord( 2 );
4556 MSI_RecordSetStringW( uirow, 1, file->File );
4557 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4558 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4559 msiobj_release( &uirow->hdr );
4561 return ERROR_SUCCESS;
4564 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4566 static const WCHAR query[] = {
4567 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4568 '`','S','e','l','f','R','e','g','`',0};
4572 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4573 if (rc != ERROR_SUCCESS)
4574 return ERROR_SUCCESS;
4576 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4577 msiobj_release( &view->hdr );
4581 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4583 MSIFEATURE *feature;
4585 HKEY hkey = NULL, userdata = NULL;
4587 if (!msi_check_publish(package))
4588 return ERROR_SUCCESS;
4590 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4592 if (rc != ERROR_SUCCESS)
4595 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4597 if (rc != ERROR_SUCCESS)
4600 /* here the guids are base 85 encoded */
4601 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4607 BOOL absent = FALSE;
4610 if (feature->Action != INSTALLSTATE_LOCAL &&
4611 feature->Action != INSTALLSTATE_SOURCE &&
4612 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4615 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4619 if (feature->Feature_Parent)
4620 size += strlenW( feature->Feature_Parent )+2;
4622 data = msi_alloc(size * sizeof(WCHAR));
4625 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4627 MSICOMPONENT* component = cl->component;
4631 if (component->ComponentId)
4633 TRACE("From %s\n",debugstr_w(component->ComponentId));
4634 CLSIDFromString(component->ComponentId, &clsid);
4635 encode_base85_guid(&clsid,buf);
4636 TRACE("to %s\n",debugstr_w(buf));
4641 if (feature->Feature_Parent)
4643 static const WCHAR sep[] = {'\2',0};
4645 strcatW(data,feature->Feature_Parent);
4648 msi_reg_set_val_str( userdata, feature->Feature, data );
4652 if (feature->Feature_Parent)
4653 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4656 size += sizeof(WCHAR);
4657 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4658 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4662 size += 2*sizeof(WCHAR);
4663 data = msi_alloc(size);
4666 if (feature->Feature_Parent)
4667 strcpyW( &data[1], feature->Feature_Parent );
4668 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4674 uirow = MSI_CreateRecord( 1 );
4675 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4676 msi_ui_actiondata( package, szPublishFeatures, uirow );
4677 msiobj_release( &uirow->hdr );
4678 /* FIXME: call msi_ui_progress? */
4683 RegCloseKey(userdata);
4687 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4693 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4695 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4697 if (r == ERROR_SUCCESS)
4699 RegDeleteValueW(hkey, feature->Feature);
4703 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4705 if (r == ERROR_SUCCESS)
4707 RegDeleteValueW(hkey, feature->Feature);
4711 uirow = MSI_CreateRecord( 1 );
4712 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4713 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4714 msiobj_release( &uirow->hdr );
4716 return ERROR_SUCCESS;
4719 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4721 MSIFEATURE *feature;
4723 if (!msi_check_unpublish(package))
4724 return ERROR_SUCCESS;
4726 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4728 msi_unpublish_feature(package, feature);
4731 return ERROR_SUCCESS;
4734 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4738 WCHAR date[9], *val, *buffer;
4739 const WCHAR *prop, *key;
4741 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4742 static const WCHAR modpath_fmt[] =
4743 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4744 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4745 static const WCHAR szModifyPath[] =
4746 {'M','o','d','i','f','y','P','a','t','h',0};
4747 static const WCHAR szUninstallString[] =
4748 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4749 static const WCHAR szEstimatedSize[] =
4750 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4751 static const WCHAR szDisplayVersion[] =
4752 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4753 static const WCHAR szInstallSource[] =
4754 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4755 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4756 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4757 static const WCHAR szAuthorizedCDFPrefix[] =
4758 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4759 static const WCHAR szARPCONTACT[] =
4760 {'A','R','P','C','O','N','T','A','C','T',0};
4761 static const WCHAR szContact[] =
4762 {'C','o','n','t','a','c','t',0};
4763 static const WCHAR szARPCOMMENTS[] =
4764 {'A','R','P','C','O','M','M','E','N','T','S',0};
4765 static const WCHAR szComments[] =
4766 {'C','o','m','m','e','n','t','s',0};
4767 static const WCHAR szProductName[] =
4768 {'P','r','o','d','u','c','t','N','a','m','e',0};
4769 static const WCHAR szDisplayName[] =
4770 {'D','i','s','p','l','a','y','N','a','m','e',0};
4771 static const WCHAR szARPHELPLINK[] =
4772 {'A','R','P','H','E','L','P','L','I','N','K',0};
4773 static const WCHAR szHelpLink[] =
4774 {'H','e','l','p','L','i','n','k',0};
4775 static const WCHAR szARPHELPTELEPHONE[] =
4776 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4777 static const WCHAR szHelpTelephone[] =
4778 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4779 static const WCHAR szARPINSTALLLOCATION[] =
4780 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4781 static const WCHAR szInstallLocation[] =
4782 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4783 static const WCHAR szManufacturer[] =
4784 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4785 static const WCHAR szPublisher[] =
4786 {'P','u','b','l','i','s','h','e','r',0};
4787 static const WCHAR szARPREADME[] =
4788 {'A','R','P','R','E','A','D','M','E',0};
4789 static const WCHAR szReadme[] =
4790 {'R','e','a','d','M','e',0};
4791 static const WCHAR szARPSIZE[] =
4792 {'A','R','P','S','I','Z','E',0};
4793 static const WCHAR szSize[] =
4794 {'S','i','z','e',0};
4795 static const WCHAR szARPURLINFOABOUT[] =
4796 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4797 static const WCHAR szURLInfoAbout[] =
4798 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4799 static const WCHAR szARPURLUPDATEINFO[] =
4800 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4801 static const WCHAR szURLUpdateInfo[] =
4802 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4803 static const WCHAR szARPSYSTEMCOMPONENT[] =
4804 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4805 static const WCHAR szSystemComponent[] =
4806 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4808 static const WCHAR *propval[] = {
4809 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4810 szARPCONTACT, szContact,
4811 szARPCOMMENTS, szComments,
4812 szProductName, szDisplayName,
4813 szARPHELPLINK, szHelpLink,
4814 szARPHELPTELEPHONE, szHelpTelephone,
4815 szARPINSTALLLOCATION, szInstallLocation,
4816 szSourceDir, szInstallSource,
4817 szManufacturer, szPublisher,
4818 szARPREADME, szReadme,
4820 szARPURLINFOABOUT, szURLInfoAbout,
4821 szARPURLUPDATEINFO, szURLUpdateInfo,
4824 const WCHAR **p = propval;
4830 val = msi_dup_property(package->db, prop);
4831 msi_reg_set_val_str(hkey, key, val);
4835 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4836 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4838 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4840 size = deformat_string(package, modpath_fmt, &buffer);
4841 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4842 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4845 /* FIXME: Write real Estimated Size when we have it */
4846 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4848 GetLocalTime(&systime);
4849 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4850 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4852 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4853 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4855 buffer = msi_dup_property(package->db, szProductVersion);
4856 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4859 DWORD verdword = msi_version_str_to_dword(buffer);
4861 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4862 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4863 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4867 return ERROR_SUCCESS;
4870 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4872 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4874 LPWSTR upgrade_code;
4875 HKEY hkey, props, upgrade_key;
4878 /* FIXME: also need to publish if the product is in advertise mode */
4879 if (!msi_check_publish(package))
4880 return ERROR_SUCCESS;
4882 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4883 if (rc != ERROR_SUCCESS)
4886 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4887 if (rc != ERROR_SUCCESS)
4890 rc = msi_publish_install_properties(package, hkey);
4891 if (rc != ERROR_SUCCESS)
4894 rc = msi_publish_install_properties(package, props);
4895 if (rc != ERROR_SUCCESS)
4898 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4901 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4902 if (rc == ERROR_SUCCESS)
4904 squash_guid( package->ProductCode, squashed_pc );
4905 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4906 RegCloseKey( upgrade_key );
4908 msi_free( upgrade_code );
4910 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4911 package->delete_on_close = FALSE;
4914 uirow = MSI_CreateRecord( 1 );
4915 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4916 msi_ui_actiondata( package, szRegisterProduct, uirow );
4917 msiobj_release( &uirow->hdr );
4920 return ERROR_SUCCESS;
4923 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4925 return execute_script(package, SCRIPT_INSTALL);
4928 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4930 MSIPACKAGE *package = param;
4931 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4932 WCHAR *p, *icon_path;
4934 if (!icon) return ERROR_SUCCESS;
4935 if ((icon_path = msi_build_icon_path( package, icon )))
4937 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4938 DeleteFileW( icon_path );
4939 if ((p = strrchrW( icon_path, '\\' )))
4942 RemoveDirectoryW( icon_path );
4944 msi_free( icon_path );
4946 return ERROR_SUCCESS;
4949 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4951 static const WCHAR query[]= {
4952 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4956 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4957 if (r == ERROR_SUCCESS)
4959 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4960 msiobj_release( &view->hdr );
4961 if (r != ERROR_SUCCESS)
4964 return ERROR_SUCCESS;
4967 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4969 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4970 WCHAR *upgrade, **features;
4971 BOOL full_uninstall = TRUE;
4972 MSIFEATURE *feature;
4973 MSIPATCHINFO *patch;
4976 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4978 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4980 features = msi_split_string( remove, ',' );
4981 for (i = 0; features && features[i]; i++)
4983 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4987 if (!full_uninstall)
4988 return ERROR_SUCCESS;
4990 MSIREG_DeleteProductKey(package->ProductCode);
4991 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4992 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4994 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4995 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4996 MSIREG_DeleteUserProductKey(package->ProductCode);
4997 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4999 upgrade = msi_dup_property(package->db, szUpgradeCode);
5002 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5003 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5007 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5009 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5010 if (!strcmpW( package->ProductCode, patch->products ))
5012 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5013 patch->delete_on_close = TRUE;
5015 /* FIXME: remove local patch package if this is the last product */
5017 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5018 package->delete_on_close = TRUE;
5020 msi_unpublish_icons( package );
5021 return ERROR_SUCCESS;
5024 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5029 /* turn off scheduling */
5030 package->script->CurrentlyScripting= FALSE;
5032 /* first do the same as an InstallExecute */
5033 rc = ACTION_InstallExecute(package);
5034 if (rc != ERROR_SUCCESS)
5037 /* then handle commit actions */
5038 rc = execute_script(package, SCRIPT_COMMIT);
5039 if (rc != ERROR_SUCCESS)
5042 remove = msi_dup_property(package->db, szRemove);
5043 rc = msi_unpublish_product(package, remove);
5048 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5050 static const WCHAR RunOnce[] = {
5051 'S','o','f','t','w','a','r','e','\\',
5052 'M','i','c','r','o','s','o','f','t','\\',
5053 'W','i','n','d','o','w','s','\\',
5054 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5055 'R','u','n','O','n','c','e',0};
5056 static const WCHAR InstallRunOnce[] = {
5057 'S','o','f','t','w','a','r','e','\\',
5058 'M','i','c','r','o','s','o','f','t','\\',
5059 'W','i','n','d','o','w','s','\\',
5060 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5061 'I','n','s','t','a','l','l','e','r','\\',
5062 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5064 static const WCHAR msiexec_fmt[] = {
5066 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5067 '\"','%','s','\"',0};
5068 static const WCHAR install_fmt[] = {
5069 '/','I',' ','\"','%','s','\"',' ',
5070 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5071 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5072 WCHAR buffer[256], sysdir[MAX_PATH];
5074 WCHAR squished_pc[100];
5076 squash_guid(package->ProductCode,squished_pc);
5078 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5079 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5080 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5083 msi_reg_set_val_str( hkey, squished_pc, buffer );
5086 TRACE("Reboot command %s\n",debugstr_w(buffer));
5088 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5089 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5091 msi_reg_set_val_str( hkey, squished_pc, buffer );
5094 return ERROR_INSTALL_SUSPEND;
5097 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5099 static const WCHAR query[] =
5100 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5101 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5102 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5103 MSIRECORD *rec, *row;
5109 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5111 rec = MSI_CreateRecord( count + 2 );
5112 str = MSI_RecordGetString( row, 1 );
5113 MSI_RecordSetStringW( rec, 0, str );
5114 msiobj_release( &row->hdr );
5115 MSI_RecordSetInteger( rec, 1, error );
5117 va_start( va, count );
5118 for (i = 0; i < count; i++)
5120 str = va_arg( va, const WCHAR *);
5121 MSI_RecordSetStringW( rec, i + 2, str );
5125 MSI_FormatRecordW( package, rec, NULL, &size );
5127 data = msi_alloc( size * sizeof(WCHAR) );
5128 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5130 msiobj_release( &rec->hdr );
5134 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5140 * We are currently doing what should be done here in the top level Install
5141 * however for Administrative and uninstalls this step will be needed
5143 if (!package->PackagePath)
5144 return ERROR_SUCCESS;
5146 msi_set_sourcedir_props(package, TRUE);
5148 attrib = GetFileAttributesW(package->db->path);
5149 if (attrib == INVALID_FILE_ATTRIBUTES)
5154 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5155 package->Context, MSICODE_PRODUCT,
5156 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5157 if (rc == ERROR_MORE_DATA)
5159 prompt = msi_alloc(size * sizeof(WCHAR));
5160 MsiSourceListGetInfoW(package->ProductCode, NULL,
5161 package->Context, MSICODE_PRODUCT,
5162 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5165 prompt = strdupW(package->db->path);
5167 msg = msi_build_error_string(package, 1302, 1, prompt);
5169 while(attrib == INVALID_FILE_ATTRIBUTES)
5171 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5175 return ERROR_INSTALL_USEREXIT;
5177 attrib = GetFileAttributesW(package->db->path);
5183 return ERROR_SUCCESS;
5188 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5191 LPWSTR buffer, productid = NULL;
5192 UINT i, rc = ERROR_SUCCESS;
5195 static const WCHAR szPropKeys[][80] =
5197 {'P','r','o','d','u','c','t','I','D',0},
5198 {'U','S','E','R','N','A','M','E',0},
5199 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5203 static const WCHAR szRegKeys[][80] =
5205 {'P','r','o','d','u','c','t','I','D',0},
5206 {'R','e','g','O','w','n','e','r',0},
5207 {'R','e','g','C','o','m','p','a','n','y',0},
5211 if (msi_check_unpublish(package))
5213 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5217 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5221 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5223 if (rc != ERROR_SUCCESS)
5226 for( i = 0; szPropKeys[i][0]; i++ )
5228 buffer = msi_dup_property( package->db, szPropKeys[i] );
5229 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5234 uirow = MSI_CreateRecord( 1 );
5235 MSI_RecordSetStringW( uirow, 1, productid );
5236 msi_ui_actiondata( package, szRegisterUser, uirow );
5237 msiobj_release( &uirow->hdr );
5239 msi_free(productid);
5245 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5249 package->script->InWhatSequence |= SEQUENCE_EXEC;
5250 rc = ACTION_ProcessExecSequence(package,FALSE);
5254 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5256 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5257 WCHAR productid_85[21], component_85[21], *ret;
5261 /* > is used if there is a component GUID and < if not. */
5263 productid_85[0] = 0;
5264 component_85[0] = 0;
5265 CLSIDFromString( package->ProductCode, &clsid );
5267 encode_base85_guid( &clsid, productid_85 );
5270 CLSIDFromString( component->ComponentId, &clsid );
5271 encode_base85_guid( &clsid, component_85 );
5274 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5275 debugstr_w(component_85));
5277 sz = 20 + strlenW( feature ) + 20 + 3;
5278 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5279 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5283 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5285 MSIPACKAGE *package = param;
5286 LPCWSTR compgroupid, component, feature, qualifier, text;
5287 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5296 feature = MSI_RecordGetString(rec, 5);
5297 feat = msi_get_loaded_feature(package, feature);
5299 return ERROR_SUCCESS;
5301 feat->Action = msi_get_feature_action( package, feat );
5302 if (feat->Action != INSTALLSTATE_LOCAL &&
5303 feat->Action != INSTALLSTATE_SOURCE &&
5304 feat->Action != INSTALLSTATE_ADVERTISED)
5306 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5307 return ERROR_SUCCESS;
5310 component = MSI_RecordGetString(rec, 3);
5311 comp = msi_get_loaded_component(package, component);
5313 return ERROR_SUCCESS;
5315 compgroupid = MSI_RecordGetString(rec,1);
5316 qualifier = MSI_RecordGetString(rec,2);
5318 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5319 if (rc != ERROR_SUCCESS)
5322 advertise = msi_create_component_advertise_string( package, comp, feature );
5323 text = MSI_RecordGetString( rec, 4 );
5326 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5327 strcpyW( p, advertise );
5329 msi_free( advertise );
5332 existing = msi_reg_get_val_str( hkey, qualifier );
5334 sz = strlenW( advertise ) + 1;
5337 for (p = existing; *p; p += len)
5339 len = strlenW( p ) + 1;
5340 if (strcmpW( advertise, p )) sz += len;
5343 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5345 rc = ERROR_OUTOFMEMORY;
5351 for (p = existing; *p; p += len)
5353 len = strlenW( p ) + 1;
5354 if (strcmpW( advertise, p ))
5356 memcpy( q, p, len * sizeof(WCHAR) );
5361 strcpyW( q, advertise );
5362 q[strlenW( q ) + 1] = 0;
5364 msi_reg_set_val_multi_str( hkey, qualifier, output );
5369 msi_free( advertise );
5370 msi_free( existing );
5373 uirow = MSI_CreateRecord( 2 );
5374 MSI_RecordSetStringW( uirow, 1, compgroupid );
5375 MSI_RecordSetStringW( uirow, 2, qualifier);
5376 msi_ui_actiondata( package, szPublishComponents, uirow );
5377 msiobj_release( &uirow->hdr );
5378 /* FIXME: call ui_progress? */
5384 * At present I am ignorning the advertised components part of this and only
5385 * focusing on the qualified component sets
5387 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5389 static const WCHAR query[] = {
5390 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5391 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5395 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5396 if (rc != ERROR_SUCCESS)
5397 return ERROR_SUCCESS;
5399 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5400 msiobj_release(&view->hdr);
5404 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5406 static const WCHAR szInstallerComponents[] = {
5407 'S','o','f','t','w','a','r','e','\\',
5408 'M','i','c','r','o','s','o','f','t','\\',
5409 'I','n','s','t','a','l','l','e','r','\\',
5410 'C','o','m','p','o','n','e','n','t','s','\\',0};
5412 MSIPACKAGE *package = param;
5413 LPCWSTR compgroupid, component, feature, qualifier;
5417 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5420 feature = MSI_RecordGetString( rec, 5 );
5421 feat = msi_get_loaded_feature( package, feature );
5423 return ERROR_SUCCESS;
5425 feat->Action = msi_get_feature_action( package, feat );
5426 if (feat->Action != INSTALLSTATE_ABSENT)
5428 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5429 return ERROR_SUCCESS;
5432 component = MSI_RecordGetString( rec, 3 );
5433 comp = msi_get_loaded_component( package, component );
5435 return ERROR_SUCCESS;
5437 compgroupid = MSI_RecordGetString( rec, 1 );
5438 qualifier = MSI_RecordGetString( rec, 2 );
5440 squash_guid( compgroupid, squashed );
5441 strcpyW( keypath, szInstallerComponents );
5442 strcatW( keypath, squashed );
5444 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5445 if (res != ERROR_SUCCESS)
5447 WARN("Unable to delete component key %d\n", res);
5450 uirow = MSI_CreateRecord( 2 );
5451 MSI_RecordSetStringW( uirow, 1, compgroupid );
5452 MSI_RecordSetStringW( uirow, 2, qualifier );
5453 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5454 msiobj_release( &uirow->hdr );
5456 return ERROR_SUCCESS;
5459 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5461 static const WCHAR query[] = {
5462 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5463 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5467 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5468 if (rc != ERROR_SUCCESS)
5469 return ERROR_SUCCESS;
5471 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5472 msiobj_release( &view->hdr );
5476 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5478 static const WCHAR query[] =
5479 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5480 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5481 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5482 MSIPACKAGE *package = param;
5483 MSICOMPONENT *component;
5486 SC_HANDLE hscm = NULL, service = NULL;
5488 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5489 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5490 DWORD serv_type, start_type, err_control;
5491 SERVICE_DESCRIPTIONW sd = {NULL};
5493 comp = MSI_RecordGetString( rec, 12 );
5494 component = msi_get_loaded_component( package, comp );
5497 WARN("service component not found\n");
5500 component->Action = msi_get_component_action( package, component );
5501 if (component->Action != INSTALLSTATE_LOCAL)
5503 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5506 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5509 ERR("Failed to open the SC Manager!\n");
5513 start_type = MSI_RecordGetInteger(rec, 5);
5514 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5517 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5518 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5519 serv_type = MSI_RecordGetInteger(rec, 4);
5520 err_control = MSI_RecordGetInteger(rec, 6);
5521 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5522 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5523 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5524 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5525 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5526 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5528 /* fetch the service path */
5529 row = MSI_QueryGetRecord(package->db, query, comp);
5532 ERR("Query failed\n");
5535 key = MSI_RecordGetString(row, 6);
5536 file = msi_get_loaded_file(package, key);
5537 msiobj_release(&row->hdr);
5540 ERR("Failed to load the service file\n");
5544 if (!args || !args[0]) image_path = file->TargetPath;
5547 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5548 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5549 return ERROR_OUTOFMEMORY;
5551 strcpyW(image_path, file->TargetPath);
5552 strcatW(image_path, szSpace);
5553 strcatW(image_path, args);
5555 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5556 start_type, err_control, image_path, load_order,
5557 NULL, depends, serv_name, pass);
5561 if (GetLastError() != ERROR_SERVICE_EXISTS)
5562 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5564 else if (sd.lpDescription)
5566 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5567 WARN("failed to set service description %u\n", GetLastError());
5570 if (image_path != file->TargetPath) msi_free(image_path);
5572 CloseServiceHandle(service);
5573 CloseServiceHandle(hscm);
5576 msi_free(sd.lpDescription);
5577 msi_free(load_order);
5578 msi_free(serv_name);
5583 return ERROR_SUCCESS;
5586 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5588 static const WCHAR query[] = {
5589 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5590 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5594 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5595 if (rc != ERROR_SUCCESS)
5596 return ERROR_SUCCESS;
5598 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5599 msiobj_release(&view->hdr);
5603 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5604 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5606 LPCWSTR *vector, *temp_vector;
5610 static const WCHAR separator[] = {'[','~',']',0};
5613 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5618 vector = msi_alloc(sizeof(LPWSTR));
5626 vector[*numargs - 1] = p;
5628 if ((q = strstrW(p, separator)))
5632 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5638 vector = temp_vector;
5647 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5649 MSIPACKAGE *package = param;
5652 SC_HANDLE scm = NULL, service = NULL;
5653 LPCWSTR component, *vector = NULL;
5654 LPWSTR name, args, display_name = NULL;
5655 DWORD event, numargs, len, wait, dummy;
5656 UINT r = ERROR_FUNCTION_FAILED;
5657 SERVICE_STATUS_PROCESS status;
5658 ULONGLONG start_time;
5660 component = MSI_RecordGetString(rec, 6);
5661 comp = msi_get_loaded_component(package, component);
5663 return ERROR_SUCCESS;
5665 comp->Action = msi_get_component_action( package, comp );
5666 if (comp->Action != INSTALLSTATE_LOCAL)
5668 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5669 return ERROR_SUCCESS;
5672 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5673 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5674 event = MSI_RecordGetInteger(rec, 3);
5675 wait = MSI_RecordGetInteger(rec, 5);
5677 if (!(event & msidbServiceControlEventStart))
5683 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5686 ERR("Failed to open the service control manager\n");
5691 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5692 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5694 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5695 GetServiceDisplayNameW( scm, name, display_name, &len );
5698 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5701 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5705 vector = msi_service_args_to_vector(args, &numargs);
5707 if (!StartServiceW(service, numargs, vector) &&
5708 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5710 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5717 /* wait for at most 30 seconds for the service to be up and running */
5718 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5719 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5721 TRACE("failed to query service status (%u)\n", GetLastError());
5724 start_time = GetTickCount64();
5725 while (status.dwCurrentState == SERVICE_START_PENDING)
5727 if (GetTickCount64() - start_time > 30000) break;
5729 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5730 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5732 TRACE("failed to query service status (%u)\n", GetLastError());
5736 if (status.dwCurrentState != SERVICE_RUNNING)
5738 WARN("service failed to start %u\n", status.dwCurrentState);
5739 r = ERROR_FUNCTION_FAILED;
5744 uirow = MSI_CreateRecord( 2 );
5745 MSI_RecordSetStringW( uirow, 1, display_name );
5746 MSI_RecordSetStringW( uirow, 2, name );
5747 msi_ui_actiondata( package, szStartServices, uirow );
5748 msiobj_release( &uirow->hdr );
5750 CloseServiceHandle(service);
5751 CloseServiceHandle(scm);
5756 msi_free(display_name);
5760 static UINT ACTION_StartServices( MSIPACKAGE *package )
5762 static const WCHAR query[] = {
5763 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5764 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5768 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5769 if (rc != ERROR_SUCCESS)
5770 return ERROR_SUCCESS;
5772 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5773 msiobj_release(&view->hdr);
5777 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5779 DWORD i, needed, count;
5780 ENUM_SERVICE_STATUSW *dependencies;
5784 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5785 0, &needed, &count))
5788 if (GetLastError() != ERROR_MORE_DATA)
5791 dependencies = msi_alloc(needed);
5795 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5796 needed, &needed, &count))
5799 for (i = 0; i < count; i++)
5801 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5802 SERVICE_STOP | SERVICE_QUERY_STATUS);
5806 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5813 msi_free(dependencies);
5817 static UINT stop_service( LPCWSTR name )
5819 SC_HANDLE scm = NULL, service = NULL;
5820 SERVICE_STATUS status;
5821 SERVICE_STATUS_PROCESS ssp;
5824 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5827 WARN("Failed to open the SCM: %d\n", GetLastError());
5831 service = OpenServiceW(scm, name,
5833 SERVICE_QUERY_STATUS |
5834 SERVICE_ENUMERATE_DEPENDENTS);
5837 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5841 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5842 sizeof(SERVICE_STATUS_PROCESS), &needed))
5844 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5848 if (ssp.dwCurrentState == SERVICE_STOPPED)
5851 stop_service_dependents(scm, service);
5853 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5854 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5857 CloseServiceHandle(service);
5858 CloseServiceHandle(scm);
5860 return ERROR_SUCCESS;
5863 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5865 MSIPACKAGE *package = param;
5869 LPWSTR name = NULL, display_name = NULL;
5873 event = MSI_RecordGetInteger( rec, 3 );
5874 if (!(event & msidbServiceControlEventStop))
5875 return ERROR_SUCCESS;
5877 component = MSI_RecordGetString( rec, 6 );
5878 comp = msi_get_loaded_component( package, component );
5880 return ERROR_SUCCESS;
5882 comp->Action = msi_get_component_action( package, comp );
5883 if (comp->Action != INSTALLSTATE_ABSENT)
5885 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5886 return ERROR_SUCCESS;
5889 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5892 ERR("Failed to open the service control manager\n");
5897 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5898 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5900 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5901 GetServiceDisplayNameW( scm, name, display_name, &len );
5903 CloseServiceHandle( scm );
5905 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5906 stop_service( name );
5909 uirow = MSI_CreateRecord( 2 );
5910 MSI_RecordSetStringW( uirow, 1, display_name );
5911 MSI_RecordSetStringW( uirow, 2, name );
5912 msi_ui_actiondata( package, szStopServices, uirow );
5913 msiobj_release( &uirow->hdr );
5916 msi_free( display_name );
5917 return ERROR_SUCCESS;
5920 static UINT ACTION_StopServices( MSIPACKAGE *package )
5922 static const WCHAR query[] = {
5923 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5924 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5928 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5929 if (rc != ERROR_SUCCESS)
5930 return ERROR_SUCCESS;
5932 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5933 msiobj_release(&view->hdr);
5937 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5939 MSIPACKAGE *package = param;
5942 LPWSTR name = NULL, display_name = NULL;
5944 SC_HANDLE scm = NULL, service = NULL;
5946 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5948 return ERROR_SUCCESS;
5950 event = MSI_RecordGetInteger( rec, 3 );
5951 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5953 comp->Action = msi_get_component_action( package, comp );
5954 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5955 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5957 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5959 return ERROR_SUCCESS;
5961 stop_service( name );
5963 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5966 WARN("Failed to open the SCM: %d\n", GetLastError());
5971 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5972 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5974 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5975 GetServiceDisplayNameW( scm, name, display_name, &len );
5978 service = OpenServiceW( scm, name, DELETE );
5981 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5985 if (!DeleteService( service ))
5986 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5989 uirow = MSI_CreateRecord( 2 );
5990 MSI_RecordSetStringW( uirow, 1, display_name );
5991 MSI_RecordSetStringW( uirow, 2, name );
5992 msi_ui_actiondata( package, szDeleteServices, uirow );
5993 msiobj_release( &uirow->hdr );
5995 CloseServiceHandle( service );
5996 CloseServiceHandle( scm );
5998 msi_free( display_name );
6000 return ERROR_SUCCESS;
6003 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6005 static const WCHAR query[] = {
6006 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6007 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6011 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6012 if (rc != ERROR_SUCCESS)
6013 return ERROR_SUCCESS;
6015 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6016 msiobj_release( &view->hdr );
6020 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6022 MSIPACKAGE *package = param;
6023 LPWSTR driver, driver_path, ptr;
6024 WCHAR outpath[MAX_PATH];
6025 MSIFILE *driver_file = NULL, *setup_file = NULL;
6028 LPCWSTR desc, file_key, component;
6030 UINT r = ERROR_SUCCESS;
6032 static const WCHAR driver_fmt[] = {
6033 'D','r','i','v','e','r','=','%','s',0};
6034 static const WCHAR setup_fmt[] = {
6035 'S','e','t','u','p','=','%','s',0};
6036 static const WCHAR usage_fmt[] = {
6037 'F','i','l','e','U','s','a','g','e','=','1',0};
6039 component = MSI_RecordGetString( rec, 2 );
6040 comp = msi_get_loaded_component( package, component );
6042 return ERROR_SUCCESS;
6044 comp->Action = msi_get_component_action( package, comp );
6045 if (comp->Action != INSTALLSTATE_LOCAL)
6047 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6048 return ERROR_SUCCESS;
6050 desc = MSI_RecordGetString(rec, 3);
6052 file_key = MSI_RecordGetString( rec, 4 );
6053 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6055 file_key = MSI_RecordGetString( rec, 5 );
6056 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6060 ERR("ODBC Driver entry not found!\n");
6061 return ERROR_FUNCTION_FAILED;
6064 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6066 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6067 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6069 driver = msi_alloc(len * sizeof(WCHAR));
6071 return ERROR_OUTOFMEMORY;
6074 lstrcpyW(ptr, desc);
6075 ptr += lstrlenW(ptr) + 1;
6077 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6082 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6086 lstrcpyW(ptr, usage_fmt);
6087 ptr += lstrlenW(ptr) + 1;
6090 if (!driver_file->TargetPath)
6092 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6093 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6095 driver_path = strdupW(driver_file->TargetPath);
6096 ptr = strrchrW(driver_path, '\\');
6097 if (ptr) *ptr = '\0';
6099 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6100 NULL, ODBC_INSTALL_COMPLETE, &usage))
6102 ERR("Failed to install SQL driver!\n");
6103 r = ERROR_FUNCTION_FAILED;
6106 uirow = MSI_CreateRecord( 5 );
6107 MSI_RecordSetStringW( uirow, 1, desc );
6108 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6109 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6110 msi_ui_actiondata( package, szInstallODBC, uirow );
6111 msiobj_release( &uirow->hdr );
6114 msi_free(driver_path);
6119 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6121 MSIPACKAGE *package = param;
6122 LPWSTR translator, translator_path, ptr;
6123 WCHAR outpath[MAX_PATH];
6124 MSIFILE *translator_file = NULL, *setup_file = NULL;
6127 LPCWSTR desc, file_key, component;
6129 UINT r = ERROR_SUCCESS;
6131 static const WCHAR translator_fmt[] = {
6132 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6133 static const WCHAR setup_fmt[] = {
6134 'S','e','t','u','p','=','%','s',0};
6136 component = MSI_RecordGetString( rec, 2 );
6137 comp = msi_get_loaded_component( package, component );
6139 return ERROR_SUCCESS;
6141 comp->Action = msi_get_component_action( package, comp );
6142 if (comp->Action != INSTALLSTATE_LOCAL)
6144 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6145 return ERROR_SUCCESS;
6147 desc = MSI_RecordGetString(rec, 3);
6149 file_key = MSI_RecordGetString( rec, 4 );
6150 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6152 file_key = MSI_RecordGetString( rec, 5 );
6153 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6155 if (!translator_file)
6157 ERR("ODBC Translator entry not found!\n");
6158 return ERROR_FUNCTION_FAILED;
6161 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6163 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6165 translator = msi_alloc(len * sizeof(WCHAR));
6167 return ERROR_OUTOFMEMORY;
6170 lstrcpyW(ptr, desc);
6171 ptr += lstrlenW(ptr) + 1;
6173 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6178 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6183 translator_path = strdupW(translator_file->TargetPath);
6184 ptr = strrchrW(translator_path, '\\');
6185 if (ptr) *ptr = '\0';
6187 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6188 NULL, ODBC_INSTALL_COMPLETE, &usage))
6190 ERR("Failed to install SQL translator!\n");
6191 r = ERROR_FUNCTION_FAILED;
6194 uirow = MSI_CreateRecord( 5 );
6195 MSI_RecordSetStringW( uirow, 1, desc );
6196 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6197 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6198 msi_ui_actiondata( package, szInstallODBC, uirow );
6199 msiobj_release( &uirow->hdr );
6201 msi_free(translator);
6202 msi_free(translator_path);
6207 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6209 MSIPACKAGE *package = param;
6212 LPCWSTR desc, driver, component;
6213 WORD request = ODBC_ADD_SYS_DSN;
6216 UINT r = ERROR_SUCCESS;
6219 static const WCHAR attrs_fmt[] = {
6220 'D','S','N','=','%','s',0 };
6222 component = MSI_RecordGetString( rec, 2 );
6223 comp = msi_get_loaded_component( package, component );
6225 return ERROR_SUCCESS;
6227 comp->Action = msi_get_component_action( package, comp );
6228 if (comp->Action != INSTALLSTATE_LOCAL)
6230 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6231 return ERROR_SUCCESS;
6234 desc = MSI_RecordGetString(rec, 3);
6235 driver = MSI_RecordGetString(rec, 4);
6236 registration = MSI_RecordGetInteger(rec, 5);
6238 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6239 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6241 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6242 attrs = msi_alloc(len * sizeof(WCHAR));
6244 return ERROR_OUTOFMEMORY;
6246 len = sprintfW(attrs, attrs_fmt, desc);
6249 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6251 ERR("Failed to install SQL data source!\n");
6252 r = ERROR_FUNCTION_FAILED;
6255 uirow = MSI_CreateRecord( 5 );
6256 MSI_RecordSetStringW( uirow, 1, desc );
6257 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6258 MSI_RecordSetInteger( uirow, 3, request );
6259 msi_ui_actiondata( package, szInstallODBC, uirow );
6260 msiobj_release( &uirow->hdr );
6267 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6269 static const WCHAR driver_query[] = {
6270 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6271 'O','D','B','C','D','r','i','v','e','r',0};
6272 static const WCHAR translator_query[] = {
6273 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6274 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6275 static const WCHAR source_query[] = {
6276 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6277 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6281 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6282 if (rc == ERROR_SUCCESS)
6284 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6285 msiobj_release(&view->hdr);
6286 if (rc != ERROR_SUCCESS)
6289 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6290 if (rc == ERROR_SUCCESS)
6292 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6293 msiobj_release(&view->hdr);
6294 if (rc != ERROR_SUCCESS)
6297 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6298 if (rc == ERROR_SUCCESS)
6300 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6301 msiobj_release(&view->hdr);
6302 if (rc != ERROR_SUCCESS)
6305 return ERROR_SUCCESS;
6308 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6310 MSIPACKAGE *package = param;
6314 LPCWSTR desc, component;
6316 component = MSI_RecordGetString( rec, 2 );
6317 comp = msi_get_loaded_component( package, component );
6319 return ERROR_SUCCESS;
6321 comp->Action = msi_get_component_action( package, comp );
6322 if (comp->Action != INSTALLSTATE_ABSENT)
6324 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6325 return ERROR_SUCCESS;
6328 desc = MSI_RecordGetString( rec, 3 );
6329 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6331 WARN("Failed to remove ODBC driver\n");
6335 FIXME("Usage count reached 0\n");
6338 uirow = MSI_CreateRecord( 2 );
6339 MSI_RecordSetStringW( uirow, 1, desc );
6340 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6341 msi_ui_actiondata( package, szRemoveODBC, uirow );
6342 msiobj_release( &uirow->hdr );
6344 return ERROR_SUCCESS;
6347 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6349 MSIPACKAGE *package = param;
6353 LPCWSTR desc, component;
6355 component = MSI_RecordGetString( rec, 2 );
6356 comp = msi_get_loaded_component( package, component );
6358 return ERROR_SUCCESS;
6360 comp->Action = msi_get_component_action( package, comp );
6361 if (comp->Action != INSTALLSTATE_ABSENT)
6363 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6364 return ERROR_SUCCESS;
6367 desc = MSI_RecordGetString( rec, 3 );
6368 if (!SQLRemoveTranslatorW( desc, &usage ))
6370 WARN("Failed to remove ODBC translator\n");
6374 FIXME("Usage count reached 0\n");
6377 uirow = MSI_CreateRecord( 2 );
6378 MSI_RecordSetStringW( uirow, 1, desc );
6379 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6380 msi_ui_actiondata( package, szRemoveODBC, uirow );
6381 msiobj_release( &uirow->hdr );
6383 return ERROR_SUCCESS;
6386 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6388 MSIPACKAGE *package = param;
6392 LPCWSTR desc, driver, component;
6393 WORD request = ODBC_REMOVE_SYS_DSN;
6397 static const WCHAR attrs_fmt[] = {
6398 'D','S','N','=','%','s',0 };
6400 component = MSI_RecordGetString( rec, 2 );
6401 comp = msi_get_loaded_component( package, component );
6403 return ERROR_SUCCESS;
6405 comp->Action = msi_get_component_action( package, comp );
6406 if (comp->Action != INSTALLSTATE_ABSENT)
6408 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6409 return ERROR_SUCCESS;
6412 desc = MSI_RecordGetString( rec, 3 );
6413 driver = MSI_RecordGetString( rec, 4 );
6414 registration = MSI_RecordGetInteger( rec, 5 );
6416 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6417 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6419 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6420 attrs = msi_alloc( len * sizeof(WCHAR) );
6422 return ERROR_OUTOFMEMORY;
6424 FIXME("Use ODBCSourceAttribute table\n");
6426 len = sprintfW( attrs, attrs_fmt, desc );
6429 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6431 WARN("Failed to remove ODBC data source\n");
6435 uirow = MSI_CreateRecord( 3 );
6436 MSI_RecordSetStringW( uirow, 1, desc );
6437 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6438 MSI_RecordSetInteger( uirow, 3, request );
6439 msi_ui_actiondata( package, szRemoveODBC, uirow );
6440 msiobj_release( &uirow->hdr );
6442 return ERROR_SUCCESS;
6445 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6447 static const WCHAR driver_query[] = {
6448 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6449 'O','D','B','C','D','r','i','v','e','r',0};
6450 static const WCHAR translator_query[] = {
6451 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6452 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6453 static const WCHAR source_query[] = {
6454 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6455 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6459 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6460 if (rc == ERROR_SUCCESS)
6462 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6463 msiobj_release( &view->hdr );
6464 if (rc != ERROR_SUCCESS)
6467 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6468 if (rc == ERROR_SUCCESS)
6470 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6471 msiobj_release( &view->hdr );
6472 if (rc != ERROR_SUCCESS)
6475 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6476 if (rc == ERROR_SUCCESS)
6478 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6479 msiobj_release( &view->hdr );
6480 if (rc != ERROR_SUCCESS)
6483 return ERROR_SUCCESS;
6486 #define ENV_ACT_SETALWAYS 0x1
6487 #define ENV_ACT_SETABSENT 0x2
6488 #define ENV_ACT_REMOVE 0x4
6489 #define ENV_ACT_REMOVEMATCH 0x8
6491 #define ENV_MOD_MACHINE 0x20000000
6492 #define ENV_MOD_APPEND 0x40000000
6493 #define ENV_MOD_PREFIX 0x80000000
6494 #define ENV_MOD_MASK 0xC0000000
6496 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6498 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6500 LPCWSTR cptr = *name;
6502 static const WCHAR prefix[] = {'[','~',']',0};
6503 static const int prefix_len = 3;
6509 *flags |= ENV_ACT_SETALWAYS;
6510 else if (*cptr == '+')
6511 *flags |= ENV_ACT_SETABSENT;
6512 else if (*cptr == '-')
6513 *flags |= ENV_ACT_REMOVE;
6514 else if (*cptr == '!')
6515 *flags |= ENV_ACT_REMOVEMATCH;
6516 else if (*cptr == '*')
6517 *flags |= ENV_MOD_MACHINE;
6527 ERR("Missing environment variable\n");
6528 return ERROR_FUNCTION_FAILED;
6533 LPCWSTR ptr = *value;
6534 if (!strncmpW(ptr, prefix, prefix_len))
6536 if (ptr[prefix_len] == szSemiColon[0])
6538 *flags |= ENV_MOD_APPEND;
6539 *value += lstrlenW(prefix);
6546 else if (lstrlenW(*value) >= prefix_len)
6548 ptr += lstrlenW(ptr) - prefix_len;
6549 if (!strcmpW( ptr, prefix ))
6551 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6553 *flags |= ENV_MOD_PREFIX;
6554 /* the "[~]" will be removed by deformat_string */;
6564 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6565 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6566 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6567 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6569 ERR("Invalid flags: %08x\n", *flags);
6570 return ERROR_FUNCTION_FAILED;
6574 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6576 return ERROR_SUCCESS;
6579 static UINT open_env_key( DWORD flags, HKEY *key )
6581 static const WCHAR user_env[] =
6582 {'E','n','v','i','r','o','n','m','e','n','t',0};
6583 static const WCHAR machine_env[] =
6584 {'S','y','s','t','e','m','\\',
6585 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6586 'C','o','n','t','r','o','l','\\',
6587 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6588 'E','n','v','i','r','o','n','m','e','n','t',0};
6593 if (flags & ENV_MOD_MACHINE)
6596 root = HKEY_LOCAL_MACHINE;
6601 root = HKEY_CURRENT_USER;
6604 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6605 if (res != ERROR_SUCCESS)
6607 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6608 return ERROR_FUNCTION_FAILED;
6611 return ERROR_SUCCESS;
6614 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6616 MSIPACKAGE *package = param;
6617 LPCWSTR name, value, component;
6618 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6619 DWORD flags, type, size;
6626 component = MSI_RecordGetString(rec, 4);
6627 comp = msi_get_loaded_component(package, component);
6629 return ERROR_SUCCESS;
6631 comp->Action = msi_get_component_action( package, comp );
6632 if (comp->Action != INSTALLSTATE_LOCAL)
6634 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6635 return ERROR_SUCCESS;
6637 name = MSI_RecordGetString(rec, 2);
6638 value = MSI_RecordGetString(rec, 3);
6640 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6642 res = env_parse_flags(&name, &value, &flags);
6643 if (res != ERROR_SUCCESS || !value)
6646 if (value && !deformat_string(package, value, &deformatted))
6648 res = ERROR_OUTOFMEMORY;
6652 value = deformatted;
6654 res = open_env_key( flags, &env );
6655 if (res != ERROR_SUCCESS)
6658 if (flags & ENV_MOD_MACHINE)
6659 action |= 0x20000000;
6663 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6664 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6665 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6668 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6672 /* Nothing to do. */
6675 res = ERROR_SUCCESS;
6679 /* If we are appending but the string was empty, strip ; */
6680 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6682 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6683 newval = strdupW(value);
6686 res = ERROR_OUTOFMEMORY;
6694 /* Contrary to MSDN, +-variable to [~];path works */
6695 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6697 res = ERROR_SUCCESS;
6701 data = msi_alloc(size);
6705 return ERROR_OUTOFMEMORY;
6708 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6709 if (res != ERROR_SUCCESS)
6712 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6715 res = RegDeleteValueW(env, name);
6716 if (res != ERROR_SUCCESS)
6717 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6721 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6722 if (flags & ENV_MOD_MASK)
6726 if (flags & ENV_MOD_APPEND) multiplier++;
6727 if (flags & ENV_MOD_PREFIX) multiplier++;
6728 mod_size = lstrlenW(value) * multiplier;
6729 size += mod_size * sizeof(WCHAR);
6732 newval = msi_alloc(size);
6736 res = ERROR_OUTOFMEMORY;
6740 if (flags & ENV_MOD_PREFIX)
6742 lstrcpyW(newval, value);
6743 ptr = newval + lstrlenW(value);
6744 action |= 0x80000000;
6747 lstrcpyW(ptr, data);
6749 if (flags & ENV_MOD_APPEND)
6751 lstrcatW(newval, value);
6752 action |= 0x40000000;
6755 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6756 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6759 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6763 uirow = MSI_CreateRecord( 3 );
6764 MSI_RecordSetStringW( uirow, 1, name );
6765 MSI_RecordSetStringW( uirow, 2, newval );
6766 MSI_RecordSetInteger( uirow, 3, action );
6767 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6768 msiobj_release( &uirow->hdr );
6770 if (env) RegCloseKey(env);
6771 msi_free(deformatted);
6777 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6779 static const WCHAR query[] = {
6780 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6781 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6785 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6786 if (rc != ERROR_SUCCESS)
6787 return ERROR_SUCCESS;
6789 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6790 msiobj_release(&view->hdr);
6794 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6796 MSIPACKAGE *package = param;
6797 LPCWSTR name, value, component;
6798 LPWSTR deformatted = NULL;
6807 component = MSI_RecordGetString( rec, 4 );
6808 comp = msi_get_loaded_component( package, component );
6810 return ERROR_SUCCESS;
6812 comp->Action = msi_get_component_action( package, comp );
6813 if (comp->Action != INSTALLSTATE_ABSENT)
6815 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6816 return ERROR_SUCCESS;
6818 name = MSI_RecordGetString( rec, 2 );
6819 value = MSI_RecordGetString( rec, 3 );
6821 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6823 r = env_parse_flags( &name, &value, &flags );
6824 if (r != ERROR_SUCCESS)
6827 if (!(flags & ENV_ACT_REMOVE))
6829 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6830 return ERROR_SUCCESS;
6833 if (value && !deformat_string( package, value, &deformatted ))
6834 return ERROR_OUTOFMEMORY;
6836 value = deformatted;
6838 r = open_env_key( flags, &env );
6839 if (r != ERROR_SUCCESS)
6845 if (flags & ENV_MOD_MACHINE)
6846 action |= 0x20000000;
6848 TRACE("Removing %s\n", debugstr_w(name));
6850 res = RegDeleteValueW( env, name );
6851 if (res != ERROR_SUCCESS)
6853 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6858 uirow = MSI_CreateRecord( 3 );
6859 MSI_RecordSetStringW( uirow, 1, name );
6860 MSI_RecordSetStringW( uirow, 2, value );
6861 MSI_RecordSetInteger( uirow, 3, action );
6862 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6863 msiobj_release( &uirow->hdr );
6865 if (env) RegCloseKey( env );
6866 msi_free( deformatted );
6870 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6872 static const WCHAR query[] = {
6873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6874 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6879 if (rc != ERROR_SUCCESS)
6880 return ERROR_SUCCESS;
6882 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6883 msiobj_release( &view->hdr );
6887 UINT msi_validate_product_id( MSIPACKAGE *package )
6889 LPWSTR key, template, id;
6890 UINT r = ERROR_SUCCESS;
6892 id = msi_dup_property( package->db, szProductID );
6896 return ERROR_SUCCESS;
6898 template = msi_dup_property( package->db, szPIDTemplate );
6899 key = msi_dup_property( package->db, szPIDKEY );
6900 if (key && template)
6902 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6903 r = msi_set_property( package->db, szProductID, key );
6905 msi_free( template );
6910 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6912 return msi_validate_product_id( package );
6915 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6918 package->need_reboot_at_end = 1;
6919 return ERROR_SUCCESS;
6922 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6924 static const WCHAR szAvailableFreeReg[] =
6925 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6927 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6929 TRACE("%p %d kilobytes\n", package, space);
6931 uirow = MSI_CreateRecord( 1 );
6932 MSI_RecordSetInteger( uirow, 1, space );
6933 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6934 msiobj_release( &uirow->hdr );
6936 return ERROR_SUCCESS;
6939 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6941 TRACE("%p\n", package);
6943 msi_set_property( package->db, szRollbackDisabled, szOne );
6944 return ERROR_SUCCESS;
6947 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6949 FIXME("%p\n", package);
6950 return ERROR_SUCCESS;
6953 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6955 static const WCHAR driver_query[] = {
6956 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6957 'O','D','B','C','D','r','i','v','e','r',0};
6958 static const WCHAR translator_query[] = {
6959 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6960 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6964 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6965 if (r == ERROR_SUCCESS)
6968 r = MSI_IterateRecords( view, &count, NULL, package );
6969 msiobj_release( &view->hdr );
6970 if (r != ERROR_SUCCESS)
6972 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6974 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6975 if (r == ERROR_SUCCESS)
6978 r = MSI_IterateRecords( view, &count, NULL, package );
6979 msiobj_release( &view->hdr );
6980 if (r != ERROR_SUCCESS)
6982 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6984 return ERROR_SUCCESS;
6987 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6989 MSIPACKAGE *package = param;
6990 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6993 if ((value = msi_dup_property( package->db, property )))
6995 FIXME("remove %s\n", debugstr_w(value));
6998 return ERROR_SUCCESS;
7001 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7003 static const WCHAR query[] = {
7004 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7005 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7009 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7010 if (r == ERROR_SUCCESS)
7012 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7013 msiobj_release( &view->hdr );
7014 if (r != ERROR_SUCCESS)
7017 return ERROR_SUCCESS;
7020 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7022 MSIPACKAGE *package = param;
7023 int attributes = MSI_RecordGetInteger( rec, 5 );
7025 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7027 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7028 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7029 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7030 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7034 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7036 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7037 if (r != ERROR_SUCCESS)
7038 return ERROR_SUCCESS;
7042 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7043 if (r != ERROR_SUCCESS)
7044 return ERROR_SUCCESS;
7046 RegCloseKey( hkey );
7048 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7049 debugstr_w(upgrade_code), debugstr_w(version_min),
7050 debugstr_w(version_max), debugstr_w(language));
7052 return ERROR_SUCCESS;
7055 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7057 static const WCHAR query[] = {
7058 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7059 'U','p','g','r','a','d','e',0};
7063 if (msi_get_property_int( package->db, szInstalled, 0 ))
7065 TRACE("product is installed, skipping action\n");
7066 return ERROR_SUCCESS;
7068 if (msi_get_property_int( package->db, szPreselected, 0 ))
7070 TRACE("Preselected property is set, not migrating feature states\n");
7071 return ERROR_SUCCESS;
7073 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7074 if (r == ERROR_SUCCESS)
7076 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7077 msiobj_release( &view->hdr );
7078 if (r != ERROR_SUCCESS)
7081 return ERROR_SUCCESS;
7084 static void bind_image( const char *filename, const char *path )
7086 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7088 WARN("failed to bind image %u\n", GetLastError());
7092 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7096 MSIPACKAGE *package = param;
7097 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7098 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7099 char *filenameA, *pathA;
7100 WCHAR *pathW, **path_list;
7102 if (!(file = msi_get_loaded_file( package, key )))
7104 WARN("file %s not found\n", debugstr_w(key));
7105 return ERROR_SUCCESS;
7107 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7108 path_list = msi_split_string( paths, ';' );
7109 if (!path_list) bind_image( filenameA, NULL );
7112 for (i = 0; path_list[i] && path_list[i][0]; i++)
7114 deformat_string( package, path_list[i], &pathW );
7115 if ((pathA = strdupWtoA( pathW )))
7117 bind_image( filenameA, pathA );
7123 msi_free( path_list );
7124 msi_free( filenameA );
7125 return ERROR_SUCCESS;
7128 static UINT ACTION_BindImage( MSIPACKAGE *package )
7130 static const WCHAR query[] = {
7131 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7132 'B','i','n','d','I','m','a','g','e',0};
7136 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7137 if (r == ERROR_SUCCESS)
7139 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7140 msiobj_release( &view->hdr );
7141 if (r != ERROR_SUCCESS)
7144 return ERROR_SUCCESS;
7147 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7149 static const WCHAR query[] = {
7150 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7155 r = MSI_OpenQuery( package->db, &view, query, table );
7156 if (r == ERROR_SUCCESS)
7158 r = MSI_IterateRecords(view, &count, NULL, package);
7159 msiobj_release(&view->hdr);
7160 if (r != ERROR_SUCCESS)
7163 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7164 return ERROR_SUCCESS;
7167 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7169 static const WCHAR table[] = {
7170 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7171 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7174 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7176 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7177 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7180 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7182 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7183 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7186 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7188 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7189 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7192 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7194 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7195 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7200 const WCHAR *action;
7201 UINT (*handler)(MSIPACKAGE *);
7202 const WCHAR *action_rollback;
7206 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7207 { szAppSearch, ACTION_AppSearch, NULL },
7208 { szBindImage, ACTION_BindImage, NULL },
7209 { szCCPSearch, ACTION_CCPSearch, NULL },
7210 { szCostFinalize, ACTION_CostFinalize, NULL },
7211 { szCostInitialize, ACTION_CostInitialize, NULL },
7212 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7213 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7214 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7215 { szDisableRollback, ACTION_DisableRollback, NULL },
7216 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7217 { szExecuteAction, ACTION_ExecuteAction, NULL },
7218 { szFileCost, ACTION_FileCost, NULL },
7219 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7220 { szForceReboot, ACTION_ForceReboot, NULL },
7221 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7222 { szInstallExecute, ACTION_InstallExecute, NULL },
7223 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7224 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7225 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7226 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7227 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7228 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7229 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7230 { szInstallValidate, ACTION_InstallValidate, NULL },
7231 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7232 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7233 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7234 { szMoveFiles, ACTION_MoveFiles, NULL },
7235 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7236 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7237 { szPatchFiles, ACTION_PatchFiles, NULL },
7238 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7239 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7240 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7241 { szPublishProduct, ACTION_PublishProduct, NULL },
7242 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7243 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7244 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7245 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7246 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7247 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7248 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7249 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7250 { szRegisterUser, ACTION_RegisterUser, NULL },
7251 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7252 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7253 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7254 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7255 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7256 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7257 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7258 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7259 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7260 { szResolveSource, ACTION_ResolveSource, NULL },
7261 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7262 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7263 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7264 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7265 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7266 { szStartServices, ACTION_StartServices, szStopServices },
7267 { szStopServices, ACTION_StopServices, szStartServices },
7268 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7269 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7270 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7271 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7272 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7273 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7274 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7275 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7276 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7277 { szValidateProductID, ACTION_ValidateProductID, NULL },
7278 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7279 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7280 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7281 { NULL, NULL, NULL }
7284 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7290 while (StandardActions[i].action != NULL)
7292 if (!strcmpW( StandardActions[i].action, action ))
7294 ui_actionstart( package, action );
7295 if (StandardActions[i].handler)
7297 ui_actioninfo( package, action, TRUE, 0 );
7298 *rc = StandardActions[i].handler( package );
7299 ui_actioninfo( package, action, FALSE, *rc );
7301 if (StandardActions[i].action_rollback && !package->need_rollback)
7303 TRACE("scheduling rollback action\n");
7304 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7309 FIXME("unhandled standard action %s\n", debugstr_w(action));
7310 *rc = ERROR_SUCCESS;
7320 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7322 UINT rc = ERROR_SUCCESS;
7325 TRACE("Performing action (%s)\n", debugstr_w(action));
7327 handled = ACTION_HandleStandardAction(package, action, &rc);
7330 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7334 WARN("unhandled msi action %s\n", debugstr_w(action));
7335 rc = ERROR_FUNCTION_NOT_CALLED;
7341 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7343 UINT rc = ERROR_SUCCESS;
7344 BOOL handled = FALSE;
7346 TRACE("Performing action (%s)\n", debugstr_w(action));
7348 package->action_progress_increment = 0;
7349 handled = ACTION_HandleStandardAction(package, action, &rc);
7352 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7354 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7359 WARN("unhandled msi action %s\n", debugstr_w(action));
7360 rc = ERROR_FUNCTION_NOT_CALLED;
7366 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7368 UINT rc = ERROR_SUCCESS;
7371 static const WCHAR query[] =
7372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7373 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7374 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7375 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7376 static const WCHAR ui_query[] =
7377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7378 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7379 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7380 ' ', '=',' ','%','i',0};
7382 if (needs_ui_sequence(package))
7383 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7385 row = MSI_QueryGetRecord(package->db, query, seq);
7389 LPCWSTR action, cond;
7391 TRACE("Running the actions\n");
7393 /* check conditions */
7394 cond = MSI_RecordGetString(row, 2);
7396 /* this is a hack to skip errors in the condition code */
7397 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7399 msiobj_release(&row->hdr);
7400 return ERROR_SUCCESS;
7403 action = MSI_RecordGetString(row, 1);
7406 ERR("failed to fetch action\n");
7407 msiobj_release(&row->hdr);
7408 return ERROR_FUNCTION_FAILED;
7411 if (needs_ui_sequence(package))
7412 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7414 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7416 msiobj_release(&row->hdr);
7422 /****************************************************
7423 * TOP level entry points
7424 *****************************************************/
7426 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7427 LPCWSTR szCommandLine )
7429 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7430 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7431 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7432 WCHAR *reinstall = NULL;
7436 msi_set_property( package->db, szAction, szInstall );
7438 package->script->InWhatSequence = SEQUENCE_INSTALL;
7445 dir = strdupW(szPackagePath);
7446 p = strrchrW(dir, '\\');
7450 file = szPackagePath + (p - dir);
7455 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7456 GetCurrentDirectoryW(MAX_PATH, dir);
7457 lstrcatW(dir, szBackSlash);
7458 file = szPackagePath;
7461 msi_free( package->PackagePath );
7462 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7463 if (!package->PackagePath)
7466 return ERROR_OUTOFMEMORY;
7469 lstrcpyW(package->PackagePath, dir);
7470 lstrcatW(package->PackagePath, file);
7473 msi_set_sourcedir_props(package, FALSE);
7476 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7477 if (rc != ERROR_SUCCESS)
7480 msi_apply_transforms( package );
7481 msi_apply_patches( package );
7483 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7485 TRACE("setting reinstall property\n");
7486 msi_set_property( package->db, szReinstall, szAll );
7489 /* properties may have been added by a transform */
7490 msi_clone_properties( package );
7492 msi_parse_command_line( package, szCommandLine, FALSE );
7493 msi_adjust_privilege_properties( package );
7494 msi_set_context( package );
7496 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7498 TRACE("disabling rollback\n");
7499 msi_set_property( package->db, szRollbackDisabled, szOne );
7502 if (needs_ui_sequence( package))
7504 package->script->InWhatSequence |= SEQUENCE_UI;
7505 rc = ACTION_ProcessUISequence(package);
7506 ui_exists = ui_sequence_exists(package);
7507 if (rc == ERROR_SUCCESS || !ui_exists)
7509 package->script->InWhatSequence |= SEQUENCE_EXEC;
7510 rc = ACTION_ProcessExecSequence(package, ui_exists);
7514 rc = ACTION_ProcessExecSequence(package, FALSE);
7516 package->script->CurrentlyScripting = FALSE;
7518 /* process the ending type action */
7519 if (rc == ERROR_SUCCESS)
7520 ACTION_PerformActionSequence(package, -1);
7521 else if (rc == ERROR_INSTALL_USEREXIT)
7522 ACTION_PerformActionSequence(package, -2);
7523 else if (rc == ERROR_INSTALL_SUSPEND)
7524 ACTION_PerformActionSequence(package, -4);
7527 ACTION_PerformActionSequence(package, -3);
7528 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7530 package->need_rollback = TRUE;
7534 /* finish up running custom actions */
7535 ACTION_FinishCustomActions(package);
7537 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7539 WARN("installation failed, running rollback script\n");
7540 execute_script( package, SCRIPT_ROLLBACK );
7542 msi_free( reinstall );
7544 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7545 return ERROR_SUCCESS_REBOOT_REQUIRED;