2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
191 sprintfW(message,template_s,timet,action);
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
221 case state_whitespace:
231 if (in_quotes && p[1] != '\"') count--;
247 if (in_quotes) count--;
251 state = state_whitespace;
252 if (!count) goto done;
257 if (!count) in_quotes = 0;
268 if (in_quotes && p[1] != '\"') count--;
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
279 if (!count) in_quotes = 0;
288 if (!ignore) *out++ = *p;
292 if (!len) *value = 0;
299 static void remove_quotes( WCHAR *str )
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
321 return ERROR_SUCCESS;
326 while (*ptr == ' ') ptr++;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
338 if (!preserve_case) struprW( prop );
341 while (*ptr2 == ' ') ptr2++;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
348 WARN("unbalanced quotes\n");
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
372 LPWSTR p, *ret = NULL;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
395 for( count = 0; (ret[count] = p); count++ )
397 p = strchrW( p, sep );
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 db = msi_dup_property( package->db, szOriginalDatabase );
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
448 p = strrchrW( db, '/' );
452 return ERROR_SUCCESS;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
543 rc = ACTION_ForceReboot( package );
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property(package->db, szSourceDir, NULL);
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
736 if (!(slash = strrchrW( new_path, '\\' )))
741 len = slash - new_path;
743 if (!msi_create_full_path( new_path ))
748 new_path[len] = '\\';
750 msi_free( new_path );
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 return comp->ActionRequest;
815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
817 if (package->need_rollback) return feature->Installed;
818 return feature->ActionRequest;
821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
823 MSIPACKAGE *package = param;
824 LPCWSTR dir, component, full_path;
829 component = MSI_RecordGetString(row, 2);
831 return ERROR_SUCCESS;
833 comp = msi_get_loaded_component(package, component);
835 return ERROR_SUCCESS;
837 comp->Action = msi_get_component_action( package, comp );
838 if (comp->Action != INSTALLSTATE_LOCAL)
840 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
841 return ERROR_SUCCESS;
844 dir = MSI_RecordGetString(row,1);
847 ERR("Unable to get folder id\n");
848 return ERROR_SUCCESS;
851 uirow = MSI_CreateRecord(1);
852 MSI_RecordSetStringW(uirow, 1, dir);
853 msi_ui_actiondata(package, szCreateFolders, uirow);
854 msiobj_release(&uirow->hdr);
856 full_path = msi_get_target_folder( package, dir );
859 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
860 return ERROR_SUCCESS;
862 TRACE("folder is %s\n", debugstr_w(full_path));
864 folder = msi_get_loaded_folder( package, dir );
865 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
866 folder->State = FOLDER_STATE_CREATED;
867 return ERROR_SUCCESS;
870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
872 static const WCHAR query[] = {
873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
874 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
879 if (rc != ERROR_SUCCESS)
880 return ERROR_SUCCESS;
882 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
883 msiobj_release(&view->hdr);
887 static void remove_persistent_folder( MSIFOLDER *folder )
891 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
893 remove_persistent_folder( fl->folder );
895 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
897 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
903 MSIPACKAGE *package = param;
904 LPCWSTR dir, component, full_path;
909 component = MSI_RecordGetString(row, 2);
911 return ERROR_SUCCESS;
913 comp = msi_get_loaded_component(package, component);
915 return ERROR_SUCCESS;
917 comp->Action = msi_get_component_action( package, comp );
918 if (comp->Action != INSTALLSTATE_ABSENT)
920 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
921 return ERROR_SUCCESS;
924 dir = MSI_RecordGetString( row, 1 );
927 ERR("Unable to get folder id\n");
928 return ERROR_SUCCESS;
931 full_path = msi_get_target_folder( package, dir );
934 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
935 return ERROR_SUCCESS;
937 TRACE("folder is %s\n", debugstr_w(full_path));
939 uirow = MSI_CreateRecord( 1 );
940 MSI_RecordSetStringW( uirow, 1, dir );
941 msi_ui_actiondata( package, szRemoveFolders, uirow );
942 msiobj_release( &uirow->hdr );
944 folder = msi_get_loaded_folder( package, dir );
945 remove_persistent_folder( folder );
946 return ERROR_SUCCESS;
949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
951 static const WCHAR query[] = {
952 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
953 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
957 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
958 if (rc != ERROR_SUCCESS)
959 return ERROR_SUCCESS;
961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
962 msiobj_release( &view->hdr );
966 static UINT load_component( MSIRECORD *row, LPVOID param )
968 MSIPACKAGE *package = param;
971 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
973 return ERROR_FUNCTION_FAILED;
975 list_add_tail( &package->components, &comp->entry );
977 /* fill in the data */
978 comp->Component = msi_dup_record_field( row, 1 );
980 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
982 comp->ComponentId = msi_dup_record_field( row, 2 );
983 comp->Directory = msi_dup_record_field( row, 3 );
984 comp->Attributes = MSI_RecordGetInteger(row,4);
985 comp->Condition = msi_dup_record_field( row, 5 );
986 comp->KeyPath = msi_dup_record_field( row, 6 );
988 comp->Installed = INSTALLSTATE_UNKNOWN;
989 comp->Action = INSTALLSTATE_UNKNOWN;
990 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
992 comp->assembly = msi_load_assembly( package, comp );
993 return ERROR_SUCCESS;
996 UINT msi_load_all_components( MSIPACKAGE *package )
998 static const WCHAR query[] = {
999 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1000 '`','C','o','m','p','o','n','e','n','t','`',0};
1004 if (!list_empty(&package->components))
1005 return ERROR_SUCCESS;
1007 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1008 if (r != ERROR_SUCCESS)
1011 if (!msi_init_assembly_caches( package ))
1013 ERR("can't initialize assembly caches\n");
1014 msiobj_release( &view->hdr );
1015 return ERROR_FUNCTION_FAILED;
1018 r = MSI_IterateRecords(view, NULL, load_component, package);
1019 msiobj_release(&view->hdr);
1024 MSIPACKAGE *package;
1025 MSIFEATURE *feature;
1028 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1032 cl = msi_alloc( sizeof (*cl) );
1034 return ERROR_NOT_ENOUGH_MEMORY;
1035 cl->component = comp;
1036 list_add_tail( &feature->Components, &cl->entry );
1038 return ERROR_SUCCESS;
1041 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1045 fl = msi_alloc( sizeof(*fl) );
1047 return ERROR_NOT_ENOUGH_MEMORY;
1048 fl->feature = child;
1049 list_add_tail( &parent->Children, &fl->entry );
1051 return ERROR_SUCCESS;
1054 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1056 _ilfs* ilfs = param;
1060 component = MSI_RecordGetString(row,1);
1062 /* check to see if the component is already loaded */
1063 comp = msi_get_loaded_component( ilfs->package, component );
1066 WARN("ignoring unknown component %s\n", debugstr_w(component));
1067 return ERROR_SUCCESS;
1069 add_feature_component( ilfs->feature, comp );
1070 comp->Enabled = TRUE;
1072 return ERROR_SUCCESS;
1075 static UINT load_feature(MSIRECORD * row, LPVOID param)
1077 static const WCHAR query[] = {
1078 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1079 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1080 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1081 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1082 MSIPACKAGE *package = param;
1083 MSIFEATURE *feature;
1088 /* fill in the data */
1090 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1092 return ERROR_NOT_ENOUGH_MEMORY;
1094 list_init( &feature->Children );
1095 list_init( &feature->Components );
1097 feature->Feature = msi_dup_record_field( row, 1 );
1099 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1101 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1102 feature->Title = msi_dup_record_field( row, 3 );
1103 feature->Description = msi_dup_record_field( row, 4 );
1105 if (!MSI_RecordIsNull(row,5))
1106 feature->Display = MSI_RecordGetInteger(row,5);
1108 feature->Level= MSI_RecordGetInteger(row,6);
1109 feature->Directory = msi_dup_record_field( row, 7 );
1110 feature->Attributes = MSI_RecordGetInteger(row,8);
1112 feature->Installed = INSTALLSTATE_UNKNOWN;
1113 feature->Action = INSTALLSTATE_UNKNOWN;
1114 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1116 list_add_tail( &package->features, &feature->entry );
1118 /* load feature components */
1120 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1121 if (rc != ERROR_SUCCESS)
1122 return ERROR_SUCCESS;
1124 ilfs.package = package;
1125 ilfs.feature = feature;
1127 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1128 msiobj_release(&view->hdr);
1132 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1134 MSIPACKAGE *package = param;
1135 MSIFEATURE *parent, *child;
1137 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1139 return ERROR_FUNCTION_FAILED;
1141 if (!child->Feature_Parent)
1142 return ERROR_SUCCESS;
1144 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1146 return ERROR_FUNCTION_FAILED;
1148 add_feature_child( parent, child );
1149 return ERROR_SUCCESS;
1152 UINT msi_load_all_features( MSIPACKAGE *package )
1154 static const WCHAR query[] = {
1155 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1156 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1157 '`','D','i','s','p','l','a','y','`',0};
1161 if (!list_empty(&package->features))
1162 return ERROR_SUCCESS;
1164 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1165 if (r != ERROR_SUCCESS)
1168 r = MSI_IterateRecords( view, NULL, load_feature, package );
1169 if (r != ERROR_SUCCESS)
1171 msiobj_release( &view->hdr );
1174 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1175 msiobj_release( &view->hdr );
1179 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1190 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1192 static const WCHAR query[] = {
1193 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1194 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1195 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1196 MSIQUERY *view = NULL;
1197 MSIRECORD *row = NULL;
1200 TRACE("%s\n", debugstr_w(file->File));
1202 r = MSI_OpenQuery(package->db, &view, query, file->File);
1203 if (r != ERROR_SUCCESS)
1206 r = MSI_ViewExecute(view, NULL);
1207 if (r != ERROR_SUCCESS)
1210 r = MSI_ViewFetch(view, &row);
1211 if (r != ERROR_SUCCESS)
1214 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1215 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1216 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1217 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1218 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1221 if (view) msiobj_release(&view->hdr);
1222 if (row) msiobj_release(&row->hdr);
1226 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1229 static const WCHAR query[] = {
1230 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1231 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1232 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1234 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1237 WARN("query failed\n");
1238 return ERROR_FUNCTION_FAILED;
1241 file->disk_id = MSI_RecordGetInteger( row, 1 );
1242 msiobj_release( &row->hdr );
1243 return ERROR_SUCCESS;
1246 static UINT load_file(MSIRECORD *row, LPVOID param)
1248 MSIPACKAGE* package = param;
1252 /* fill in the data */
1254 file = msi_alloc_zero( sizeof (MSIFILE) );
1256 return ERROR_NOT_ENOUGH_MEMORY;
1258 file->File = msi_dup_record_field( row, 1 );
1260 component = MSI_RecordGetString( row, 2 );
1261 file->Component = msi_get_loaded_component( package, component );
1263 if (!file->Component)
1265 WARN("Component not found: %s\n", debugstr_w(component));
1266 msi_free(file->File);
1268 return ERROR_SUCCESS;
1271 file->FileName = msi_dup_record_field( row, 3 );
1272 msi_reduce_to_long_filename( file->FileName );
1274 file->ShortName = msi_dup_record_field( row, 3 );
1275 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1277 file->FileSize = MSI_RecordGetInteger( row, 4 );
1278 file->Version = msi_dup_record_field( row, 5 );
1279 file->Language = msi_dup_record_field( row, 6 );
1280 file->Attributes = MSI_RecordGetInteger( row, 7 );
1281 file->Sequence = MSI_RecordGetInteger( row, 8 );
1283 file->state = msifs_invalid;
1285 /* if the compressed bits are not set in the file attributes,
1286 * then read the information from the package word count property
1288 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1290 file->IsCompressed = FALSE;
1292 else if (file->Attributes &
1293 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1295 file->IsCompressed = TRUE;
1297 else if (file->Attributes & msidbFileAttributesNoncompressed)
1299 file->IsCompressed = FALSE;
1303 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1306 load_file_hash(package, file);
1307 load_file_disk_id(package, file);
1309 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1311 list_add_tail( &package->files, &file->entry );
1313 return ERROR_SUCCESS;
1316 static UINT load_all_files(MSIPACKAGE *package)
1318 static const WCHAR query[] = {
1319 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1320 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1321 '`','S','e','q','u','e','n','c','e','`', 0};
1325 if (!list_empty(&package->files))
1326 return ERROR_SUCCESS;
1328 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1329 if (rc != ERROR_SUCCESS)
1330 return ERROR_SUCCESS;
1332 rc = MSI_IterateRecords(view, NULL, load_file, package);
1333 msiobj_release(&view->hdr);
1337 static UINT load_media( MSIRECORD *row, LPVOID param )
1339 MSIPACKAGE *package = param;
1340 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1341 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1343 /* FIXME: load external cabinets and directory sources too */
1344 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1345 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1346 return ERROR_SUCCESS;
1349 static UINT load_all_media( MSIPACKAGE *package )
1351 static const WCHAR query[] = {
1352 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1353 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1354 '`','D','i','s','k','I','d','`',0};
1358 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1359 if (r != ERROR_SUCCESS)
1360 return ERROR_SUCCESS;
1362 r = MSI_IterateRecords( view, NULL, load_media, package );
1363 msiobj_release( &view->hdr );
1367 static UINT load_patch(MSIRECORD *row, LPVOID param)
1369 MSIPACKAGE *package = param;
1370 MSIFILEPATCH *patch;
1373 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1375 return ERROR_NOT_ENOUGH_MEMORY;
1377 file_key = msi_dup_record_field( row, 1 );
1378 patch->File = msi_get_loaded_file( package, file_key );
1383 ERR("Failed to find target for patch in File table\n");
1385 return ERROR_FUNCTION_FAILED;
1388 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1390 /* FIXME: The database should be properly transformed */
1391 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1393 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1394 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1395 patch->IsApplied = FALSE;
1398 * Header field - for patch validation.
1399 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1402 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1404 list_add_tail( &package->filepatches, &patch->entry );
1406 return ERROR_SUCCESS;
1409 static UINT load_all_patches(MSIPACKAGE *package)
1411 static const WCHAR query[] = {
1412 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1413 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1414 '`','S','e','q','u','e','n','c','e','`',0};
1418 if (!list_empty(&package->filepatches))
1419 return ERROR_SUCCESS;
1421 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1422 if (rc != ERROR_SUCCESS)
1423 return ERROR_SUCCESS;
1425 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1426 msiobj_release(&view->hdr);
1430 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1432 static const WCHAR query[] = {
1433 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1434 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1435 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1438 folder->persistent = FALSE;
1439 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1441 if (!MSI_ViewExecute( view, NULL ))
1444 if (!MSI_ViewFetch( view, &rec ))
1446 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1447 folder->persistent = TRUE;
1448 msiobj_release( &rec->hdr );
1451 msiobj_release( &view->hdr );
1453 return ERROR_SUCCESS;
1456 static UINT load_folder( MSIRECORD *row, LPVOID param )
1458 MSIPACKAGE *package = param;
1459 static WCHAR szEmpty[] = { 0 };
1460 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1463 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1464 list_init( &folder->children );
1465 folder->Directory = msi_dup_record_field( row, 1 );
1466 folder->Parent = msi_dup_record_field( row, 2 );
1467 p = msi_dup_record_field(row, 3);
1469 TRACE("%s\n", debugstr_w(folder->Directory));
1471 /* split src and target dir */
1473 src_short = folder_split_path( p, ':' );
1475 /* split the long and short paths */
1476 tgt_long = folder_split_path( tgt_short, '|' );
1477 src_long = folder_split_path( src_short, '|' );
1479 /* check for no-op dirs */
1480 if (tgt_short && !strcmpW( szDot, tgt_short ))
1481 tgt_short = szEmpty;
1482 if (src_short && !strcmpW( szDot, src_short ))
1483 src_short = szEmpty;
1486 tgt_long = tgt_short;
1489 src_short = tgt_short;
1490 src_long = tgt_long;
1494 src_long = src_short;
1496 /* FIXME: use the target short path too */
1497 folder->TargetDefault = strdupW(tgt_long);
1498 folder->SourceShortPath = strdupW(src_short);
1499 folder->SourceLongPath = strdupW(src_long);
1502 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1503 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1504 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1506 load_folder_persistence( package, folder );
1508 list_add_tail( &package->folders, &folder->entry );
1509 return ERROR_SUCCESS;
1512 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1516 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1518 list_add_tail( &parent->children, &fl->entry );
1519 return ERROR_SUCCESS;
1522 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1524 MSIPACKAGE *package = param;
1525 MSIFOLDER *parent, *child;
1527 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1528 return ERROR_FUNCTION_FAILED;
1530 if (!child->Parent) return ERROR_SUCCESS;
1532 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1533 return ERROR_FUNCTION_FAILED;
1535 return add_folder_child( parent, child );
1538 static UINT load_all_folders( MSIPACKAGE *package )
1540 static const WCHAR query[] = {
1541 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1542 '`','D','i','r','e','c','t','o','r','y','`',0};
1546 if (!list_empty(&package->folders))
1547 return ERROR_SUCCESS;
1549 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1550 if (r != ERROR_SUCCESS)
1553 r = MSI_IterateRecords( view, NULL, load_folder, package );
1554 if (r != ERROR_SUCCESS)
1556 msiobj_release( &view->hdr );
1559 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1560 msiobj_release( &view->hdr );
1564 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1566 msi_set_property( package->db, szCostingComplete, szZero );
1567 msi_set_property( package->db, szRootDrive, szCRoot );
1569 load_all_folders( package );
1570 msi_load_all_components( package );
1571 msi_load_all_features( package );
1572 load_all_files( package );
1573 load_all_patches( package );
1574 load_all_media( package );
1576 return ERROR_SUCCESS;
1579 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1581 const WCHAR *action = package->script->Actions[script][index];
1582 ui_actionstart( package, action );
1583 TRACE("executing %s\n", debugstr_w(action));
1584 return ACTION_PerformAction( package, action, script );
1587 static UINT execute_script( MSIPACKAGE *package, UINT script )
1589 UINT i, rc = ERROR_SUCCESS;
1591 TRACE("executing script %u\n", script);
1593 if (!package->script)
1595 ERR("no script!\n");
1596 return ERROR_FUNCTION_FAILED;
1598 if (script == SCRIPT_ROLLBACK)
1600 for (i = package->script->ActionCount[script]; i > 0; i--)
1602 rc = execute_script_action( package, script, i - 1 );
1603 if (rc != ERROR_SUCCESS) break;
1608 for (i = 0; i < package->script->ActionCount[script]; i++)
1610 rc = execute_script_action( package, script, i );
1611 if (rc != ERROR_SUCCESS) break;
1614 msi_free_action_script(package, script);
1618 static UINT ACTION_FileCost(MSIPACKAGE *package)
1620 return ERROR_SUCCESS;
1623 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1628 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1630 if (!comp->ComponentId) continue;
1632 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1633 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1635 if (r == ERROR_SUCCESS) continue;
1637 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1638 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1640 if (r == ERROR_SUCCESS) continue;
1642 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1643 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1645 if (r == ERROR_SUCCESS) continue;
1647 comp->Installed = INSTALLSTATE_ABSENT;
1651 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1653 MSIFEATURE *feature;
1655 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1657 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1659 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1660 feature->Installed = INSTALLSTATE_ABSENT;
1662 feature->Installed = state;
1666 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1668 return (feature->Level > 0 && feature->Level <= level);
1671 static BOOL process_state_property(MSIPACKAGE* package, int level,
1672 LPCWSTR property, INSTALLSTATE state)
1675 MSIFEATURE *feature;
1677 override = msi_dup_property( package->db, property );
1681 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1686 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1688 if (!strcmpiW( override, szAll ))
1690 if (feature->Installed != state)
1692 feature->Action = state;
1693 feature->ActionRequest = state;
1698 LPWSTR ptr = override;
1699 LPWSTR ptr2 = strchrW(override,',');
1703 int len = ptr2 - ptr;
1705 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1706 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1708 if (feature->Installed != state)
1710 feature->Action = state;
1711 feature->ActionRequest = state;
1718 ptr2 = strchrW(ptr,',');
1729 static BOOL process_overrides( MSIPACKAGE *package, int level )
1731 static const WCHAR szAddLocal[] =
1732 {'A','D','D','L','O','C','A','L',0};
1733 static const WCHAR szAddSource[] =
1734 {'A','D','D','S','O','U','R','C','E',0};
1735 static const WCHAR szAdvertise[] =
1736 {'A','D','V','E','R','T','I','S','E',0};
1739 /* all these activation/deactivation things happen in order and things
1740 * later on the list override things earlier on the list.
1742 * 0 INSTALLLEVEL processing
1755 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1756 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1757 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1758 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1759 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1762 msi_set_property( package->db, szPreselected, szOne );
1767 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1770 MSICOMPONENT* component;
1771 MSIFEATURE *feature;
1773 TRACE("Checking Install Level\n");
1775 level = msi_get_property_int(package->db, szInstallLevel, 1);
1777 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1779 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1781 if (!is_feature_selected( feature, level )) continue;
1783 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1785 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1787 feature->Action = INSTALLSTATE_SOURCE;
1788 feature->ActionRequest = INSTALLSTATE_SOURCE;
1790 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1792 feature->Action = INSTALLSTATE_ADVERTISED;
1793 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1797 feature->Action = INSTALLSTATE_LOCAL;
1798 feature->ActionRequest = INSTALLSTATE_LOCAL;
1802 /* disable child features of unselected parent or follow parent */
1803 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1807 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1809 if (!is_feature_selected( feature, level ))
1811 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1812 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1814 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1816 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1817 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1818 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1819 fl->feature->Action = feature->Action;
1820 fl->feature->ActionRequest = feature->ActionRequest;
1825 else /* preselected */
1827 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1829 if (!is_feature_selected( feature, level )) continue;
1831 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1833 if (feature->Installed == INSTALLSTATE_ABSENT)
1835 feature->Action = INSTALLSTATE_UNKNOWN;
1836 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1840 feature->Action = feature->Installed;
1841 feature->ActionRequest = feature->Installed;
1845 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1849 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1851 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1852 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1854 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1855 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1856 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1857 fl->feature->Action = feature->Action;
1858 fl->feature->ActionRequest = feature->ActionRequest;
1864 /* now we want to set component state based based on feature state */
1865 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1869 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1870 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1871 feature->ActionRequest, feature->Action);
1873 if (!is_feature_selected( feature, level )) continue;
1875 /* features with components that have compressed files are made local */
1876 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1878 if (cl->component->ForceLocalState &&
1879 feature->ActionRequest == INSTALLSTATE_SOURCE)
1881 feature->Action = INSTALLSTATE_LOCAL;
1882 feature->ActionRequest = INSTALLSTATE_LOCAL;
1887 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1889 component = cl->component;
1891 switch (feature->ActionRequest)
1893 case INSTALLSTATE_ABSENT:
1894 component->anyAbsent = 1;
1896 case INSTALLSTATE_ADVERTISED:
1897 component->hasAdvertiseFeature = 1;
1899 case INSTALLSTATE_SOURCE:
1900 component->hasSourceFeature = 1;
1902 case INSTALLSTATE_LOCAL:
1903 component->hasLocalFeature = 1;
1905 case INSTALLSTATE_DEFAULT:
1906 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1907 component->hasAdvertiseFeature = 1;
1908 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1909 component->hasSourceFeature = 1;
1911 component->hasLocalFeature = 1;
1919 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1921 /* check if it's local or source */
1922 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1923 (component->hasLocalFeature || component->hasSourceFeature))
1925 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1926 !component->ForceLocalState)
1928 component->Action = INSTALLSTATE_SOURCE;
1929 component->ActionRequest = INSTALLSTATE_SOURCE;
1933 component->Action = INSTALLSTATE_LOCAL;
1934 component->ActionRequest = INSTALLSTATE_LOCAL;
1939 /* if any feature is local, the component must be local too */
1940 if (component->hasLocalFeature)
1942 component->Action = INSTALLSTATE_LOCAL;
1943 component->ActionRequest = INSTALLSTATE_LOCAL;
1946 if (component->hasSourceFeature)
1948 component->Action = INSTALLSTATE_SOURCE;
1949 component->ActionRequest = INSTALLSTATE_SOURCE;
1952 if (component->hasAdvertiseFeature)
1954 component->Action = INSTALLSTATE_ADVERTISED;
1955 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1958 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1959 if (component->anyAbsent &&
1960 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1962 component->Action = INSTALLSTATE_ABSENT;
1963 component->ActionRequest = INSTALLSTATE_ABSENT;
1967 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1969 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1971 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1972 component->Action = INSTALLSTATE_LOCAL;
1973 component->ActionRequest = INSTALLSTATE_LOCAL;
1976 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1977 component->Installed == INSTALLSTATE_SOURCE &&
1978 component->hasSourceFeature)
1980 component->Action = INSTALLSTATE_UNKNOWN;
1981 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1984 TRACE("component %s (installed %d request %d action %d)\n",
1985 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1988 return ERROR_SUCCESS;
1991 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1993 MSIPACKAGE *package = param;
1995 MSIFEATURE *feature;
1997 name = MSI_RecordGetString( row, 1 );
1999 feature = msi_get_loaded_feature( package, name );
2001 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2005 Condition = MSI_RecordGetString(row,3);
2007 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2009 int level = MSI_RecordGetInteger(row,2);
2010 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2011 feature->Level = level;
2014 return ERROR_SUCCESS;
2017 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2019 static const WCHAR name[] = {'\\',0};
2020 VS_FIXEDFILEINFO *ptr, *ret;
2022 DWORD versize, handle;
2025 versize = GetFileVersionInfoSizeW( filename, &handle );
2029 version = msi_alloc( versize );
2033 GetFileVersionInfoW( filename, 0, versize, version );
2035 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2037 msi_free( version );
2041 ret = msi_alloc( sz );
2042 memcpy( ret, ptr, sz );
2044 msi_free( version );
2048 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2052 msi_parse_version_string( version, &ms, &ls );
2054 if (fi->dwFileVersionMS > ms) return 1;
2055 else if (fi->dwFileVersionMS < ms) return -1;
2056 else if (fi->dwFileVersionLS > ls) return 1;
2057 else if (fi->dwFileVersionLS < ls) return -1;
2061 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2065 msi_parse_version_string( ver1, &ms1, NULL );
2066 msi_parse_version_string( ver2, &ms2, NULL );
2068 if (ms1 > ms2) return 1;
2069 else if (ms1 < ms2) return -1;
2073 DWORD msi_get_disk_file_size( LPCWSTR filename )
2078 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2079 if (file == INVALID_HANDLE_VALUE)
2080 return INVALID_FILE_SIZE;
2082 size = GetFileSize( file, NULL );
2083 TRACE("size is %u\n", size);
2084 CloseHandle( file );
2088 BOOL msi_file_hash_matches( MSIFILE *file )
2091 MSIFILEHASHINFO hash;
2093 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2094 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2095 if (r != ERROR_SUCCESS)
2098 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2101 static WCHAR *get_temp_dir( void )
2104 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2106 GetTempPathW( MAX_PATH, tmp );
2109 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2110 if (CreateDirectoryW( dir, NULL )) break;
2112 return strdupW( dir );
2116 * msi_build_directory_name()
2118 * This function is to save messing round with directory names
2119 * It handles adding backslashes between path segments,
2120 * and can add \ at the end of the directory name if told to.
2122 * It takes a variable number of arguments.
2123 * It always allocates a new string for the result, so make sure
2124 * to free the return value when finished with it.
2126 * The first arg is the number of path segments that follow.
2127 * The arguments following count are a list of path segments.
2128 * A path segment may be NULL.
2130 * Path segments will be added with a \ separating them.
2131 * A \ will not be added after the last segment, however if the
2132 * last segment is NULL, then the last character will be a \
2134 WCHAR *msi_build_directory_name( DWORD count, ... )
2140 va_start( va, count );
2141 for (i = 0; i < count; i++)
2143 const WCHAR *str = va_arg( va, const WCHAR * );
2144 if (str) sz += strlenW( str ) + 1;
2148 dir = msi_alloc( sz * sizeof(WCHAR) );
2151 va_start( va, count );
2152 for (i = 0; i < count; i++)
2154 const WCHAR *str = va_arg( va, const WCHAR * );
2156 strcatW( dir, str );
2157 if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2163 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2165 MSIASSEMBLY *assembly = file->Component->assembly;
2167 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2169 msi_free( file->TargetPath );
2170 if (assembly && !assembly->application)
2172 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2173 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2174 msi_track_tempfile( package, file->TargetPath );
2178 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2179 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2182 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2185 static UINT calculate_file_cost( MSIPACKAGE *package )
2187 VS_FIXEDFILEINFO *file_version;
2188 WCHAR *font_version;
2191 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2193 MSICOMPONENT *comp = file->Component;
2196 if (!comp->Enabled) continue;
2198 if (file->IsCompressed)
2199 comp->ForceLocalState = TRUE;
2201 set_target_path( package, file );
2203 if ((comp->assembly && !comp->assembly->installed) ||
2204 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2206 comp->Cost += file->FileSize;
2209 file_size = msi_get_disk_file_size( file->TargetPath );
2213 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2215 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2217 comp->Cost += file->FileSize - file_size;
2219 msi_free( file_version );
2222 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2224 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2226 comp->Cost += file->FileSize - file_size;
2228 msi_free( font_version );
2232 if (file_size != file->FileSize)
2234 comp->Cost += file->FileSize - file_size;
2237 return ERROR_SUCCESS;
2240 WCHAR *msi_normalize_path( const WCHAR *in )
2242 const WCHAR *p = in;
2244 int n, len = strlenW( in ) + 2;
2246 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2251 /* copy until the end of the string or a space */
2252 while (*p != ' ' && (*q = *p))
2255 /* reduce many backslashes to one */
2256 if (*p != '\\' || *q != '\\')
2260 /* quit at the end of the string */
2264 /* count the number of spaces */
2269 /* if it's leading or trailing space, skip it */
2270 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2272 else /* copy n spaces */
2273 while (n && (*q++ = *p++)) n--;
2275 while (q - ret > 0 && q[-1] == ' ') q--;
2276 if (q - ret > 0 && q[-1] != '\\')
2284 static WCHAR *get_install_location( MSIPACKAGE *package )
2289 if (!package->ProductCode) return NULL;
2290 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ))
2292 path = msi_reg_get_val_str( hkey, szInstallLocation );
2293 RegCloseKey( hkey );
2297 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2300 MSIFOLDER *folder, *parent, *child;
2301 WCHAR *path, *normalized_path;
2303 TRACE("resolving %s\n", debugstr_w(name));
2305 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2307 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2309 if (!(path = get_install_location( package )) &&
2310 (!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))))
2312 path = msi_dup_property( package->db, szRootDrive );
2315 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2317 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2319 parent = msi_get_loaded_folder( package, folder->Parent );
2320 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2323 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2325 normalized_path = msi_normalize_path( path );
2327 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2329 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2330 msi_free( normalized_path );
2333 msi_set_property( package->db, folder->Directory, normalized_path );
2334 msi_free( folder->ResolvedTarget );
2335 folder->ResolvedTarget = normalized_path;
2337 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2340 msi_resolve_target_folder( package, child->Directory, load_prop );
2342 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2345 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2347 static const WCHAR query[] = {
2348 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2349 '`','C','o','n','d','i','t','i','o','n','`',0};
2350 static const WCHAR szOutOfDiskSpace[] = {
2351 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2357 TRACE("Building directory properties\n");
2358 msi_resolve_target_folder( package, szTargetDir, TRUE );
2360 TRACE("Evaluating component conditions\n");
2361 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2363 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2365 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2366 comp->Enabled = FALSE;
2369 comp->Enabled = TRUE;
2372 /* read components states from the registry */
2373 ACTION_GetComponentInstallStates(package);
2374 ACTION_GetFeatureInstallStates(package);
2376 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2378 TRACE("Evaluating feature conditions\n");
2380 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2381 if (rc == ERROR_SUCCESS)
2383 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2384 msiobj_release( &view->hdr );
2385 if (rc != ERROR_SUCCESS)
2390 TRACE("Calculating file cost\n");
2391 calculate_file_cost( package );
2393 msi_set_property( package->db, szCostingComplete, szOne );
2394 /* set default run level if not set */
2395 level = msi_dup_property( package->db, szInstallLevel );
2397 msi_set_property( package->db, szInstallLevel, szOne );
2400 /* FIXME: check volume disk space */
2401 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2403 return MSI_SetFeatureStates(package);
2406 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, DWORD *size)
2412 data = (LPSTR)strdupW(szEmpty);
2413 *size = sizeof(szEmpty);
2417 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2423 LPWSTR deformated = NULL;
2426 deformat_string(package, &value[2], &deformated);
2428 /* binary value type */
2432 *size = (strlenW(ptr)/2)+1;
2434 *size = strlenW(ptr)/2;
2436 data = msi_alloc(*size);
2442 /* if uneven pad with a zero in front */
2448 data[count] = (BYTE)strtol(byte,NULL,0);
2450 TRACE("Uneven byte count\n");
2458 data[count] = (BYTE)strtol(byte,NULL,0);
2461 msi_free(deformated);
2463 TRACE("Data %i bytes(%i)\n",*size,count);
2470 deformat_string(package, &value[1], &deformated);
2473 *size = sizeof(DWORD);
2474 data = msi_alloc(*size);
2480 if ( (*p < '0') || (*p > '9') )
2486 if (deformated[0] == '-')
2489 TRACE("DWORD %i\n",*(LPDWORD)data);
2491 msi_free(deformated);
2496 static const WCHAR szMulti[] = {'[','~',']',0};
2505 *type=REG_EXPAND_SZ;
2513 if (strstrW(value, szMulti))
2514 *type = REG_MULTI_SZ;
2516 /* remove initial delimiter */
2517 if (!strncmpW(value, szMulti, 3))
2520 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2522 /* add double NULL terminator */
2523 if (*type == REG_MULTI_SZ)
2525 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2526 data = msi_realloc_zero(data, *size);
2532 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2539 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2541 *root_key = HKEY_LOCAL_MACHINE;
2546 *root_key = HKEY_CURRENT_USER;
2551 *root_key = HKEY_CLASSES_ROOT;
2555 *root_key = HKEY_CURRENT_USER;
2559 *root_key = HKEY_LOCAL_MACHINE;
2563 *root_key = HKEY_USERS;
2567 ERR("Unknown root %i\n", root);
2574 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2576 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2577 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2579 if ((is_64bit || is_wow64) &&
2580 !(comp->Attributes & msidbComponentAttributes64bit) &&
2581 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2586 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2587 if (!(path_32node = msi_alloc( size ))) return NULL;
2589 memcpy( path_32node, path, len * sizeof(WCHAR) );
2590 strcpyW( path_32node + len, szWow6432Node );
2591 strcatW( path_32node, szBackSlash );
2592 strcatW( path_32node, path + len );
2595 return strdupW( path );
2598 static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
2600 REGSAM access = KEY_ALL_ACCESS;
2601 WCHAR *subkey, *p, *q;
2602 HKEY hkey, ret = NULL;
2605 if (is_wow64) access |= KEY_WOW64_64KEY;
2607 if (!(subkey = strdupW( path ))) return NULL;
2609 if ((q = strchrW( p, '\\' ))) *q = 0;
2611 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2613 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2616 TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
2622 ret = open_key( hkey, q + 1, create );
2623 RegCloseKey( hkey );
2630 static BOOL is_special_entry( const WCHAR *name )
2632 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2635 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2637 MSIPACKAGE *package = param;
2639 HKEY root_key, hkey;
2641 LPWSTR deformated, uikey, keypath;
2642 LPCWSTR szRoot, component, name, key;
2646 BOOL check_first = FALSE;
2649 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2651 component = MSI_RecordGetString(row, 6);
2652 comp = msi_get_loaded_component(package,component);
2654 return ERROR_SUCCESS;
2656 comp->Action = msi_get_component_action( package, comp );
2657 if (comp->Action != INSTALLSTATE_LOCAL)
2659 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2660 return ERROR_SUCCESS;
2663 name = MSI_RecordGetString(row, 4);
2664 if( MSI_RecordIsNull(row,5) && name )
2666 /* null values can have special meanings */
2667 if (name[0]=='-' && name[1] == 0)
2668 return ERROR_SUCCESS;
2669 if ((name[0] == '+' || name[0] == '*') && !name[1])
2673 root = MSI_RecordGetInteger(row,2);
2674 key = MSI_RecordGetString(row, 3);
2676 szRoot = get_root_key( package, root, &root_key );
2678 return ERROR_SUCCESS;
2680 deformat_string(package, key , &deformated);
2681 size = strlenW(deformated) + strlenW(szRoot) + 1;
2682 uikey = msi_alloc(size*sizeof(WCHAR));
2683 strcpyW(uikey,szRoot);
2684 strcatW(uikey,deformated);
2686 keypath = get_keypath( comp, root_key, deformated );
2687 msi_free( deformated );
2688 if (!(hkey = open_key( root_key, keypath, TRUE )))
2690 ERR("Could not create key %s\n", debugstr_w(keypath));
2693 return ERROR_FUNCTION_FAILED;
2695 value = parse_value(package, MSI_RecordGetString(row, 5), &type, &size);
2696 deformat_string(package, name, &deformated);
2698 if (!is_special_entry( name ))
2702 TRACE("Setting value %s of %s\n", debugstr_w(deformated),
2704 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2709 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2710 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2712 TRACE("value %s of %s checked already exists\n", debugstr_w(deformated),
2717 TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated),
2719 if (deformated || size)
2720 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2726 uirow = MSI_CreateRecord(3);
2727 MSI_RecordSetStringW(uirow,2,deformated);
2728 MSI_RecordSetStringW(uirow,1,uikey);
2729 if (type == REG_SZ || type == REG_EXPAND_SZ)
2730 MSI_RecordSetStringW(uirow, 3, (LPWSTR)value);
2731 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2732 msiobj_release( &uirow->hdr );
2735 msi_free(deformated);
2739 return ERROR_SUCCESS;
2742 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2744 static const WCHAR query[] = {
2745 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2746 '`','R','e','g','i','s','t','r','y','`',0};
2750 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2751 if (rc != ERROR_SUCCESS)
2752 return ERROR_SUCCESS;
2754 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2755 msiobj_release(&view->hdr);
2759 static void delete_key( HKEY root, const WCHAR *path )
2766 if (is_wow64) access |= KEY_WOW64_64KEY;
2768 if (!(subkey = strdupW( path ))) return;
2771 if ((p = strrchrW( subkey, '\\' ))) *p = 0;
2772 hkey = open_key( root, subkey, FALSE );
2775 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2777 res = RegDeleteKeyExW( root, subkey, access, 0 );
2780 TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
2783 if (p && p[1]) RegCloseKey( hkey );
2789 static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
2793 DWORD num_subkeys, num_values;
2795 if ((hkey = open_key( root, path, FALSE )))
2797 if ((res = RegDeleteValueW( hkey, value )))
2798 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2800 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2801 NULL, NULL, NULL, NULL );
2802 RegCloseKey( hkey );
2803 if (!res && !num_subkeys && !num_values)
2805 TRACE("removing empty key %s\n", debugstr_w(path));
2806 delete_key( root, path );
2811 static void delete_tree( HKEY root, const WCHAR *path )
2816 if (!(hkey = open_key( root, path, FALSE ))) return;
2817 res = RegDeleteTreeW( hkey, NULL );
2818 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
2819 delete_key( root, path );
2820 RegCloseKey( hkey );
2823 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2825 MSIPACKAGE *package = param;
2826 LPCWSTR component, name, key_str, root_key_str;
2827 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2830 BOOL delete_key = FALSE;
2835 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2837 component = MSI_RecordGetString( row, 6 );
2838 comp = msi_get_loaded_component( package, component );
2840 return ERROR_SUCCESS;
2842 comp->Action = msi_get_component_action( package, comp );
2843 if (comp->Action != INSTALLSTATE_ABSENT)
2845 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2846 return ERROR_SUCCESS;
2849 name = MSI_RecordGetString( row, 4 );
2850 if (MSI_RecordIsNull( row, 5 ) && name )
2852 if (name[0] == '+' && !name[1])
2853 return ERROR_SUCCESS;
2854 if ((name[0] == '-' || name[0] == '*') && !name[1])
2861 root = MSI_RecordGetInteger( row, 2 );
2862 key_str = MSI_RecordGetString( row, 3 );
2864 root_key_str = get_root_key( package, root, &hkey_root );
2866 return ERROR_SUCCESS;
2868 deformat_string( package, key_str, &deformated_key );
2869 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2870 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2871 strcpyW( ui_key_str, root_key_str );
2872 strcatW( ui_key_str, deformated_key );
2874 deformat_string( package, name, &deformated_name );
2876 keypath = get_keypath( comp, hkey_root, deformated_key );
2877 msi_free( deformated_key );
2878 if (delete_key) delete_tree( hkey_root, keypath );
2879 else delete_value( hkey_root, keypath, deformated_name );
2880 msi_free( keypath );
2882 uirow = MSI_CreateRecord( 2 );
2883 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2884 MSI_RecordSetStringW( uirow, 2, deformated_name );
2885 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2886 msiobj_release( &uirow->hdr );
2888 msi_free( ui_key_str );
2889 msi_free( deformated_name );
2890 return ERROR_SUCCESS;
2893 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2895 MSIPACKAGE *package = param;
2896 LPCWSTR component, name, key_str, root_key_str;
2897 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2900 BOOL delete_key = FALSE;
2905 component = MSI_RecordGetString( row, 5 );
2906 comp = msi_get_loaded_component( package, component );
2908 return ERROR_SUCCESS;
2910 comp->Action = msi_get_component_action( package, comp );
2911 if (comp->Action != INSTALLSTATE_LOCAL)
2913 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2914 return ERROR_SUCCESS;
2917 if ((name = MSI_RecordGetString( row, 4 )))
2919 if (name[0] == '-' && !name[1])
2926 root = MSI_RecordGetInteger( row, 2 );
2927 key_str = MSI_RecordGetString( row, 3 );
2929 root_key_str = get_root_key( package, root, &hkey_root );
2931 return ERROR_SUCCESS;
2933 deformat_string( package, key_str, &deformated_key );
2934 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2935 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2936 strcpyW( ui_key_str, root_key_str );
2937 strcatW( ui_key_str, deformated_key );
2939 deformat_string( package, name, &deformated_name );
2941 keypath = get_keypath( comp, hkey_root, deformated_key );
2942 msi_free( deformated_key );
2943 if (delete_key) delete_tree( hkey_root, keypath );
2944 else delete_value( hkey_root, keypath, deformated_name );
2945 msi_free( keypath );
2947 uirow = MSI_CreateRecord( 2 );
2948 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2949 MSI_RecordSetStringW( uirow, 2, deformated_name );
2950 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2951 msiobj_release( &uirow->hdr );
2953 msi_free( ui_key_str );
2954 msi_free( deformated_name );
2955 return ERROR_SUCCESS;
2958 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2960 static const WCHAR registry_query[] = {
2961 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2962 '`','R','e','g','i','s','t','r','y','`',0};
2963 static const WCHAR remove_registry_query[] = {
2964 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2965 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2969 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2970 if (rc == ERROR_SUCCESS)
2972 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2973 msiobj_release( &view->hdr );
2974 if (rc != ERROR_SUCCESS)
2977 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2978 if (rc == ERROR_SUCCESS)
2980 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2981 msiobj_release( &view->hdr );
2982 if (rc != ERROR_SUCCESS)
2985 return ERROR_SUCCESS;
2988 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2990 package->script->CurrentlyScripting = TRUE;
2992 return ERROR_SUCCESS;
2996 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2998 static const WCHAR query[]= {
2999 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3000 '`','R','e','g','i','s','t','r','y','`',0};
3002 DWORD total = 0, count = 0;
3004 MSIFEATURE *feature;
3008 TRACE("InstallValidate\n");
3010 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3011 if (rc == ERROR_SUCCESS)
3013 rc = MSI_IterateRecords( view, &count, NULL, package );
3014 msiobj_release( &view->hdr );
3015 if (rc != ERROR_SUCCESS)
3017 total += count * REG_PROGRESS_VALUE;
3019 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3020 total += COMPONENT_PROGRESS_VALUE;
3022 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3023 total += file->FileSize;
3025 msi_ui_progress( package, 0, total, 0, 0 );
3027 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3029 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3030 debugstr_w(feature->Feature), feature->Installed,
3031 feature->ActionRequest, feature->Action);
3033 return ERROR_SUCCESS;
3036 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3038 MSIPACKAGE* package = param;
3039 LPCWSTR cond = NULL;
3040 LPCWSTR message = NULL;
3043 static const WCHAR title[]=
3044 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3046 cond = MSI_RecordGetString(row,1);
3048 r = MSI_EvaluateConditionW(package,cond);
3049 if (r == MSICONDITION_FALSE)
3051 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3054 message = MSI_RecordGetString(row,2);
3055 deformat_string(package,message,&deformated);
3056 MessageBoxW(NULL,deformated,title,MB_OK);
3057 msi_free(deformated);
3060 return ERROR_INSTALL_FAILURE;
3063 return ERROR_SUCCESS;
3066 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3068 static const WCHAR query[] = {
3069 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3070 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3074 TRACE("Checking launch conditions\n");
3076 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3077 if (rc != ERROR_SUCCESS)
3078 return ERROR_SUCCESS;
3080 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3081 msiobj_release(&view->hdr);
3085 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3089 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3091 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3093 static const WCHAR query[] = {
3094 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3095 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3096 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3097 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3098 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3101 LPWSTR deformated, buffer, deformated_name;
3104 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3108 root = MSI_RecordGetInteger(row,2);
3109 key = MSI_RecordGetString(row, 3);
3110 name = MSI_RecordGetString(row, 4);
3111 deformat_string(package, key , &deformated);
3112 deformat_string(package, name, &deformated_name);
3114 len = strlenW(deformated) + 6;
3115 if (deformated_name)
3116 len+=strlenW(deformated_name);
3118 buffer = msi_alloc( len *sizeof(WCHAR));
3120 if (deformated_name)
3121 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3123 sprintfW(buffer,fmt,root,deformated);
3125 msi_free(deformated);
3126 msi_free(deformated_name);
3127 msiobj_release(&row->hdr);
3131 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3133 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3138 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3141 return strdupW( file->TargetPath );
3146 static HKEY openSharedDLLsKey(void)
3149 static const WCHAR path[] =
3150 {'S','o','f','t','w','a','r','e','\\',
3151 'M','i','c','r','o','s','o','f','t','\\',
3152 'W','i','n','d','o','w','s','\\',
3153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3154 'S','h','a','r','e','d','D','L','L','s',0};
3156 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3160 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3165 DWORD sz = sizeof(count);
3168 hkey = openSharedDLLsKey();
3169 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3170 if (rc != ERROR_SUCCESS)
3176 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3180 hkey = openSharedDLLsKey();
3182 msi_reg_set_val_dword( hkey, path, count );
3184 RegDeleteValueW(hkey,path);
3189 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3191 MSIFEATURE *feature;
3195 /* only refcount DLLs */
3196 if (comp->KeyPath == NULL ||
3198 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3199 comp->Attributes & msidbComponentAttributesODBCDataSource)
3203 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3204 write = (count > 0);
3206 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3210 /* increment counts */
3211 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3215 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3218 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3220 if ( cl->component == comp )
3225 /* decrement counts */
3226 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3230 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3233 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3235 if ( cl->component == comp )
3240 /* ref count all the files in the component */
3245 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3247 if (file->Component == comp)
3248 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3252 /* add a count for permanent */
3253 if (comp->Attributes & msidbComponentAttributesPermanent)
3256 comp->RefCount = count;
3259 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3262 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3266 const WCHAR prefixW[] = {'<','\\',0};
3267 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3268 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3272 strcpyW( keypath, prefixW );
3273 strcatW( keypath, comp->assembly->display_name );
3277 return resolve_keypath( package, comp );
3280 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3282 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3289 squash_guid(package->ProductCode,squished_pc);
3290 msi_set_sourcedir_props(package, FALSE);
3292 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3295 INSTALLSTATE action;
3297 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3298 if (!comp->ComponentId)
3301 squash_guid( comp->ComponentId, squished_cc );
3302 msi_free( comp->FullKeypath );
3303 comp->FullKeypath = build_full_keypath( package, comp );
3305 ACTION_RefCountComponent( package, comp );
3307 if (package->need_rollback) action = comp->Installed;
3308 else action = comp->ActionRequest;
3310 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3311 debugstr_w(comp->Component), debugstr_w(squished_cc),
3312 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3314 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3316 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3317 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3319 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3321 if (rc != ERROR_SUCCESS)
3324 if (comp->Attributes & msidbComponentAttributesPermanent)
3326 static const WCHAR szPermKey[] =
3327 { '0','0','0','0','0','0','0','0','0','0','0','0',
3328 '0','0','0','0','0','0','0','0','0','0','0','0',
3329 '0','0','0','0','0','0','0','0',0 };
3331 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3333 if (action == INSTALLSTATE_LOCAL)
3334 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3340 WCHAR source[MAX_PATH];
3341 WCHAR base[MAX_PATH];
3344 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3345 static const WCHAR query[] = {
3346 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3347 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3348 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3349 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3350 '`','D','i','s','k','I','d','`',0};
3352 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3355 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3356 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3357 ptr2 = strrchrW(source, '\\') + 1;
3358 msiobj_release(&row->hdr);
3360 lstrcpyW(base, package->PackagePath);
3361 ptr = strrchrW(base, '\\');
3364 sourcepath = msi_resolve_file_source(package, file);
3365 ptr = sourcepath + lstrlenW(base);
3366 lstrcpyW(ptr2, ptr);
3367 msi_free(sourcepath);
3369 msi_reg_set_val_str(hkey, squished_pc, source);
3373 else if (action == INSTALLSTATE_ABSENT)
3375 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3376 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3378 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3382 uirow = MSI_CreateRecord(3);
3383 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3384 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3385 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3386 msi_ui_actiondata( package, szProcessComponents, uirow );
3387 msiobj_release( &uirow->hdr );
3389 return ERROR_SUCCESS;
3400 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3401 LPWSTR lpszName, LONG_PTR lParam)
3404 typelib_struct *tl_struct = (typelib_struct*) lParam;
3405 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3409 if (!IS_INTRESOURCE(lpszName))
3411 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3415 sz = strlenW(tl_struct->source)+4;
3416 sz *= sizeof(WCHAR);
3418 if ((INT_PTR)lpszName == 1)
3419 tl_struct->path = strdupW(tl_struct->source);
3422 tl_struct->path = msi_alloc(sz);
3423 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3426 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3427 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3430 msi_free(tl_struct->path);
3431 tl_struct->path = NULL;
3436 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3437 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3439 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3443 msi_free(tl_struct->path);
3444 tl_struct->path = NULL;
3446 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3447 ITypeLib_Release(tl_struct->ptLib);
3452 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3454 MSIPACKAGE* package = param;
3458 typelib_struct tl_struct;
3463 component = MSI_RecordGetString(row,3);
3464 comp = msi_get_loaded_component(package,component);
3466 return ERROR_SUCCESS;
3468 comp->Action = msi_get_component_action( package, comp );
3469 if (comp->Action != INSTALLSTATE_LOCAL)
3471 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3472 return ERROR_SUCCESS;
3475 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3477 TRACE("component has no key path\n");
3478 return ERROR_SUCCESS;
3480 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3482 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3486 guid = MSI_RecordGetString(row,1);
3487 CLSIDFromString( guid, &tl_struct.clsid);
3488 tl_struct.source = strdupW( file->TargetPath );
3489 tl_struct.path = NULL;
3491 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3492 (LONG_PTR)&tl_struct);
3496 LPCWSTR helpid, help_path = NULL;
3499 helpid = MSI_RecordGetString(row,6);
3501 if (helpid) help_path = msi_get_target_folder( package, helpid );
3502 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3505 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3507 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3509 ITypeLib_Release(tl_struct.ptLib);
3510 msi_free(tl_struct.path);
3512 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3514 FreeLibrary(module);
3515 msi_free(tl_struct.source);
3519 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3522 ERR("Failed to load type library: %08x\n", hr);
3523 return ERROR_INSTALL_FAILURE;
3526 ITypeLib_Release(tlib);
3529 return ERROR_SUCCESS;
3532 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3534 static const WCHAR query[] = {
3535 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3536 '`','T','y','p','e','L','i','b','`',0};
3540 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3541 if (rc != ERROR_SUCCESS)
3542 return ERROR_SUCCESS;
3544 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3545 msiobj_release(&view->hdr);
3549 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3551 MSIPACKAGE *package = param;
3552 LPCWSTR component, guid;
3560 component = MSI_RecordGetString( row, 3 );
3561 comp = msi_get_loaded_component( package, component );
3563 return ERROR_SUCCESS;
3565 comp->Action = msi_get_component_action( package, comp );
3566 if (comp->Action != INSTALLSTATE_ABSENT)
3568 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3569 return ERROR_SUCCESS;
3571 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3573 guid = MSI_RecordGetString( row, 1 );
3574 CLSIDFromString( guid, &libid );
3575 version = MSI_RecordGetInteger( row, 4 );
3576 language = MSI_RecordGetInteger( row, 2 );
3579 syskind = SYS_WIN64;
3581 syskind = SYS_WIN32;
3584 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3587 WARN("Failed to unregister typelib: %08x\n", hr);
3590 return ERROR_SUCCESS;
3593 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3595 static const WCHAR query[] = {
3596 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3597 '`','T','y','p','e','L','i','b','`',0};
3601 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3602 if (rc != ERROR_SUCCESS)
3603 return ERROR_SUCCESS;
3605 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3606 msiobj_release( &view->hdr );
3610 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3612 static const WCHAR szlnk[] = {'.','l','n','k',0};
3613 LPCWSTR directory, extension, link_folder;
3614 LPWSTR link_file, filename;
3616 directory = MSI_RecordGetString( row, 2 );
3617 link_folder = msi_get_target_folder( package, directory );
3620 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3623 /* may be needed because of a bug somewhere else */
3624 msi_create_full_path( link_folder );
3626 filename = msi_dup_record_field( row, 3 );
3627 msi_reduce_to_long_filename( filename );
3629 extension = strchrW( filename, '.' );
3630 if (!extension || strcmpiW( extension, szlnk ))
3632 int len = strlenW( filename );
3633 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3634 memcpy( filename + len, szlnk, sizeof(szlnk) );
3636 link_file = msi_build_directory_name( 2, link_folder, filename );
3637 msi_free( filename );
3642 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3644 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3645 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3646 WCHAR *folder, *dest, *path;
3648 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3649 folder = msi_dup_property( package->db, szWindowsFolder );
3652 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3653 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3654 msi_free( appdata );
3656 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3657 msi_create_full_path( dest );
3658 path = msi_build_directory_name( 2, dest, icon_name );
3664 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3666 MSIPACKAGE *package = param;
3667 LPWSTR link_file, deformated, path;
3668 LPCWSTR component, target;
3670 IShellLinkW *sl = NULL;
3671 IPersistFile *pf = NULL;
3674 component = MSI_RecordGetString(row, 4);
3675 comp = msi_get_loaded_component(package, component);
3677 return ERROR_SUCCESS;
3679 comp->Action = msi_get_component_action( package, comp );
3680 if (comp->Action != INSTALLSTATE_LOCAL)
3682 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3683 return ERROR_SUCCESS;
3685 msi_ui_actiondata( package, szCreateShortcuts, row );
3687 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3688 &IID_IShellLinkW, (LPVOID *) &sl );
3692 ERR("CLSID_ShellLink not available\n");
3696 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3699 ERR("QueryInterface(IID_IPersistFile) failed\n");
3703 target = MSI_RecordGetString(row, 5);
3704 if (strchrW(target, '['))
3706 deformat_string( package, target, &path );
3707 TRACE("target path is %s\n", debugstr_w(path));
3708 IShellLinkW_SetPath( sl, path );
3713 FIXME("poorly handled shortcut format, advertised shortcut\n");
3714 IShellLinkW_SetPath(sl,comp->FullKeypath);
3717 if (!MSI_RecordIsNull(row,6))
3719 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3720 deformat_string(package, arguments, &deformated);
3721 IShellLinkW_SetArguments(sl,deformated);
3722 msi_free(deformated);
3725 if (!MSI_RecordIsNull(row,7))
3727 LPCWSTR description = MSI_RecordGetString(row, 7);
3728 IShellLinkW_SetDescription(sl, description);
3731 if (!MSI_RecordIsNull(row,8))
3732 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3734 if (!MSI_RecordIsNull(row,9))
3737 LPCWSTR icon = MSI_RecordGetString(row, 9);
3739 path = msi_build_icon_path(package, icon);
3740 index = MSI_RecordGetInteger(row,10);
3742 /* no value means 0 */
3743 if (index == MSI_NULL_INTEGER)
3746 IShellLinkW_SetIconLocation(sl, path, index);
3750 if (!MSI_RecordIsNull(row,11))
3751 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3753 if (!MSI_RecordIsNull(row,12))
3755 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3756 full_path = msi_get_target_folder( package, wkdir );
3757 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3759 link_file = get_link_file(package, row);
3761 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3762 IPersistFile_Save(pf, link_file, FALSE);
3763 msi_free(link_file);
3767 IPersistFile_Release( pf );
3769 IShellLinkW_Release( sl );
3771 return ERROR_SUCCESS;
3774 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3776 static const WCHAR query[] = {
3777 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3778 '`','S','h','o','r','t','c','u','t','`',0};
3783 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3784 if (rc != ERROR_SUCCESS)
3785 return ERROR_SUCCESS;
3787 res = CoInitialize( NULL );
3789 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3790 msiobj_release(&view->hdr);
3792 if (SUCCEEDED(res)) CoUninitialize();
3796 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3798 MSIPACKAGE *package = param;
3803 component = MSI_RecordGetString( row, 4 );
3804 comp = msi_get_loaded_component( package, component );
3806 return ERROR_SUCCESS;
3808 comp->Action = msi_get_component_action( package, comp );
3809 if (comp->Action != INSTALLSTATE_ABSENT)
3811 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3812 return ERROR_SUCCESS;
3814 msi_ui_actiondata( package, szRemoveShortcuts, row );
3816 link_file = get_link_file( package, row );
3818 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3819 if (!DeleteFileW( link_file ))
3821 WARN("Failed to remove shortcut file %u\n", GetLastError());
3823 msi_free( link_file );
3825 return ERROR_SUCCESS;
3828 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3830 static const WCHAR query[] = {
3831 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3832 '`','S','h','o','r','t','c','u','t','`',0};
3836 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3837 if (rc != ERROR_SUCCESS)
3838 return ERROR_SUCCESS;
3840 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3841 msiobj_release( &view->hdr );
3845 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3847 MSIPACKAGE* package = param;
3855 FileName = MSI_RecordGetString(row,1);
3858 ERR("Unable to get FileName\n");
3859 return ERROR_SUCCESS;
3862 FilePath = msi_build_icon_path(package, FileName);
3864 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3866 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3867 FILE_ATTRIBUTE_NORMAL, NULL);
3869 if (the_file == INVALID_HANDLE_VALUE)
3871 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3873 return ERROR_SUCCESS;
3880 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3881 if (rc != ERROR_SUCCESS)
3883 ERR("Failed to get stream\n");
3884 CloseHandle(the_file);
3885 DeleteFileW(FilePath);
3888 WriteFile(the_file,buffer,sz,&write,NULL);
3889 } while (sz == 1024);
3892 CloseHandle(the_file);
3894 return ERROR_SUCCESS;
3897 static UINT msi_publish_icons(MSIPACKAGE *package)
3899 static const WCHAR query[]= {
3900 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3901 '`','I','c','o','n','`',0};
3905 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3906 if (r == ERROR_SUCCESS)
3908 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3909 msiobj_release(&view->hdr);
3910 if (r != ERROR_SUCCESS)
3913 return ERROR_SUCCESS;
3916 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3922 MSISOURCELISTINFO *info;
3924 r = RegCreateKeyW(hkey, szSourceList, &source);
3925 if (r != ERROR_SUCCESS)
3928 RegCloseKey(source);
3930 buffer = strrchrW(package->PackagePath, '\\') + 1;
3931 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3932 package->Context, MSICODE_PRODUCT,
3933 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3934 if (r != ERROR_SUCCESS)
3937 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3938 package->Context, MSICODE_PRODUCT,
3939 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3940 if (r != ERROR_SUCCESS)
3943 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3944 package->Context, MSICODE_PRODUCT,
3945 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3946 if (r != ERROR_SUCCESS)
3949 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3951 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3952 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3953 info->options, info->value);
3955 MsiSourceListSetInfoW(package->ProductCode, NULL,
3956 info->context, info->options,
3957 info->property, info->value);
3960 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3962 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3963 disk->context, disk->options,
3964 disk->disk_id, disk->volume_label, disk->disk_prompt);
3967 return ERROR_SUCCESS;
3970 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3972 MSIHANDLE hdb, suminfo;
3973 WCHAR guids[MAX_PATH];
3974 WCHAR packcode[SQUISH_GUID_SIZE];
3981 static const WCHAR szARPProductIcon[] =
3982 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3983 static const WCHAR szAssignment[] =
3984 {'A','s','s','i','g','n','m','e','n','t',0};
3985 static const WCHAR szAdvertiseFlags[] =
3986 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3987 static const WCHAR szClients[] =
3988 {'C','l','i','e','n','t','s',0};
3989 static const WCHAR szColon[] = {':',0};
3991 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3992 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3995 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3996 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3999 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4001 buffer = msi_dup_property(package->db, szARPProductIcon);
4004 LPWSTR path = msi_build_icon_path(package, buffer);
4005 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4010 buffer = msi_dup_property(package->db, szProductVersion);
4013 DWORD verdword = msi_version_str_to_dword(buffer);
4014 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4018 msi_reg_set_val_dword(hkey, szAssignment, 0);
4019 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4020 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4021 msi_reg_set_val_str(hkey, szClients, szColon);
4023 hdb = alloc_msihandle(&package->db->hdr);
4025 return ERROR_NOT_ENOUGH_MEMORY;
4027 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4028 MsiCloseHandle(hdb);
4029 if (r != ERROR_SUCCESS)
4033 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4034 NULL, guids, &size);
4035 if (r != ERROR_SUCCESS)
4038 ptr = strchrW(guids, ';');
4040 squash_guid(guids, packcode);
4041 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4044 MsiCloseHandle(suminfo);
4045 return ERROR_SUCCESS;
4048 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4053 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4055 upgrade = msi_dup_property(package->db, szUpgradeCode);
4057 return ERROR_SUCCESS;
4059 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4060 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4062 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4064 if (r != ERROR_SUCCESS)
4066 WARN("failed to open upgrade code key\n");
4068 return ERROR_SUCCESS;
4070 squash_guid(package->ProductCode, squashed_pc);
4071 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4074 return ERROR_SUCCESS;
4077 static BOOL msi_check_publish(MSIPACKAGE *package)
4079 MSIFEATURE *feature;
4081 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4083 feature->Action = msi_get_feature_action( package, feature );
4084 if (feature->Action == INSTALLSTATE_LOCAL)
4091 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4093 MSIFEATURE *feature;
4095 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4097 feature->Action = msi_get_feature_action( package, feature );
4098 if (feature->Action != INSTALLSTATE_ABSENT)
4105 static UINT msi_publish_patches( MSIPACKAGE *package )
4107 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4108 WCHAR patch_squashed[GUID_SIZE];
4109 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4111 MSIPATCHINFO *patch;
4113 WCHAR *p, *all_patches = NULL;
4116 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4117 if (r != ERROR_SUCCESS)
4118 return ERROR_FUNCTION_FAILED;
4120 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4121 if (res != ERROR_SUCCESS)
4123 r = ERROR_FUNCTION_FAILED;
4127 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4128 if (r != ERROR_SUCCESS)
4131 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4133 squash_guid( patch->patchcode, patch_squashed );
4134 len += strlenW( patch_squashed ) + 1;
4137 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4141 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4145 squash_guid( patch->patchcode, p );
4146 p += strlenW( p ) + 1;
4148 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4149 (const BYTE *)patch->transforms,
4150 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4151 if (res != ERROR_SUCCESS)
4154 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4155 if (r != ERROR_SUCCESS)
4158 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4159 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4160 RegCloseKey( patch_key );
4161 if (res != ERROR_SUCCESS)
4164 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4166 res = GetLastError();
4167 ERR("Unable to copy patch package %d\n", res);
4170 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4171 if (res != ERROR_SUCCESS)
4174 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4175 RegCloseKey( patch_key );
4176 if (res != ERROR_SUCCESS)
4180 all_patches[len] = 0;
4181 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4182 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4183 if (res != ERROR_SUCCESS)
4186 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4187 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4188 if (res != ERROR_SUCCESS)
4189 r = ERROR_FUNCTION_FAILED;
4192 RegCloseKey( product_patches_key );
4193 RegCloseKey( patches_key );
4194 RegCloseKey( product_key );
4195 msi_free( all_patches );
4199 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4202 HKEY hukey = NULL, hudkey = NULL;
4205 if (!list_empty(&package->patches))
4207 rc = msi_publish_patches(package);
4208 if (rc != ERROR_SUCCESS)
4212 /* FIXME: also need to publish if the product is in advertise mode */
4213 if (!msi_check_publish(package))
4214 return ERROR_SUCCESS;
4216 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4218 if (rc != ERROR_SUCCESS)
4221 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4222 NULL, &hudkey, TRUE);
4223 if (rc != ERROR_SUCCESS)
4226 rc = msi_publish_upgrade_code(package);
4227 if (rc != ERROR_SUCCESS)
4230 rc = msi_publish_product_properties(package, hukey);
4231 if (rc != ERROR_SUCCESS)
4234 rc = msi_publish_sourcelist(package, hukey);
4235 if (rc != ERROR_SUCCESS)
4238 rc = msi_publish_icons(package);
4241 uirow = MSI_CreateRecord( 1 );
4242 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4243 msi_ui_actiondata( package, szPublishProduct, uirow );
4244 msiobj_release( &uirow->hdr );
4247 RegCloseKey(hudkey);
4251 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4253 WCHAR *filename, *ptr, *folder, *ret;
4254 const WCHAR *dirprop;
4256 filename = msi_dup_record_field( row, 2 );
4257 if (filename && (ptr = strchrW( filename, '|' )))
4262 dirprop = MSI_RecordGetString( row, 3 );
4265 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4266 if (!folder) folder = msi_dup_property( package->db, dirprop );
4269 folder = msi_dup_property( package->db, szWindowsFolder );
4273 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4274 msi_free( filename );
4278 ret = msi_build_directory_name( 2, folder, ptr );
4280 msi_free( filename );
4285 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4287 MSIPACKAGE *package = param;
4288 LPCWSTR component, section, key, value, identifier;
4289 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4294 component = MSI_RecordGetString(row, 8);
4295 comp = msi_get_loaded_component(package,component);
4297 return ERROR_SUCCESS;
4299 comp->Action = msi_get_component_action( package, comp );
4300 if (comp->Action != INSTALLSTATE_LOCAL)
4302 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4303 return ERROR_SUCCESS;
4306 identifier = MSI_RecordGetString(row,1);
4307 section = MSI_RecordGetString(row,4);
4308 key = MSI_RecordGetString(row,5);
4309 value = MSI_RecordGetString(row,6);
4310 action = MSI_RecordGetInteger(row,7);
4312 deformat_string(package,section,&deformated_section);
4313 deformat_string(package,key,&deformated_key);
4314 deformat_string(package,value,&deformated_value);
4316 fullname = get_ini_file_name(package, row);
4320 TRACE("Adding value %s to section %s in %s\n",
4321 debugstr_w(deformated_key), debugstr_w(deformated_section),
4322 debugstr_w(fullname));
4323 WritePrivateProfileStringW(deformated_section, deformated_key,
4324 deformated_value, fullname);
4326 else if (action == 1)
4329 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4330 returned, 10, fullname);
4331 if (returned[0] == 0)
4333 TRACE("Adding value %s to section %s in %s\n",
4334 debugstr_w(deformated_key), debugstr_w(deformated_section),
4335 debugstr_w(fullname));
4337 WritePrivateProfileStringW(deformated_section, deformated_key,
4338 deformated_value, fullname);
4341 else if (action == 3)
4342 FIXME("Append to existing section not yet implemented\n");
4344 uirow = MSI_CreateRecord(4);
4345 MSI_RecordSetStringW(uirow,1,identifier);
4346 MSI_RecordSetStringW(uirow,2,deformated_section);
4347 MSI_RecordSetStringW(uirow,3,deformated_key);
4348 MSI_RecordSetStringW(uirow,4,deformated_value);
4349 msi_ui_actiondata( package, szWriteIniValues, uirow );
4350 msiobj_release( &uirow->hdr );
4353 msi_free(deformated_key);
4354 msi_free(deformated_value);
4355 msi_free(deformated_section);
4356 return ERROR_SUCCESS;
4359 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4361 static const WCHAR query[] = {
4362 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4363 '`','I','n','i','F','i','l','e','`',0};
4367 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4368 if (rc != ERROR_SUCCESS)
4369 return ERROR_SUCCESS;
4371 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4372 msiobj_release(&view->hdr);
4376 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4378 MSIPACKAGE *package = param;
4379 LPCWSTR component, section, key, value, identifier;
4380 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4385 component = MSI_RecordGetString( row, 8 );
4386 comp = msi_get_loaded_component( package, component );
4388 return ERROR_SUCCESS;
4390 comp->Action = msi_get_component_action( package, comp );
4391 if (comp->Action != INSTALLSTATE_ABSENT)
4393 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4394 return ERROR_SUCCESS;
4397 identifier = MSI_RecordGetString( row, 1 );
4398 section = MSI_RecordGetString( row, 4 );
4399 key = MSI_RecordGetString( row, 5 );
4400 value = MSI_RecordGetString( row, 6 );
4401 action = MSI_RecordGetInteger( row, 7 );
4403 deformat_string( package, section, &deformated_section );
4404 deformat_string( package, key, &deformated_key );
4405 deformat_string( package, value, &deformated_value );
4407 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4409 filename = get_ini_file_name( package, row );
4411 TRACE("Removing key %s from section %s in %s\n",
4412 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4414 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4416 WARN("Unable to remove key %u\n", GetLastError());
4418 msi_free( filename );
4421 FIXME("Unsupported action %d\n", action);
4424 uirow = MSI_CreateRecord( 4 );
4425 MSI_RecordSetStringW( uirow, 1, identifier );
4426 MSI_RecordSetStringW( uirow, 2, deformated_section );
4427 MSI_RecordSetStringW( uirow, 3, deformated_key );
4428 MSI_RecordSetStringW( uirow, 4, deformated_value );
4429 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4430 msiobj_release( &uirow->hdr );
4432 msi_free( deformated_key );
4433 msi_free( deformated_value );
4434 msi_free( deformated_section );
4435 return ERROR_SUCCESS;
4438 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4440 MSIPACKAGE *package = param;
4441 LPCWSTR component, section, key, value, identifier;
4442 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4447 component = MSI_RecordGetString( row, 8 );
4448 comp = msi_get_loaded_component( package, component );
4450 return ERROR_SUCCESS;
4452 comp->Action = msi_get_component_action( package, comp );
4453 if (comp->Action != INSTALLSTATE_LOCAL)
4455 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4456 return ERROR_SUCCESS;
4459 identifier = MSI_RecordGetString( row, 1 );
4460 section = MSI_RecordGetString( row, 4 );
4461 key = MSI_RecordGetString( row, 5 );
4462 value = MSI_RecordGetString( row, 6 );
4463 action = MSI_RecordGetInteger( row, 7 );
4465 deformat_string( package, section, &deformated_section );
4466 deformat_string( package, key, &deformated_key );
4467 deformat_string( package, value, &deformated_value );
4469 if (action == msidbIniFileActionRemoveLine)
4471 filename = get_ini_file_name( package, row );
4473 TRACE("Removing key %s from section %s in %s\n",
4474 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4476 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4478 WARN("Unable to remove key %u\n", GetLastError());
4480 msi_free( filename );
4483 FIXME("Unsupported action %d\n", action);
4485 uirow = MSI_CreateRecord( 4 );
4486 MSI_RecordSetStringW( uirow, 1, identifier );
4487 MSI_RecordSetStringW( uirow, 2, deformated_section );
4488 MSI_RecordSetStringW( uirow, 3, deformated_key );
4489 MSI_RecordSetStringW( uirow, 4, deformated_value );
4490 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4491 msiobj_release( &uirow->hdr );
4493 msi_free( deformated_key );
4494 msi_free( deformated_value );
4495 msi_free( deformated_section );
4496 return ERROR_SUCCESS;
4499 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4501 static const WCHAR query[] = {
4502 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4503 '`','I','n','i','F','i','l','e','`',0};
4504 static const WCHAR remove_query[] = {
4505 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4506 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4510 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4511 if (rc == ERROR_SUCCESS)
4513 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4514 msiobj_release( &view->hdr );
4515 if (rc != ERROR_SUCCESS)
4518 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4519 if (rc == ERROR_SUCCESS)
4521 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4522 msiobj_release( &view->hdr );
4523 if (rc != ERROR_SUCCESS)
4526 return ERROR_SUCCESS;
4529 static void register_dll( const WCHAR *dll, BOOL unregister )
4533 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4536 HRESULT (WINAPI *func_ptr)( void );
4537 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4539 func_ptr = (void *)GetProcAddress( hmod, func );
4542 HRESULT hr = func_ptr();
4544 WARN("failed to register dll 0x%08x\n", hr);
4547 WARN("entry point %s not found\n", func);
4548 FreeLibrary( hmod );
4551 WARN("failed to load library %u\n", GetLastError());
4554 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4556 MSIPACKAGE *package = param;
4561 filename = MSI_RecordGetString( row, 1 );
4562 file = msi_get_loaded_file( package, filename );
4565 WARN("unable to find file %s\n", debugstr_w(filename));
4566 return ERROR_SUCCESS;
4568 file->Component->Action = msi_get_component_action( package, file->Component );
4569 if (file->Component->Action != INSTALLSTATE_LOCAL)
4571 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4572 return ERROR_SUCCESS;
4575 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4576 register_dll( file->TargetPath, FALSE );
4578 uirow = MSI_CreateRecord( 2 );
4579 MSI_RecordSetStringW( uirow, 1, file->File );
4580 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4581 msi_ui_actiondata( package, szSelfRegModules, uirow );
4582 msiobj_release( &uirow->hdr );
4584 return ERROR_SUCCESS;
4587 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4589 static const WCHAR query[] = {
4590 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4591 '`','S','e','l','f','R','e','g','`',0};
4595 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4596 if (rc != ERROR_SUCCESS)
4597 return ERROR_SUCCESS;
4599 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4600 msiobj_release(&view->hdr);
4604 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4606 MSIPACKAGE *package = param;
4611 filename = MSI_RecordGetString( row, 1 );
4612 file = msi_get_loaded_file( package, filename );
4615 WARN("unable to find file %s\n", debugstr_w(filename));
4616 return ERROR_SUCCESS;
4618 file->Component->Action = msi_get_component_action( package, file->Component );
4619 if (file->Component->Action != INSTALLSTATE_ABSENT)
4621 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4622 return ERROR_SUCCESS;
4625 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4626 register_dll( file->TargetPath, TRUE );
4628 uirow = MSI_CreateRecord( 2 );
4629 MSI_RecordSetStringW( uirow, 1, file->File );
4630 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4631 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4632 msiobj_release( &uirow->hdr );
4634 return ERROR_SUCCESS;
4637 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4639 static const WCHAR query[] = {
4640 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4641 '`','S','e','l','f','R','e','g','`',0};
4645 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4646 if (rc != ERROR_SUCCESS)
4647 return ERROR_SUCCESS;
4649 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4650 msiobj_release( &view->hdr );
4654 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4656 MSIFEATURE *feature;
4658 HKEY hkey = NULL, userdata = NULL;
4660 if (!msi_check_publish(package))
4661 return ERROR_SUCCESS;
4663 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4665 if (rc != ERROR_SUCCESS)
4668 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4670 if (rc != ERROR_SUCCESS)
4673 /* here the guids are base 85 encoded */
4674 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4680 BOOL absent = FALSE;
4683 if (feature->Action != INSTALLSTATE_LOCAL &&
4684 feature->Action != INSTALLSTATE_SOURCE &&
4685 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4688 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4692 if (feature->Feature_Parent)
4693 size += strlenW( feature->Feature_Parent )+2;
4695 data = msi_alloc(size * sizeof(WCHAR));
4698 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4700 MSICOMPONENT* component = cl->component;
4704 if (component->ComponentId)
4706 TRACE("From %s\n",debugstr_w(component->ComponentId));
4707 CLSIDFromString(component->ComponentId, &clsid);
4708 encode_base85_guid(&clsid,buf);
4709 TRACE("to %s\n",debugstr_w(buf));
4714 if (feature->Feature_Parent)
4716 static const WCHAR sep[] = {'\2',0};
4718 strcatW(data,feature->Feature_Parent);
4721 msi_reg_set_val_str( userdata, feature->Feature, data );
4725 if (feature->Feature_Parent)
4726 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4729 size += sizeof(WCHAR);
4730 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4731 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4735 size += 2*sizeof(WCHAR);
4736 data = msi_alloc(size);
4739 if (feature->Feature_Parent)
4740 strcpyW( &data[1], feature->Feature_Parent );
4741 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4747 uirow = MSI_CreateRecord( 1 );
4748 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4749 msi_ui_actiondata( package, szPublishFeatures, uirow );
4750 msiobj_release( &uirow->hdr );
4751 /* FIXME: call msi_ui_progress? */
4756 RegCloseKey(userdata);
4760 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4766 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4768 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4770 if (r == ERROR_SUCCESS)
4772 RegDeleteValueW(hkey, feature->Feature);
4776 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4778 if (r == ERROR_SUCCESS)
4780 RegDeleteValueW(hkey, feature->Feature);
4784 uirow = MSI_CreateRecord( 1 );
4785 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4786 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4787 msiobj_release( &uirow->hdr );
4789 return ERROR_SUCCESS;
4792 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4794 MSIFEATURE *feature;
4796 if (!msi_check_unpublish(package))
4797 return ERROR_SUCCESS;
4799 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4801 msi_unpublish_feature(package, feature);
4804 return ERROR_SUCCESS;
4807 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4811 WCHAR date[9], *val, *buffer;
4812 const WCHAR *prop, *key;
4814 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4815 static const WCHAR modpath_fmt[] =
4816 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4817 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4818 static const WCHAR szModifyPath[] =
4819 {'M','o','d','i','f','y','P','a','t','h',0};
4820 static const WCHAR szUninstallString[] =
4821 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4822 static const WCHAR szEstimatedSize[] =
4823 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4824 static const WCHAR szDisplayVersion[] =
4825 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4826 static const WCHAR szInstallSource[] =
4827 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4828 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4829 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4830 static const WCHAR szAuthorizedCDFPrefix[] =
4831 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4832 static const WCHAR szARPCONTACT[] =
4833 {'A','R','P','C','O','N','T','A','C','T',0};
4834 static const WCHAR szContact[] =
4835 {'C','o','n','t','a','c','t',0};
4836 static const WCHAR szARPCOMMENTS[] =
4837 {'A','R','P','C','O','M','M','E','N','T','S',0};
4838 static const WCHAR szComments[] =
4839 {'C','o','m','m','e','n','t','s',0};
4840 static const WCHAR szProductName[] =
4841 {'P','r','o','d','u','c','t','N','a','m','e',0};
4842 static const WCHAR szDisplayName[] =
4843 {'D','i','s','p','l','a','y','N','a','m','e',0};
4844 static const WCHAR szARPHELPLINK[] =
4845 {'A','R','P','H','E','L','P','L','I','N','K',0};
4846 static const WCHAR szHelpLink[] =
4847 {'H','e','l','p','L','i','n','k',0};
4848 static const WCHAR szARPHELPTELEPHONE[] =
4849 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4850 static const WCHAR szHelpTelephone[] =
4851 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4852 static const WCHAR szARPINSTALLLOCATION[] =
4853 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4854 static const WCHAR szManufacturer[] =
4855 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4856 static const WCHAR szPublisher[] =
4857 {'P','u','b','l','i','s','h','e','r',0};
4858 static const WCHAR szARPREADME[] =
4859 {'A','R','P','R','E','A','D','M','E',0};
4860 static const WCHAR szReadme[] =
4861 {'R','e','a','d','M','e',0};
4862 static const WCHAR szARPSIZE[] =
4863 {'A','R','P','S','I','Z','E',0};
4864 static const WCHAR szSize[] =
4865 {'S','i','z','e',0};
4866 static const WCHAR szARPURLINFOABOUT[] =
4867 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4868 static const WCHAR szURLInfoAbout[] =
4869 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4870 static const WCHAR szARPURLUPDATEINFO[] =
4871 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4872 static const WCHAR szURLUpdateInfo[] =
4873 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4874 static const WCHAR szARPSYSTEMCOMPONENT[] =
4875 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4876 static const WCHAR szSystemComponent[] =
4877 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4879 static const WCHAR *propval[] = {
4880 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4881 szARPCONTACT, szContact,
4882 szARPCOMMENTS, szComments,
4883 szProductName, szDisplayName,
4884 szARPHELPLINK, szHelpLink,
4885 szARPHELPTELEPHONE, szHelpTelephone,
4886 szARPINSTALLLOCATION, szInstallLocation,
4887 szSourceDir, szInstallSource,
4888 szManufacturer, szPublisher,
4889 szARPREADME, szReadme,
4891 szARPURLINFOABOUT, szURLInfoAbout,
4892 szARPURLUPDATEINFO, szURLUpdateInfo,
4895 const WCHAR **p = propval;
4901 val = msi_dup_property(package->db, prop);
4902 msi_reg_set_val_str(hkey, key, val);
4906 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4907 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4909 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4911 size = deformat_string(package, modpath_fmt, &buffer);
4912 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4913 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4916 /* FIXME: Write real Estimated Size when we have it */
4917 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4919 GetLocalTime(&systime);
4920 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4921 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4923 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4924 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4926 buffer = msi_dup_property(package->db, szProductVersion);
4927 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4930 DWORD verdword = msi_version_str_to_dword(buffer);
4932 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4933 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4934 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4938 return ERROR_SUCCESS;
4941 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4943 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4945 LPWSTR upgrade_code;
4946 HKEY hkey, props, upgrade_key;
4949 /* FIXME: also need to publish if the product is in advertise mode */
4950 if (!msi_check_publish(package))
4951 return ERROR_SUCCESS;
4953 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4954 if (rc != ERROR_SUCCESS)
4957 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4958 if (rc != ERROR_SUCCESS)
4961 rc = msi_publish_install_properties(package, hkey);
4962 if (rc != ERROR_SUCCESS)
4965 rc = msi_publish_install_properties(package, props);
4966 if (rc != ERROR_SUCCESS)
4969 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4972 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4973 if (rc == ERROR_SUCCESS)
4975 squash_guid( package->ProductCode, squashed_pc );
4976 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4977 RegCloseKey( upgrade_key );
4979 msi_free( upgrade_code );
4981 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4982 package->delete_on_close = FALSE;
4985 uirow = MSI_CreateRecord( 1 );
4986 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4987 msi_ui_actiondata( package, szRegisterProduct, uirow );
4988 msiobj_release( &uirow->hdr );
4991 return ERROR_SUCCESS;
4994 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4996 return execute_script(package, SCRIPT_INSTALL);
4999 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5001 MSIPACKAGE *package = param;
5002 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5003 WCHAR *p, *icon_path;
5005 if (!icon) return ERROR_SUCCESS;
5006 if ((icon_path = msi_build_icon_path( package, icon )))
5008 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5009 DeleteFileW( icon_path );
5010 if ((p = strrchrW( icon_path, '\\' )))
5013 RemoveDirectoryW( icon_path );
5015 msi_free( icon_path );
5017 return ERROR_SUCCESS;
5020 static UINT msi_unpublish_icons( MSIPACKAGE *package )
5022 static const WCHAR query[]= {
5023 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
5027 r = MSI_DatabaseOpenViewW( package->db, query, &view );
5028 if (r == ERROR_SUCCESS)
5030 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5031 msiobj_release( &view->hdr );
5032 if (r != ERROR_SUCCESS)
5035 return ERROR_SUCCESS;
5038 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
5040 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
5041 WCHAR *upgrade, **features;
5042 BOOL full_uninstall = TRUE;
5043 MSIFEATURE *feature;
5044 MSIPATCHINFO *patch;
5047 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5049 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
5051 features = msi_split_string( remove, ',' );
5052 for (i = 0; features && features[i]; i++)
5054 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
5058 if (!full_uninstall)
5059 return ERROR_SUCCESS;
5061 MSIREG_DeleteProductKey(package->ProductCode);
5062 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5063 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5065 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5066 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5067 MSIREG_DeleteUserProductKey(package->ProductCode);
5068 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5070 upgrade = msi_dup_property(package->db, szUpgradeCode);
5073 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5074 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5078 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5080 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5081 if (!strcmpW( package->ProductCode, patch->products ))
5083 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5084 patch->delete_on_close = TRUE;
5086 /* FIXME: remove local patch package if this is the last product */
5088 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5089 package->delete_on_close = TRUE;
5091 msi_unpublish_icons( package );
5092 return ERROR_SUCCESS;
5095 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5100 /* turn off scheduling */
5101 package->script->CurrentlyScripting= FALSE;
5103 /* first do the same as an InstallExecute */
5104 rc = ACTION_InstallExecute(package);
5105 if (rc != ERROR_SUCCESS)
5108 /* then handle commit actions */
5109 rc = execute_script(package, SCRIPT_COMMIT);
5110 if (rc != ERROR_SUCCESS)
5113 remove = msi_dup_property(package->db, szRemove);
5114 rc = msi_unpublish_product(package, remove);
5119 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5121 static const WCHAR RunOnce[] = {
5122 'S','o','f','t','w','a','r','e','\\',
5123 'M','i','c','r','o','s','o','f','t','\\',
5124 'W','i','n','d','o','w','s','\\',
5125 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5126 'R','u','n','O','n','c','e',0};
5127 static const WCHAR InstallRunOnce[] = {
5128 'S','o','f','t','w','a','r','e','\\',
5129 'M','i','c','r','o','s','o','f','t','\\',
5130 'W','i','n','d','o','w','s','\\',
5131 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5132 'I','n','s','t','a','l','l','e','r','\\',
5133 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5135 static const WCHAR msiexec_fmt[] = {
5137 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5138 '\"','%','s','\"',0};
5139 static const WCHAR install_fmt[] = {
5140 '/','I',' ','\"','%','s','\"',' ',
5141 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5142 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5143 WCHAR buffer[256], sysdir[MAX_PATH];
5145 WCHAR squished_pc[100];
5147 squash_guid(package->ProductCode,squished_pc);
5149 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5150 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5151 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5154 msi_reg_set_val_str( hkey, squished_pc, buffer );
5157 TRACE("Reboot command %s\n",debugstr_w(buffer));
5159 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5160 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5162 msi_reg_set_val_str( hkey, squished_pc, buffer );
5165 return ERROR_INSTALL_SUSPEND;
5168 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5170 static const WCHAR query[] =
5171 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5172 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5173 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5174 MSIRECORD *rec, *row;
5180 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5182 rec = MSI_CreateRecord( count + 2 );
5183 str = MSI_RecordGetString( row, 1 );
5184 MSI_RecordSetStringW( rec, 0, str );
5185 msiobj_release( &row->hdr );
5186 MSI_RecordSetInteger( rec, 1, error );
5188 va_start( va, count );
5189 for (i = 0; i < count; i++)
5191 str = va_arg( va, const WCHAR *);
5192 MSI_RecordSetStringW( rec, i + 2, str );
5196 MSI_FormatRecordW( package, rec, NULL, &size );
5198 data = msi_alloc( size * sizeof(WCHAR) );
5199 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5201 msiobj_release( &rec->hdr );
5205 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5211 * We are currently doing what should be done here in the top level Install
5212 * however for Administrative and uninstalls this step will be needed
5214 if (!package->PackagePath)
5215 return ERROR_SUCCESS;
5217 msi_set_sourcedir_props(package, TRUE);
5219 attrib = GetFileAttributesW(package->db->path);
5220 if (attrib == INVALID_FILE_ATTRIBUTES)
5225 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5226 package->Context, MSICODE_PRODUCT,
5227 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5228 if (rc == ERROR_MORE_DATA)
5230 prompt = msi_alloc(size * sizeof(WCHAR));
5231 MsiSourceListGetInfoW(package->ProductCode, NULL,
5232 package->Context, MSICODE_PRODUCT,
5233 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5236 prompt = strdupW(package->db->path);
5238 msg = msi_build_error_string(package, 1302, 1, prompt);
5240 while(attrib == INVALID_FILE_ATTRIBUTES)
5242 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5246 return ERROR_INSTALL_USEREXIT;
5248 attrib = GetFileAttributesW(package->db->path);
5254 return ERROR_SUCCESS;
5259 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5262 LPWSTR buffer, productid = NULL;
5263 UINT i, rc = ERROR_SUCCESS;
5266 static const WCHAR szPropKeys[][80] =
5268 {'P','r','o','d','u','c','t','I','D',0},
5269 {'U','S','E','R','N','A','M','E',0},
5270 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5274 static const WCHAR szRegKeys[][80] =
5276 {'P','r','o','d','u','c','t','I','D',0},
5277 {'R','e','g','O','w','n','e','r',0},
5278 {'R','e','g','C','o','m','p','a','n','y',0},
5282 if (msi_check_unpublish(package))
5284 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5288 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5292 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5294 if (rc != ERROR_SUCCESS)
5297 for( i = 0; szPropKeys[i][0]; i++ )
5299 buffer = msi_dup_property( package->db, szPropKeys[i] );
5300 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5305 uirow = MSI_CreateRecord( 1 );
5306 MSI_RecordSetStringW( uirow, 1, productid );
5307 msi_ui_actiondata( package, szRegisterUser, uirow );
5308 msiobj_release( &uirow->hdr );
5310 msi_free(productid);
5316 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5320 package->script->InWhatSequence |= SEQUENCE_EXEC;
5321 rc = ACTION_ProcessExecSequence(package,FALSE);
5325 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5327 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5328 WCHAR productid_85[21], component_85[21], *ret;
5332 /* > is used if there is a component GUID and < if not. */
5334 productid_85[0] = 0;
5335 component_85[0] = 0;
5336 CLSIDFromString( package->ProductCode, &clsid );
5338 encode_base85_guid( &clsid, productid_85 );
5341 CLSIDFromString( component->ComponentId, &clsid );
5342 encode_base85_guid( &clsid, component_85 );
5345 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5346 debugstr_w(component_85));
5348 sz = 20 + strlenW( feature ) + 20 + 3;
5349 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5350 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5354 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5356 MSIPACKAGE *package = param;
5357 LPCWSTR compgroupid, component, feature, qualifier, text;
5358 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5367 feature = MSI_RecordGetString(rec, 5);
5368 feat = msi_get_loaded_feature(package, feature);
5370 return ERROR_SUCCESS;
5372 feat->Action = msi_get_feature_action( package, feat );
5373 if (feat->Action != INSTALLSTATE_LOCAL &&
5374 feat->Action != INSTALLSTATE_SOURCE &&
5375 feat->Action != INSTALLSTATE_ADVERTISED)
5377 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5378 return ERROR_SUCCESS;
5381 component = MSI_RecordGetString(rec, 3);
5382 comp = msi_get_loaded_component(package, component);
5384 return ERROR_SUCCESS;
5386 compgroupid = MSI_RecordGetString(rec,1);
5387 qualifier = MSI_RecordGetString(rec,2);
5389 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5390 if (rc != ERROR_SUCCESS)
5393 advertise = msi_create_component_advertise_string( package, comp, feature );
5394 text = MSI_RecordGetString( rec, 4 );
5397 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5398 strcpyW( p, advertise );
5400 msi_free( advertise );
5403 existing = msi_reg_get_val_str( hkey, qualifier );
5405 sz = strlenW( advertise ) + 1;
5408 for (p = existing; *p; p += len)
5410 len = strlenW( p ) + 1;
5411 if (strcmpW( advertise, p )) sz += len;
5414 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5416 rc = ERROR_OUTOFMEMORY;
5422 for (p = existing; *p; p += len)
5424 len = strlenW( p ) + 1;
5425 if (strcmpW( advertise, p ))
5427 memcpy( q, p, len * sizeof(WCHAR) );
5432 strcpyW( q, advertise );
5433 q[strlenW( q ) + 1] = 0;
5435 msi_reg_set_val_multi_str( hkey, qualifier, output );
5440 msi_free( advertise );
5441 msi_free( existing );
5444 uirow = MSI_CreateRecord( 2 );
5445 MSI_RecordSetStringW( uirow, 1, compgroupid );
5446 MSI_RecordSetStringW( uirow, 2, qualifier);
5447 msi_ui_actiondata( package, szPublishComponents, uirow );
5448 msiobj_release( &uirow->hdr );
5449 /* FIXME: call ui_progress? */
5455 * At present I am ignorning the advertised components part of this and only
5456 * focusing on the qualified component sets
5458 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5460 static const WCHAR query[] = {
5461 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5462 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5466 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5467 if (rc != ERROR_SUCCESS)
5468 return ERROR_SUCCESS;
5470 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5471 msiobj_release(&view->hdr);
5475 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5477 static const WCHAR szInstallerComponents[] = {
5478 'S','o','f','t','w','a','r','e','\\',
5479 'M','i','c','r','o','s','o','f','t','\\',
5480 'I','n','s','t','a','l','l','e','r','\\',
5481 'C','o','m','p','o','n','e','n','t','s','\\',0};
5483 MSIPACKAGE *package = param;
5484 LPCWSTR compgroupid, component, feature, qualifier;
5488 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5491 feature = MSI_RecordGetString( rec, 5 );
5492 feat = msi_get_loaded_feature( package, feature );
5494 return ERROR_SUCCESS;
5496 feat->Action = msi_get_feature_action( package, feat );
5497 if (feat->Action != INSTALLSTATE_ABSENT)
5499 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5500 return ERROR_SUCCESS;
5503 component = MSI_RecordGetString( rec, 3 );
5504 comp = msi_get_loaded_component( package, component );
5506 return ERROR_SUCCESS;
5508 compgroupid = MSI_RecordGetString( rec, 1 );
5509 qualifier = MSI_RecordGetString( rec, 2 );
5511 squash_guid( compgroupid, squashed );
5512 strcpyW( keypath, szInstallerComponents );
5513 strcatW( keypath, squashed );
5515 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5516 if (res != ERROR_SUCCESS)
5518 WARN("Unable to delete component key %d\n", res);
5521 uirow = MSI_CreateRecord( 2 );
5522 MSI_RecordSetStringW( uirow, 1, compgroupid );
5523 MSI_RecordSetStringW( uirow, 2, qualifier );
5524 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5525 msiobj_release( &uirow->hdr );
5527 return ERROR_SUCCESS;
5530 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5532 static const WCHAR query[] = {
5533 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5534 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5538 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5539 if (rc != ERROR_SUCCESS)
5540 return ERROR_SUCCESS;
5542 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5543 msiobj_release( &view->hdr );
5547 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5549 static const WCHAR query[] =
5550 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5551 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5552 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5553 MSIPACKAGE *package = param;
5554 MSICOMPONENT *component;
5557 SC_HANDLE hscm = NULL, service = NULL;
5559 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5560 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5561 DWORD serv_type, start_type, err_control;
5562 SERVICE_DESCRIPTIONW sd = {NULL};
5564 comp = MSI_RecordGetString( rec, 12 );
5565 component = msi_get_loaded_component( package, comp );
5568 WARN("service component not found\n");
5571 component->Action = msi_get_component_action( package, component );
5572 if (component->Action != INSTALLSTATE_LOCAL)
5574 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5577 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5580 ERR("Failed to open the SC Manager!\n");
5584 start_type = MSI_RecordGetInteger(rec, 5);
5585 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5588 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5589 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5590 serv_type = MSI_RecordGetInteger(rec, 4);
5591 err_control = MSI_RecordGetInteger(rec, 6);
5592 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5593 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5594 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5595 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5596 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5597 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5599 /* fetch the service path */
5600 row = MSI_QueryGetRecord(package->db, query, comp);
5603 ERR("Query failed\n");
5606 key = MSI_RecordGetString(row, 6);
5607 file = msi_get_loaded_file(package, key);
5608 msiobj_release(&row->hdr);
5611 ERR("Failed to load the service file\n");
5615 if (!args || !args[0]) image_path = file->TargetPath;
5618 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5619 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5620 return ERROR_OUTOFMEMORY;
5622 strcpyW(image_path, file->TargetPath);
5623 strcatW(image_path, szSpace);
5624 strcatW(image_path, args);
5626 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5627 start_type, err_control, image_path, load_order,
5628 NULL, depends, serv_name, pass);
5632 if (GetLastError() != ERROR_SERVICE_EXISTS)
5633 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5635 else if (sd.lpDescription)
5637 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5638 WARN("failed to set service description %u\n", GetLastError());
5641 if (image_path != file->TargetPath) msi_free(image_path);
5643 CloseServiceHandle(service);
5644 CloseServiceHandle(hscm);
5647 msi_free(sd.lpDescription);
5648 msi_free(load_order);
5649 msi_free(serv_name);
5654 return ERROR_SUCCESS;
5657 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5659 static const WCHAR query[] = {
5660 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5661 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5665 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5666 if (rc != ERROR_SUCCESS)
5667 return ERROR_SUCCESS;
5669 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5670 msiobj_release(&view->hdr);
5674 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5675 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5677 LPCWSTR *vector, *temp_vector;
5681 static const WCHAR separator[] = {'[','~',']',0};
5684 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5689 vector = msi_alloc(sizeof(LPWSTR));
5697 vector[*numargs - 1] = p;
5699 if ((q = strstrW(p, separator)))
5703 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5709 vector = temp_vector;
5718 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5720 MSIPACKAGE *package = param;
5723 SC_HANDLE scm = NULL, service = NULL;
5724 LPCWSTR component, *vector = NULL;
5725 LPWSTR name, args, display_name = NULL;
5726 DWORD event, numargs, len, wait, dummy;
5727 UINT r = ERROR_FUNCTION_FAILED;
5728 SERVICE_STATUS_PROCESS status;
5729 ULONGLONG start_time;
5731 component = MSI_RecordGetString(rec, 6);
5732 comp = msi_get_loaded_component(package, component);
5734 return ERROR_SUCCESS;
5736 comp->Action = msi_get_component_action( package, comp );
5737 if (comp->Action != INSTALLSTATE_LOCAL)
5739 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5740 return ERROR_SUCCESS;
5743 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5744 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5745 event = MSI_RecordGetInteger(rec, 3);
5746 wait = MSI_RecordGetInteger(rec, 5);
5748 if (!(event & msidbServiceControlEventStart))
5754 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5757 ERR("Failed to open the service control manager\n");
5762 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5763 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5765 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5766 GetServiceDisplayNameW( scm, name, display_name, &len );
5769 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5772 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5776 vector = msi_service_args_to_vector(args, &numargs);
5778 if (!StartServiceW(service, numargs, vector) &&
5779 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5781 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5788 /* wait for at most 30 seconds for the service to be up and running */
5789 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5790 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5792 TRACE("failed to query service status (%u)\n", GetLastError());
5795 start_time = GetTickCount64();
5796 while (status.dwCurrentState == SERVICE_START_PENDING)
5798 if (GetTickCount64() - start_time > 30000) break;
5800 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5801 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5803 TRACE("failed to query service status (%u)\n", GetLastError());
5807 if (status.dwCurrentState != SERVICE_RUNNING)
5809 WARN("service failed to start %u\n", status.dwCurrentState);
5810 r = ERROR_FUNCTION_FAILED;
5815 uirow = MSI_CreateRecord( 2 );
5816 MSI_RecordSetStringW( uirow, 1, display_name );
5817 MSI_RecordSetStringW( uirow, 2, name );
5818 msi_ui_actiondata( package, szStartServices, uirow );
5819 msiobj_release( &uirow->hdr );
5821 CloseServiceHandle(service);
5822 CloseServiceHandle(scm);
5827 msi_free(display_name);
5831 static UINT ACTION_StartServices( MSIPACKAGE *package )
5833 static const WCHAR query[] = {
5834 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5835 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5839 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5840 if (rc != ERROR_SUCCESS)
5841 return ERROR_SUCCESS;
5843 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5844 msiobj_release(&view->hdr);
5848 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5850 DWORD i, needed, count;
5851 ENUM_SERVICE_STATUSW *dependencies;
5855 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5856 0, &needed, &count))
5859 if (GetLastError() != ERROR_MORE_DATA)
5862 dependencies = msi_alloc(needed);
5866 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5867 needed, &needed, &count))
5870 for (i = 0; i < count; i++)
5872 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5873 SERVICE_STOP | SERVICE_QUERY_STATUS);
5877 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5884 msi_free(dependencies);
5888 static UINT stop_service( LPCWSTR name )
5890 SC_HANDLE scm = NULL, service = NULL;
5891 SERVICE_STATUS status;
5892 SERVICE_STATUS_PROCESS ssp;
5895 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5898 WARN("Failed to open the SCM: %d\n", GetLastError());
5902 service = OpenServiceW(scm, name,
5904 SERVICE_QUERY_STATUS |
5905 SERVICE_ENUMERATE_DEPENDENTS);
5908 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5912 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5913 sizeof(SERVICE_STATUS_PROCESS), &needed))
5915 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5919 if (ssp.dwCurrentState == SERVICE_STOPPED)
5922 stop_service_dependents(scm, service);
5924 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5925 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5928 CloseServiceHandle(service);
5929 CloseServiceHandle(scm);
5931 return ERROR_SUCCESS;
5934 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5936 MSIPACKAGE *package = param;
5940 LPWSTR name = NULL, display_name = NULL;
5944 event = MSI_RecordGetInteger( rec, 3 );
5945 if (!(event & msidbServiceControlEventStop))
5946 return ERROR_SUCCESS;
5948 component = MSI_RecordGetString( rec, 6 );
5949 comp = msi_get_loaded_component( package, component );
5951 return ERROR_SUCCESS;
5953 comp->Action = msi_get_component_action( package, comp );
5954 if (comp->Action != INSTALLSTATE_ABSENT)
5956 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5957 return ERROR_SUCCESS;
5960 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5963 ERR("Failed to open the service control manager\n");
5968 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5969 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5971 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5972 GetServiceDisplayNameW( scm, name, display_name, &len );
5974 CloseServiceHandle( scm );
5976 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5977 stop_service( name );
5980 uirow = MSI_CreateRecord( 2 );
5981 MSI_RecordSetStringW( uirow, 1, display_name );
5982 MSI_RecordSetStringW( uirow, 2, name );
5983 msi_ui_actiondata( package, szStopServices, uirow );
5984 msiobj_release( &uirow->hdr );
5987 msi_free( display_name );
5988 return ERROR_SUCCESS;
5991 static UINT ACTION_StopServices( MSIPACKAGE *package )
5993 static const WCHAR query[] = {
5994 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5995 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5999 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6000 if (rc != ERROR_SUCCESS)
6001 return ERROR_SUCCESS;
6003 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6004 msiobj_release(&view->hdr);
6008 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6010 MSIPACKAGE *package = param;
6013 LPWSTR name = NULL, display_name = NULL;
6015 SC_HANDLE scm = NULL, service = NULL;
6017 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6019 return ERROR_SUCCESS;
6021 event = MSI_RecordGetInteger( rec, 3 );
6022 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6024 comp->Action = msi_get_component_action( package, comp );
6025 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6026 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6028 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6030 return ERROR_SUCCESS;
6032 stop_service( name );
6034 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6037 WARN("Failed to open the SCM: %d\n", GetLastError());
6042 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6043 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6045 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6046 GetServiceDisplayNameW( scm, name, display_name, &len );
6049 service = OpenServiceW( scm, name, DELETE );
6052 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6056 if (!DeleteService( service ))
6057 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6060 uirow = MSI_CreateRecord( 2 );
6061 MSI_RecordSetStringW( uirow, 1, display_name );
6062 MSI_RecordSetStringW( uirow, 2, name );
6063 msi_ui_actiondata( package, szDeleteServices, uirow );
6064 msiobj_release( &uirow->hdr );
6066 CloseServiceHandle( service );
6067 CloseServiceHandle( scm );
6069 msi_free( display_name );
6071 return ERROR_SUCCESS;
6074 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6076 static const WCHAR query[] = {
6077 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6078 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6082 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6083 if (rc != ERROR_SUCCESS)
6084 return ERROR_SUCCESS;
6086 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6087 msiobj_release( &view->hdr );
6091 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6093 MSIPACKAGE *package = param;
6094 LPWSTR driver, driver_path, ptr;
6095 WCHAR outpath[MAX_PATH];
6096 MSIFILE *driver_file = NULL, *setup_file = NULL;
6099 LPCWSTR desc, file_key, component;
6101 UINT r = ERROR_SUCCESS;
6103 static const WCHAR driver_fmt[] = {
6104 'D','r','i','v','e','r','=','%','s',0};
6105 static const WCHAR setup_fmt[] = {
6106 'S','e','t','u','p','=','%','s',0};
6107 static const WCHAR usage_fmt[] = {
6108 'F','i','l','e','U','s','a','g','e','=','1',0};
6110 component = MSI_RecordGetString( rec, 2 );
6111 comp = msi_get_loaded_component( package, component );
6113 return ERROR_SUCCESS;
6115 comp->Action = msi_get_component_action( package, comp );
6116 if (comp->Action != INSTALLSTATE_LOCAL)
6118 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6119 return ERROR_SUCCESS;
6121 desc = MSI_RecordGetString(rec, 3);
6123 file_key = MSI_RecordGetString( rec, 4 );
6124 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6126 file_key = MSI_RecordGetString( rec, 5 );
6127 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6131 ERR("ODBC Driver entry not found!\n");
6132 return ERROR_FUNCTION_FAILED;
6135 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6137 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6138 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6140 driver = msi_alloc(len * sizeof(WCHAR));
6142 return ERROR_OUTOFMEMORY;
6145 lstrcpyW(ptr, desc);
6146 ptr += lstrlenW(ptr) + 1;
6148 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6153 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6157 lstrcpyW(ptr, usage_fmt);
6158 ptr += lstrlenW(ptr) + 1;
6161 if (!driver_file->TargetPath)
6163 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6164 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6166 driver_path = strdupW(driver_file->TargetPath);
6167 ptr = strrchrW(driver_path, '\\');
6168 if (ptr) *ptr = '\0';
6170 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6171 NULL, ODBC_INSTALL_COMPLETE, &usage))
6173 ERR("Failed to install SQL driver!\n");
6174 r = ERROR_FUNCTION_FAILED;
6177 uirow = MSI_CreateRecord( 5 );
6178 MSI_RecordSetStringW( uirow, 1, desc );
6179 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6180 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6181 msi_ui_actiondata( package, szInstallODBC, uirow );
6182 msiobj_release( &uirow->hdr );
6185 msi_free(driver_path);
6190 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6192 MSIPACKAGE *package = param;
6193 LPWSTR translator, translator_path, ptr;
6194 WCHAR outpath[MAX_PATH];
6195 MSIFILE *translator_file = NULL, *setup_file = NULL;
6198 LPCWSTR desc, file_key, component;
6200 UINT r = ERROR_SUCCESS;
6202 static const WCHAR translator_fmt[] = {
6203 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6204 static const WCHAR setup_fmt[] = {
6205 'S','e','t','u','p','=','%','s',0};
6207 component = MSI_RecordGetString( rec, 2 );
6208 comp = msi_get_loaded_component( package, component );
6210 return ERROR_SUCCESS;
6212 comp->Action = msi_get_component_action( package, comp );
6213 if (comp->Action != INSTALLSTATE_LOCAL)
6215 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6216 return ERROR_SUCCESS;
6218 desc = MSI_RecordGetString(rec, 3);
6220 file_key = MSI_RecordGetString( rec, 4 );
6221 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6223 file_key = MSI_RecordGetString( rec, 5 );
6224 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6226 if (!translator_file)
6228 ERR("ODBC Translator entry not found!\n");
6229 return ERROR_FUNCTION_FAILED;
6232 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6234 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6236 translator = msi_alloc(len * sizeof(WCHAR));
6238 return ERROR_OUTOFMEMORY;
6241 lstrcpyW(ptr, desc);
6242 ptr += lstrlenW(ptr) + 1;
6244 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6249 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6254 translator_path = strdupW(translator_file->TargetPath);
6255 ptr = strrchrW(translator_path, '\\');
6256 if (ptr) *ptr = '\0';
6258 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6259 NULL, ODBC_INSTALL_COMPLETE, &usage))
6261 ERR("Failed to install SQL translator!\n");
6262 r = ERROR_FUNCTION_FAILED;
6265 uirow = MSI_CreateRecord( 5 );
6266 MSI_RecordSetStringW( uirow, 1, desc );
6267 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6268 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6269 msi_ui_actiondata( package, szInstallODBC, uirow );
6270 msiobj_release( &uirow->hdr );
6272 msi_free(translator);
6273 msi_free(translator_path);
6278 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6280 MSIPACKAGE *package = param;
6283 LPCWSTR desc, driver, component;
6284 WORD request = ODBC_ADD_SYS_DSN;
6287 UINT r = ERROR_SUCCESS;
6290 static const WCHAR attrs_fmt[] = {
6291 'D','S','N','=','%','s',0 };
6293 component = MSI_RecordGetString( rec, 2 );
6294 comp = msi_get_loaded_component( package, component );
6296 return ERROR_SUCCESS;
6298 comp->Action = msi_get_component_action( package, comp );
6299 if (comp->Action != INSTALLSTATE_LOCAL)
6301 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6302 return ERROR_SUCCESS;
6305 desc = MSI_RecordGetString(rec, 3);
6306 driver = MSI_RecordGetString(rec, 4);
6307 registration = MSI_RecordGetInteger(rec, 5);
6309 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6310 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6312 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6313 attrs = msi_alloc(len * sizeof(WCHAR));
6315 return ERROR_OUTOFMEMORY;
6317 len = sprintfW(attrs, attrs_fmt, desc);
6320 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6322 ERR("Failed to install SQL data source!\n");
6323 r = ERROR_FUNCTION_FAILED;
6326 uirow = MSI_CreateRecord( 5 );
6327 MSI_RecordSetStringW( uirow, 1, desc );
6328 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6329 MSI_RecordSetInteger( uirow, 3, request );
6330 msi_ui_actiondata( package, szInstallODBC, uirow );
6331 msiobj_release( &uirow->hdr );
6338 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6340 static const WCHAR driver_query[] = {
6341 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6342 'O','D','B','C','D','r','i','v','e','r',0};
6343 static const WCHAR translator_query[] = {
6344 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6345 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6346 static const WCHAR source_query[] = {
6347 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6348 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6352 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6353 if (rc == ERROR_SUCCESS)
6355 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6356 msiobj_release(&view->hdr);
6357 if (rc != ERROR_SUCCESS)
6360 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6361 if (rc == ERROR_SUCCESS)
6363 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6364 msiobj_release(&view->hdr);
6365 if (rc != ERROR_SUCCESS)
6368 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6369 if (rc == ERROR_SUCCESS)
6371 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6372 msiobj_release(&view->hdr);
6373 if (rc != ERROR_SUCCESS)
6376 return ERROR_SUCCESS;
6379 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6381 MSIPACKAGE *package = param;
6385 LPCWSTR desc, component;
6387 component = MSI_RecordGetString( rec, 2 );
6388 comp = msi_get_loaded_component( package, component );
6390 return ERROR_SUCCESS;
6392 comp->Action = msi_get_component_action( package, comp );
6393 if (comp->Action != INSTALLSTATE_ABSENT)
6395 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6396 return ERROR_SUCCESS;
6399 desc = MSI_RecordGetString( rec, 3 );
6400 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6402 WARN("Failed to remove ODBC driver\n");
6406 FIXME("Usage count reached 0\n");
6409 uirow = MSI_CreateRecord( 2 );
6410 MSI_RecordSetStringW( uirow, 1, desc );
6411 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6412 msi_ui_actiondata( package, szRemoveODBC, uirow );
6413 msiobj_release( &uirow->hdr );
6415 return ERROR_SUCCESS;
6418 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6420 MSIPACKAGE *package = param;
6424 LPCWSTR desc, component;
6426 component = MSI_RecordGetString( rec, 2 );
6427 comp = msi_get_loaded_component( package, component );
6429 return ERROR_SUCCESS;
6431 comp->Action = msi_get_component_action( package, comp );
6432 if (comp->Action != INSTALLSTATE_ABSENT)
6434 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6435 return ERROR_SUCCESS;
6438 desc = MSI_RecordGetString( rec, 3 );
6439 if (!SQLRemoveTranslatorW( desc, &usage ))
6441 WARN("Failed to remove ODBC translator\n");
6445 FIXME("Usage count reached 0\n");
6448 uirow = MSI_CreateRecord( 2 );
6449 MSI_RecordSetStringW( uirow, 1, desc );
6450 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6451 msi_ui_actiondata( package, szRemoveODBC, uirow );
6452 msiobj_release( &uirow->hdr );
6454 return ERROR_SUCCESS;
6457 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6459 MSIPACKAGE *package = param;
6463 LPCWSTR desc, driver, component;
6464 WORD request = ODBC_REMOVE_SYS_DSN;
6468 static const WCHAR attrs_fmt[] = {
6469 'D','S','N','=','%','s',0 };
6471 component = MSI_RecordGetString( rec, 2 );
6472 comp = msi_get_loaded_component( package, component );
6474 return ERROR_SUCCESS;
6476 comp->Action = msi_get_component_action( package, comp );
6477 if (comp->Action != INSTALLSTATE_ABSENT)
6479 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6480 return ERROR_SUCCESS;
6483 desc = MSI_RecordGetString( rec, 3 );
6484 driver = MSI_RecordGetString( rec, 4 );
6485 registration = MSI_RecordGetInteger( rec, 5 );
6487 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6488 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6490 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6491 attrs = msi_alloc( len * sizeof(WCHAR) );
6493 return ERROR_OUTOFMEMORY;
6495 FIXME("Use ODBCSourceAttribute table\n");
6497 len = sprintfW( attrs, attrs_fmt, desc );
6500 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6502 WARN("Failed to remove ODBC data source\n");
6506 uirow = MSI_CreateRecord( 3 );
6507 MSI_RecordSetStringW( uirow, 1, desc );
6508 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6509 MSI_RecordSetInteger( uirow, 3, request );
6510 msi_ui_actiondata( package, szRemoveODBC, uirow );
6511 msiobj_release( &uirow->hdr );
6513 return ERROR_SUCCESS;
6516 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6518 static const WCHAR driver_query[] = {
6519 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6520 'O','D','B','C','D','r','i','v','e','r',0};
6521 static const WCHAR translator_query[] = {
6522 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6523 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6524 static const WCHAR source_query[] = {
6525 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6526 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6530 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6531 if (rc == ERROR_SUCCESS)
6533 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6534 msiobj_release( &view->hdr );
6535 if (rc != ERROR_SUCCESS)
6538 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6539 if (rc == ERROR_SUCCESS)
6541 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6542 msiobj_release( &view->hdr );
6543 if (rc != ERROR_SUCCESS)
6546 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6547 if (rc == ERROR_SUCCESS)
6549 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6550 msiobj_release( &view->hdr );
6551 if (rc != ERROR_SUCCESS)
6554 return ERROR_SUCCESS;
6557 #define ENV_ACT_SETALWAYS 0x1
6558 #define ENV_ACT_SETABSENT 0x2
6559 #define ENV_ACT_REMOVE 0x4
6560 #define ENV_ACT_REMOVEMATCH 0x8
6562 #define ENV_MOD_MACHINE 0x20000000
6563 #define ENV_MOD_APPEND 0x40000000
6564 #define ENV_MOD_PREFIX 0x80000000
6565 #define ENV_MOD_MASK 0xC0000000
6567 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6569 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6571 LPCWSTR cptr = *name;
6573 static const WCHAR prefix[] = {'[','~',']',0};
6574 static const int prefix_len = 3;
6580 *flags |= ENV_ACT_SETALWAYS;
6581 else if (*cptr == '+')
6582 *flags |= ENV_ACT_SETABSENT;
6583 else if (*cptr == '-')
6584 *flags |= ENV_ACT_REMOVE;
6585 else if (*cptr == '!')
6586 *flags |= ENV_ACT_REMOVEMATCH;
6587 else if (*cptr == '*')
6588 *flags |= ENV_MOD_MACHINE;
6598 ERR("Missing environment variable\n");
6599 return ERROR_FUNCTION_FAILED;
6604 LPCWSTR ptr = *value;
6605 if (!strncmpW(ptr, prefix, prefix_len))
6607 if (ptr[prefix_len] == szSemiColon[0])
6609 *flags |= ENV_MOD_APPEND;
6610 *value += lstrlenW(prefix);
6617 else if (lstrlenW(*value) >= prefix_len)
6619 ptr += lstrlenW(ptr) - prefix_len;
6620 if (!strcmpW( ptr, prefix ))
6622 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6624 *flags |= ENV_MOD_PREFIX;
6625 /* the "[~]" will be removed by deformat_string */;
6635 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6636 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6637 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6638 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6640 ERR("Invalid flags: %08x\n", *flags);
6641 return ERROR_FUNCTION_FAILED;
6645 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6647 return ERROR_SUCCESS;
6650 static UINT open_env_key( DWORD flags, HKEY *key )
6652 static const WCHAR user_env[] =
6653 {'E','n','v','i','r','o','n','m','e','n','t',0};
6654 static const WCHAR machine_env[] =
6655 {'S','y','s','t','e','m','\\',
6656 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6657 'C','o','n','t','r','o','l','\\',
6658 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6659 'E','n','v','i','r','o','n','m','e','n','t',0};
6664 if (flags & ENV_MOD_MACHINE)
6667 root = HKEY_LOCAL_MACHINE;
6672 root = HKEY_CURRENT_USER;
6675 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6676 if (res != ERROR_SUCCESS)
6678 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6679 return ERROR_FUNCTION_FAILED;
6682 return ERROR_SUCCESS;
6685 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6687 MSIPACKAGE *package = param;
6688 LPCWSTR name, value, component;
6689 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6690 DWORD flags, type, size;
6697 component = MSI_RecordGetString(rec, 4);
6698 comp = msi_get_loaded_component(package, component);
6700 return ERROR_SUCCESS;
6702 comp->Action = msi_get_component_action( package, comp );
6703 if (comp->Action != INSTALLSTATE_LOCAL)
6705 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6706 return ERROR_SUCCESS;
6708 name = MSI_RecordGetString(rec, 2);
6709 value = MSI_RecordGetString(rec, 3);
6711 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6713 res = env_parse_flags(&name, &value, &flags);
6714 if (res != ERROR_SUCCESS || !value)
6717 if (value && !deformat_string(package, value, &deformatted))
6719 res = ERROR_OUTOFMEMORY;
6723 value = deformatted;
6725 res = open_env_key( flags, &env );
6726 if (res != ERROR_SUCCESS)
6729 if (flags & ENV_MOD_MACHINE)
6730 action |= 0x20000000;
6734 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6735 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6736 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6739 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6743 /* Nothing to do. */
6746 res = ERROR_SUCCESS;
6750 /* If we are appending but the string was empty, strip ; */
6751 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6753 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6754 newval = strdupW(value);
6757 res = ERROR_OUTOFMEMORY;
6765 /* Contrary to MSDN, +-variable to [~];path works */
6766 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6768 res = ERROR_SUCCESS;
6772 data = msi_alloc(size);
6776 return ERROR_OUTOFMEMORY;
6779 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6780 if (res != ERROR_SUCCESS)
6783 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6786 res = RegDeleteValueW(env, name);
6787 if (res != ERROR_SUCCESS)
6788 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6792 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6793 if (flags & ENV_MOD_MASK)
6797 if (flags & ENV_MOD_APPEND) multiplier++;
6798 if (flags & ENV_MOD_PREFIX) multiplier++;
6799 mod_size = lstrlenW(value) * multiplier;
6800 size += mod_size * sizeof(WCHAR);
6803 newval = msi_alloc(size);
6807 res = ERROR_OUTOFMEMORY;
6811 if (flags & ENV_MOD_PREFIX)
6813 lstrcpyW(newval, value);
6814 ptr = newval + lstrlenW(value);
6815 action |= 0x80000000;
6818 lstrcpyW(ptr, data);
6820 if (flags & ENV_MOD_APPEND)
6822 lstrcatW(newval, value);
6823 action |= 0x40000000;
6826 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6827 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6830 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6834 uirow = MSI_CreateRecord( 3 );
6835 MSI_RecordSetStringW( uirow, 1, name );
6836 MSI_RecordSetStringW( uirow, 2, newval );
6837 MSI_RecordSetInteger( uirow, 3, action );
6838 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6839 msiobj_release( &uirow->hdr );
6841 if (env) RegCloseKey(env);
6842 msi_free(deformatted);
6848 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6850 static const WCHAR query[] = {
6851 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6852 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6856 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6857 if (rc != ERROR_SUCCESS)
6858 return ERROR_SUCCESS;
6860 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6861 msiobj_release(&view->hdr);
6865 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6867 MSIPACKAGE *package = param;
6868 LPCWSTR name, value, component;
6869 LPWSTR deformatted = NULL;
6878 component = MSI_RecordGetString( rec, 4 );
6879 comp = msi_get_loaded_component( package, component );
6881 return ERROR_SUCCESS;
6883 comp->Action = msi_get_component_action( package, comp );
6884 if (comp->Action != INSTALLSTATE_ABSENT)
6886 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6887 return ERROR_SUCCESS;
6889 name = MSI_RecordGetString( rec, 2 );
6890 value = MSI_RecordGetString( rec, 3 );
6892 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6894 r = env_parse_flags( &name, &value, &flags );
6895 if (r != ERROR_SUCCESS)
6898 if (!(flags & ENV_ACT_REMOVE))
6900 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6901 return ERROR_SUCCESS;
6904 if (value && !deformat_string( package, value, &deformatted ))
6905 return ERROR_OUTOFMEMORY;
6907 value = deformatted;
6909 r = open_env_key( flags, &env );
6910 if (r != ERROR_SUCCESS)
6916 if (flags & ENV_MOD_MACHINE)
6917 action |= 0x20000000;
6919 TRACE("Removing %s\n", debugstr_w(name));
6921 res = RegDeleteValueW( env, name );
6922 if (res != ERROR_SUCCESS)
6924 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6929 uirow = MSI_CreateRecord( 3 );
6930 MSI_RecordSetStringW( uirow, 1, name );
6931 MSI_RecordSetStringW( uirow, 2, value );
6932 MSI_RecordSetInteger( uirow, 3, action );
6933 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6934 msiobj_release( &uirow->hdr );
6936 if (env) RegCloseKey( env );
6937 msi_free( deformatted );
6941 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6943 static const WCHAR query[] = {
6944 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6945 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6949 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6950 if (rc != ERROR_SUCCESS)
6951 return ERROR_SUCCESS;
6953 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6954 msiobj_release( &view->hdr );
6958 UINT msi_validate_product_id( MSIPACKAGE *package )
6960 LPWSTR key, template, id;
6961 UINT r = ERROR_SUCCESS;
6963 id = msi_dup_property( package->db, szProductID );
6967 return ERROR_SUCCESS;
6969 template = msi_dup_property( package->db, szPIDTemplate );
6970 key = msi_dup_property( package->db, szPIDKEY );
6971 if (key && template)
6973 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6974 r = msi_set_property( package->db, szProductID, key );
6976 msi_free( template );
6981 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6983 return msi_validate_product_id( package );
6986 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6989 package->need_reboot_at_end = 1;
6990 return ERROR_SUCCESS;
6993 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6995 static const WCHAR szAvailableFreeReg[] =
6996 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6998 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7000 TRACE("%p %d kilobytes\n", package, space);
7002 uirow = MSI_CreateRecord( 1 );
7003 MSI_RecordSetInteger( uirow, 1, space );
7004 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
7005 msiobj_release( &uirow->hdr );
7007 return ERROR_SUCCESS;
7010 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7012 TRACE("%p\n", package);
7014 msi_set_property( package->db, szRollbackDisabled, szOne );
7015 return ERROR_SUCCESS;
7018 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7020 FIXME("%p\n", package);
7021 return ERROR_SUCCESS;
7024 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7026 static const WCHAR driver_query[] = {
7027 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7028 'O','D','B','C','D','r','i','v','e','r',0};
7029 static const WCHAR translator_query[] = {
7030 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7031 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
7035 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7036 if (r == ERROR_SUCCESS)
7039 r = MSI_IterateRecords( view, &count, NULL, package );
7040 msiobj_release( &view->hdr );
7041 if (r != ERROR_SUCCESS)
7043 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7045 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7046 if (r == ERROR_SUCCESS)
7049 r = MSI_IterateRecords( view, &count, NULL, package );
7050 msiobj_release( &view->hdr );
7051 if (r != ERROR_SUCCESS)
7053 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7055 return ERROR_SUCCESS;
7058 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7060 static const WCHAR fmtW[] =
7061 {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0};
7062 MSIPACKAGE *package = param;
7063 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7064 UINT len = sizeof(fmtW)/sizeof(fmtW[0]);
7065 WCHAR *product, *features, *cmd;
7067 PROCESS_INFORMATION info;
7070 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7072 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7074 len += strlenW( product );
7076 len += strlenW( features );
7078 len += sizeof(szAll) / sizeof(szAll[0]);
7080 if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
7082 msi_free( product );
7083 msi_free( features );
7084 return ERROR_OUTOFMEMORY;
7086 sprintfW( cmd, fmtW, product, features ? features : szAll );
7087 msi_free( product );
7088 msi_free( features );
7090 memset( &si, 0, sizeof(STARTUPINFOW) );
7091 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7093 if (!ret) return GetLastError();
7094 CloseHandle( info.hThread );
7096 WaitForSingleObject( info.hProcess, INFINITE );
7097 CloseHandle( info.hProcess );
7098 return ERROR_SUCCESS;
7101 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7103 static const WCHAR query[] = {
7104 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7108 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7109 if (r == ERROR_SUCCESS)
7111 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7112 msiobj_release( &view->hdr );
7113 if (r != ERROR_SUCCESS)
7116 return ERROR_SUCCESS;
7119 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7121 MSIPACKAGE *package = param;
7122 int attributes = MSI_RecordGetInteger( rec, 5 );
7124 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7126 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7127 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7128 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7129 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7133 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7135 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7136 if (r != ERROR_SUCCESS)
7137 return ERROR_SUCCESS;
7141 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7142 if (r != ERROR_SUCCESS)
7143 return ERROR_SUCCESS;
7145 RegCloseKey( hkey );
7147 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7148 debugstr_w(upgrade_code), debugstr_w(version_min),
7149 debugstr_w(version_max), debugstr_w(language));
7151 return ERROR_SUCCESS;
7154 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7156 static const WCHAR query[] = {
7157 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7158 'U','p','g','r','a','d','e',0};
7162 if (msi_get_property_int( package->db, szInstalled, 0 ))
7164 TRACE("product is installed, skipping action\n");
7165 return ERROR_SUCCESS;
7167 if (msi_get_property_int( package->db, szPreselected, 0 ))
7169 TRACE("Preselected property is set, not migrating feature states\n");
7170 return ERROR_SUCCESS;
7172 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7173 if (r == ERROR_SUCCESS)
7175 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7176 msiobj_release( &view->hdr );
7177 if (r != ERROR_SUCCESS)
7180 return ERROR_SUCCESS;
7183 static void bind_image( const char *filename, const char *path )
7185 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7187 WARN("failed to bind image %u\n", GetLastError());
7191 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7195 MSIPACKAGE *package = param;
7196 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7197 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7198 char *filenameA, *pathA;
7199 WCHAR *pathW, **path_list;
7201 if (!(file = msi_get_loaded_file( package, key )))
7203 WARN("file %s not found\n", debugstr_w(key));
7204 return ERROR_SUCCESS;
7206 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7207 path_list = msi_split_string( paths, ';' );
7208 if (!path_list) bind_image( filenameA, NULL );
7211 for (i = 0; path_list[i] && path_list[i][0]; i++)
7213 deformat_string( package, path_list[i], &pathW );
7214 if ((pathA = strdupWtoA( pathW )))
7216 bind_image( filenameA, pathA );
7222 msi_free( path_list );
7223 msi_free( filenameA );
7224 return ERROR_SUCCESS;
7227 static UINT ACTION_BindImage( MSIPACKAGE *package )
7229 static const WCHAR query[] = {
7230 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7231 'B','i','n','d','I','m','a','g','e',0};
7235 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7236 if (r == ERROR_SUCCESS)
7238 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7239 msiobj_release( &view->hdr );
7240 if (r != ERROR_SUCCESS)
7243 return ERROR_SUCCESS;
7246 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7248 static const WCHAR query[] = {
7249 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7254 r = MSI_OpenQuery( package->db, &view, query, table );
7255 if (r == ERROR_SUCCESS)
7257 r = MSI_IterateRecords(view, &count, NULL, package);
7258 msiobj_release(&view->hdr);
7259 if (r != ERROR_SUCCESS)
7262 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7263 return ERROR_SUCCESS;
7266 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7268 static const WCHAR table[] = {
7269 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7270 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7273 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7275 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7276 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7279 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7281 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7282 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7285 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7287 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7288 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7291 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7293 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7294 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7299 const WCHAR *action;
7300 UINT (*handler)(MSIPACKAGE *);
7301 const WCHAR *action_rollback;
7305 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7306 { szAppSearch, ACTION_AppSearch, NULL },
7307 { szBindImage, ACTION_BindImage, NULL },
7308 { szCCPSearch, ACTION_CCPSearch, NULL },
7309 { szCostFinalize, ACTION_CostFinalize, NULL },
7310 { szCostInitialize, ACTION_CostInitialize, NULL },
7311 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7312 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7313 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7314 { szDisableRollback, ACTION_DisableRollback, NULL },
7315 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7316 { szExecuteAction, ACTION_ExecuteAction, NULL },
7317 { szFileCost, ACTION_FileCost, NULL },
7318 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7319 { szForceReboot, ACTION_ForceReboot, NULL },
7320 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7321 { szInstallExecute, ACTION_InstallExecute, NULL },
7322 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7323 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7324 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7325 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7326 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7327 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7328 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7329 { szInstallValidate, ACTION_InstallValidate, NULL },
7330 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7331 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7332 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7333 { szMoveFiles, ACTION_MoveFiles, NULL },
7334 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7335 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7336 { szPatchFiles, ACTION_PatchFiles, NULL },
7337 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7338 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7339 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7340 { szPublishProduct, ACTION_PublishProduct, NULL },
7341 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7342 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7343 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7344 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7345 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7346 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7347 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7348 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7349 { szRegisterUser, ACTION_RegisterUser, NULL },
7350 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7351 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7352 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7353 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7354 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7355 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7356 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7357 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7358 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7359 { szResolveSource, ACTION_ResolveSource, NULL },
7360 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7361 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7362 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7363 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7364 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7365 { szStartServices, ACTION_StartServices, szStopServices },
7366 { szStopServices, ACTION_StopServices, szStartServices },
7367 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7368 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7369 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7370 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7371 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7372 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7373 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7374 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7375 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7376 { szValidateProductID, ACTION_ValidateProductID, NULL },
7377 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7378 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7379 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7380 { NULL, NULL, NULL }
7383 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7389 while (StandardActions[i].action != NULL)
7391 if (!strcmpW( StandardActions[i].action, action ))
7393 ui_actionstart( package, action );
7394 if (StandardActions[i].handler)
7396 ui_actioninfo( package, action, TRUE, 0 );
7397 *rc = StandardActions[i].handler( package );
7398 ui_actioninfo( package, action, FALSE, *rc );
7400 if (StandardActions[i].action_rollback && !package->need_rollback)
7402 TRACE("scheduling rollback action\n");
7403 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7408 FIXME("unhandled standard action %s\n", debugstr_w(action));
7409 *rc = ERROR_SUCCESS;
7419 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7421 UINT rc = ERROR_SUCCESS;
7424 TRACE("Performing action (%s)\n", debugstr_w(action));
7426 handled = ACTION_HandleStandardAction(package, action, &rc);
7429 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7433 WARN("unhandled msi action %s\n", debugstr_w(action));
7434 rc = ERROR_FUNCTION_NOT_CALLED;
7440 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7442 UINT rc = ERROR_SUCCESS;
7443 BOOL handled = FALSE;
7445 TRACE("Performing action (%s)\n", debugstr_w(action));
7447 package->action_progress_increment = 0;
7448 handled = ACTION_HandleStandardAction(package, action, &rc);
7451 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7453 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7458 WARN("unhandled msi action %s\n", debugstr_w(action));
7459 rc = ERROR_FUNCTION_NOT_CALLED;
7465 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7467 UINT rc = ERROR_SUCCESS;
7470 static const WCHAR query[] =
7471 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7472 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7473 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7474 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7475 static const WCHAR ui_query[] =
7476 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7477 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7478 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7479 ' ', '=',' ','%','i',0};
7481 if (needs_ui_sequence(package))
7482 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7484 row = MSI_QueryGetRecord(package->db, query, seq);
7488 LPCWSTR action, cond;
7490 TRACE("Running the actions\n");
7492 /* check conditions */
7493 cond = MSI_RecordGetString(row, 2);
7495 /* this is a hack to skip errors in the condition code */
7496 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7498 msiobj_release(&row->hdr);
7499 return ERROR_SUCCESS;
7502 action = MSI_RecordGetString(row, 1);
7505 ERR("failed to fetch action\n");
7506 msiobj_release(&row->hdr);
7507 return ERROR_FUNCTION_FAILED;
7510 if (needs_ui_sequence(package))
7511 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7513 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7515 msiobj_release(&row->hdr);
7521 /****************************************************
7522 * TOP level entry points
7523 *****************************************************/
7525 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7526 LPCWSTR szCommandLine )
7528 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7529 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7530 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7531 WCHAR *reinstall = NULL;
7535 msi_set_property( package->db, szAction, szInstall );
7537 package->script->InWhatSequence = SEQUENCE_INSTALL;
7544 dir = strdupW(szPackagePath);
7545 p = strrchrW(dir, '\\');
7549 file = szPackagePath + (p - dir);
7554 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7555 GetCurrentDirectoryW(MAX_PATH, dir);
7556 lstrcatW(dir, szBackSlash);
7557 file = szPackagePath;
7560 msi_free( package->PackagePath );
7561 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7562 if (!package->PackagePath)
7565 return ERROR_OUTOFMEMORY;
7568 lstrcpyW(package->PackagePath, dir);
7569 lstrcatW(package->PackagePath, file);
7572 msi_set_sourcedir_props(package, FALSE);
7575 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7576 if (rc != ERROR_SUCCESS)
7579 msi_apply_transforms( package );
7580 msi_apply_patches( package );
7582 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7584 TRACE("setting reinstall property\n");
7585 msi_set_property( package->db, szReinstall, szAll );
7588 /* properties may have been added by a transform */
7589 msi_clone_properties( package );
7591 msi_parse_command_line( package, szCommandLine, FALSE );
7592 msi_adjust_privilege_properties( package );
7593 msi_set_context( package );
7595 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7597 TRACE("disabling rollback\n");
7598 msi_set_property( package->db, szRollbackDisabled, szOne );
7601 if (needs_ui_sequence( package))
7603 package->script->InWhatSequence |= SEQUENCE_UI;
7604 rc = ACTION_ProcessUISequence(package);
7605 ui_exists = ui_sequence_exists(package);
7606 if (rc == ERROR_SUCCESS || !ui_exists)
7608 package->script->InWhatSequence |= SEQUENCE_EXEC;
7609 rc = ACTION_ProcessExecSequence(package, ui_exists);
7613 rc = ACTION_ProcessExecSequence(package, FALSE);
7615 package->script->CurrentlyScripting = FALSE;
7617 /* process the ending type action */
7618 if (rc == ERROR_SUCCESS)
7619 ACTION_PerformActionSequence(package, -1);
7620 else if (rc == ERROR_INSTALL_USEREXIT)
7621 ACTION_PerformActionSequence(package, -2);
7622 else if (rc == ERROR_INSTALL_SUSPEND)
7623 ACTION_PerformActionSequence(package, -4);
7626 ACTION_PerformActionSequence(package, -3);
7627 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7629 package->need_rollback = TRUE;
7633 /* finish up running custom actions */
7634 ACTION_FinishCustomActions(package);
7636 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7638 WARN("installation failed, running rollback script\n");
7639 execute_script( package, SCRIPT_ROLLBACK );
7641 msi_free( reinstall );
7643 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7644 return ERROR_SUCCESS_REBOOT_REQUIRED;