2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
191 sprintfW(message,template_s,timet,action);
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
221 case state_whitespace:
231 if (in_quotes && p[1] != '\"') count--;
247 if (in_quotes) count--;
251 state = state_whitespace;
252 if (!count) goto done;
257 if (!count) in_quotes = 0;
268 if (in_quotes && p[1] != '\"') count--;
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
279 if (!count) in_quotes = 0;
288 if (!ignore) *out++ = *p;
292 if (!len) *value = 0;
299 static void remove_quotes( WCHAR *str )
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
321 return ERROR_SUCCESS;
326 while (*ptr == ' ') ptr++;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
338 if (!preserve_case) struprW( prop );
341 while (*ptr2 == ' ') ptr2++;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
348 WARN("unbalanced quotes\n");
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
372 LPWSTR p, *ret = NULL;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
395 for( count = 0; (ret[count] = p); count++ )
397 p = strchrW( p, sep );
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 db = msi_dup_property( package->db, szOriginalDatabase );
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
448 p = strrchrW( db, '/' );
452 return ERROR_SUCCESS;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
543 rc = ACTION_ForceReboot( package );
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property(package->db, szSourceDir, NULL);
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
736 if (!(slash = strrchrW( new_path, '\\' )))
741 len = slash - new_path;
743 if (!msi_create_full_path( new_path ))
748 new_path[len] = '\\';
750 msi_free( new_path );
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 return comp->ActionRequest;
815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
817 if (package->need_rollback) return feature->Installed;
818 return feature->ActionRequest;
821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
823 MSIPACKAGE *package = param;
824 LPCWSTR dir, component, full_path;
829 component = MSI_RecordGetString(row, 2);
831 return ERROR_SUCCESS;
833 comp = msi_get_loaded_component(package, component);
835 return ERROR_SUCCESS;
837 comp->Action = msi_get_component_action( package, comp );
838 if (comp->Action != INSTALLSTATE_LOCAL)
840 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
841 return ERROR_SUCCESS;
844 dir = MSI_RecordGetString(row,1);
847 ERR("Unable to get folder id\n");
848 return ERROR_SUCCESS;
851 uirow = MSI_CreateRecord(1);
852 MSI_RecordSetStringW(uirow, 1, dir);
853 msi_ui_actiondata(package, szCreateFolders, uirow);
854 msiobj_release(&uirow->hdr);
856 full_path = msi_get_target_folder( package, dir );
859 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
860 return ERROR_SUCCESS;
862 TRACE("folder is %s\n", debugstr_w(full_path));
864 folder = msi_get_loaded_folder( package, dir );
865 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
866 folder->State = FOLDER_STATE_CREATED;
867 return ERROR_SUCCESS;
870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
872 static const WCHAR query[] = {
873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
874 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
879 if (rc != ERROR_SUCCESS)
880 return ERROR_SUCCESS;
882 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
883 msiobj_release(&view->hdr);
887 static void remove_persistent_folder( MSIFOLDER *folder )
891 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
893 remove_persistent_folder( fl->folder );
895 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
897 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
903 MSIPACKAGE *package = param;
904 LPCWSTR dir, component, full_path;
909 component = MSI_RecordGetString(row, 2);
911 return ERROR_SUCCESS;
913 comp = msi_get_loaded_component(package, component);
915 return ERROR_SUCCESS;
917 comp->Action = msi_get_component_action( package, comp );
918 if (comp->Action != INSTALLSTATE_ABSENT)
920 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
921 return ERROR_SUCCESS;
924 dir = MSI_RecordGetString( row, 1 );
927 ERR("Unable to get folder id\n");
928 return ERROR_SUCCESS;
931 full_path = msi_get_target_folder( package, dir );
934 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
935 return ERROR_SUCCESS;
937 TRACE("folder is %s\n", debugstr_w(full_path));
939 uirow = MSI_CreateRecord( 1 );
940 MSI_RecordSetStringW( uirow, 1, dir );
941 msi_ui_actiondata( package, szRemoveFolders, uirow );
942 msiobj_release( &uirow->hdr );
944 folder = msi_get_loaded_folder( package, dir );
945 remove_persistent_folder( folder );
946 return ERROR_SUCCESS;
949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
951 static const WCHAR query[] = {
952 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
953 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
957 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
958 if (rc != ERROR_SUCCESS)
959 return ERROR_SUCCESS;
961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
962 msiobj_release( &view->hdr );
966 static UINT load_component( MSIRECORD *row, LPVOID param )
968 MSIPACKAGE *package = param;
971 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
973 return ERROR_FUNCTION_FAILED;
975 list_add_tail( &package->components, &comp->entry );
977 /* fill in the data */
978 comp->Component = msi_dup_record_field( row, 1 );
980 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
982 comp->ComponentId = msi_dup_record_field( row, 2 );
983 comp->Directory = msi_dup_record_field( row, 3 );
984 comp->Attributes = MSI_RecordGetInteger(row,4);
985 comp->Condition = msi_dup_record_field( row, 5 );
986 comp->KeyPath = msi_dup_record_field( row, 6 );
988 comp->Installed = INSTALLSTATE_UNKNOWN;
989 comp->Action = INSTALLSTATE_UNKNOWN;
990 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
992 comp->assembly = msi_load_assembly( package, comp );
993 return ERROR_SUCCESS;
996 UINT msi_load_all_components( MSIPACKAGE *package )
998 static const WCHAR query[] = {
999 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1000 '`','C','o','m','p','o','n','e','n','t','`',0};
1004 if (!list_empty(&package->components))
1005 return ERROR_SUCCESS;
1007 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1008 if (r != ERROR_SUCCESS)
1011 if (!msi_init_assembly_caches( package ))
1013 ERR("can't initialize assembly caches\n");
1014 msiobj_release( &view->hdr );
1015 return ERROR_FUNCTION_FAILED;
1018 r = MSI_IterateRecords(view, NULL, load_component, package);
1019 msiobj_release(&view->hdr);
1020 msi_destroy_assembly_caches( package );
1025 MSIPACKAGE *package;
1026 MSIFEATURE *feature;
1029 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1033 cl = msi_alloc( sizeof (*cl) );
1035 return ERROR_NOT_ENOUGH_MEMORY;
1036 cl->component = comp;
1037 list_add_tail( &feature->Components, &cl->entry );
1039 return ERROR_SUCCESS;
1042 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1046 fl = msi_alloc( sizeof(*fl) );
1048 return ERROR_NOT_ENOUGH_MEMORY;
1049 fl->feature = child;
1050 list_add_tail( &parent->Children, &fl->entry );
1052 return ERROR_SUCCESS;
1055 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1057 _ilfs* ilfs = param;
1061 component = MSI_RecordGetString(row,1);
1063 /* check to see if the component is already loaded */
1064 comp = msi_get_loaded_component( ilfs->package, component );
1067 WARN("ignoring unknown component %s\n", debugstr_w(component));
1068 return ERROR_SUCCESS;
1070 add_feature_component( ilfs->feature, comp );
1071 comp->Enabled = TRUE;
1073 return ERROR_SUCCESS;
1076 static UINT load_feature(MSIRECORD * row, LPVOID param)
1078 static const WCHAR query[] = {
1079 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1080 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1081 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1082 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1083 MSIPACKAGE *package = param;
1084 MSIFEATURE *feature;
1089 /* fill in the data */
1091 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1093 return ERROR_NOT_ENOUGH_MEMORY;
1095 list_init( &feature->Children );
1096 list_init( &feature->Components );
1098 feature->Feature = msi_dup_record_field( row, 1 );
1100 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1102 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1103 feature->Title = msi_dup_record_field( row, 3 );
1104 feature->Description = msi_dup_record_field( row, 4 );
1106 if (!MSI_RecordIsNull(row,5))
1107 feature->Display = MSI_RecordGetInteger(row,5);
1109 feature->Level= MSI_RecordGetInteger(row,6);
1110 feature->Directory = msi_dup_record_field( row, 7 );
1111 feature->Attributes = MSI_RecordGetInteger(row,8);
1113 feature->Installed = INSTALLSTATE_UNKNOWN;
1114 feature->Action = INSTALLSTATE_UNKNOWN;
1115 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1117 list_add_tail( &package->features, &feature->entry );
1119 /* load feature components */
1121 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1125 ilfs.package = package;
1126 ilfs.feature = feature;
1128 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1129 msiobj_release(&view->hdr);
1133 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1135 MSIPACKAGE *package = param;
1136 MSIFEATURE *parent, *child;
1138 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1140 return ERROR_FUNCTION_FAILED;
1142 if (!child->Feature_Parent)
1143 return ERROR_SUCCESS;
1145 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1147 return ERROR_FUNCTION_FAILED;
1149 add_feature_child( parent, child );
1150 return ERROR_SUCCESS;
1153 UINT msi_load_all_features( MSIPACKAGE *package )
1155 static const WCHAR query[] = {
1156 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1157 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1158 '`','D','i','s','p','l','a','y','`',0};
1162 if (!list_empty(&package->features))
1163 return ERROR_SUCCESS;
1165 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1166 if (r != ERROR_SUCCESS)
1169 r = MSI_IterateRecords( view, NULL, load_feature, package );
1170 if (r != ERROR_SUCCESS)
1172 msiobj_release( &view->hdr );
1175 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1176 msiobj_release( &view->hdr );
1180 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1191 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1193 static const WCHAR query[] = {
1194 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1195 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1196 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1197 MSIQUERY *view = NULL;
1198 MSIRECORD *row = NULL;
1201 TRACE("%s\n", debugstr_w(file->File));
1203 r = MSI_OpenQuery(package->db, &view, query, file->File);
1204 if (r != ERROR_SUCCESS)
1207 r = MSI_ViewExecute(view, NULL);
1208 if (r != ERROR_SUCCESS)
1211 r = MSI_ViewFetch(view, &row);
1212 if (r != ERROR_SUCCESS)
1215 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1216 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1217 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1218 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1219 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1222 if (view) msiobj_release(&view->hdr);
1223 if (row) msiobj_release(&row->hdr);
1227 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1230 static const WCHAR query[] = {
1231 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1232 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1233 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1235 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1238 WARN("query failed\n");
1239 return ERROR_FUNCTION_FAILED;
1242 file->disk_id = MSI_RecordGetInteger( row, 1 );
1243 msiobj_release( &row->hdr );
1244 return ERROR_SUCCESS;
1247 static UINT load_file(MSIRECORD *row, LPVOID param)
1249 MSIPACKAGE* package = param;
1253 /* fill in the data */
1255 file = msi_alloc_zero( sizeof (MSIFILE) );
1257 return ERROR_NOT_ENOUGH_MEMORY;
1259 file->File = msi_dup_record_field( row, 1 );
1261 component = MSI_RecordGetString( row, 2 );
1262 file->Component = msi_get_loaded_component( package, component );
1264 if (!file->Component)
1266 WARN("Component not found: %s\n", debugstr_w(component));
1267 msi_free(file->File);
1269 return ERROR_SUCCESS;
1272 file->FileName = msi_dup_record_field( row, 3 );
1273 msi_reduce_to_long_filename( file->FileName );
1275 file->ShortName = msi_dup_record_field( row, 3 );
1276 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1278 file->FileSize = MSI_RecordGetInteger( row, 4 );
1279 file->Version = msi_dup_record_field( row, 5 );
1280 file->Language = msi_dup_record_field( row, 6 );
1281 file->Attributes = MSI_RecordGetInteger( row, 7 );
1282 file->Sequence = MSI_RecordGetInteger( row, 8 );
1284 file->state = msifs_invalid;
1286 /* if the compressed bits are not set in the file attributes,
1287 * then read the information from the package word count property
1289 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1291 file->IsCompressed = FALSE;
1293 else if (file->Attributes &
1294 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1296 file->IsCompressed = TRUE;
1298 else if (file->Attributes & msidbFileAttributesNoncompressed)
1300 file->IsCompressed = FALSE;
1304 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1307 load_file_hash(package, file);
1308 load_file_disk_id(package, file);
1310 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1312 list_add_tail( &package->files, &file->entry );
1314 return ERROR_SUCCESS;
1317 static UINT load_all_files(MSIPACKAGE *package)
1319 static const WCHAR query[] = {
1320 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1321 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1322 '`','S','e','q','u','e','n','c','e','`', 0};
1326 if (!list_empty(&package->files))
1327 return ERROR_SUCCESS;
1329 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1330 if (rc != ERROR_SUCCESS)
1331 return ERROR_SUCCESS;
1333 rc = MSI_IterateRecords(view, NULL, load_file, package);
1334 msiobj_release(&view->hdr);
1338 static UINT load_media( MSIRECORD *row, LPVOID param )
1340 MSIPACKAGE *package = param;
1341 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1342 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1344 /* FIXME: load external cabinets and directory sources too */
1345 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1346 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1347 return ERROR_SUCCESS;
1350 static UINT load_all_media( MSIPACKAGE *package )
1352 static const WCHAR query[] = {
1353 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1354 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1355 '`','D','i','s','k','I','d','`',0};
1359 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1360 if (r != ERROR_SUCCESS)
1361 return ERROR_SUCCESS;
1363 r = MSI_IterateRecords( view, NULL, load_media, package );
1364 msiobj_release( &view->hdr );
1368 static UINT load_patch(MSIRECORD *row, LPVOID param)
1370 MSIPACKAGE *package = param;
1371 MSIFILEPATCH *patch;
1374 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1376 return ERROR_NOT_ENOUGH_MEMORY;
1378 file_key = msi_dup_record_field( row, 1 );
1379 patch->File = msi_get_loaded_file( package, file_key );
1384 ERR("Failed to find target for patch in File table\n");
1386 return ERROR_FUNCTION_FAILED;
1389 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1391 /* FIXME: The database should be properly transformed */
1392 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1394 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1395 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1396 patch->IsApplied = FALSE;
1399 * Header field - for patch validation.
1400 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1403 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1405 list_add_tail( &package->filepatches, &patch->entry );
1407 return ERROR_SUCCESS;
1410 static UINT load_all_patches(MSIPACKAGE *package)
1412 static const WCHAR query[] = {
1413 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1414 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1415 '`','S','e','q','u','e','n','c','e','`',0};
1419 if (!list_empty(&package->filepatches))
1420 return ERROR_SUCCESS;
1422 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1423 if (rc != ERROR_SUCCESS)
1424 return ERROR_SUCCESS;
1426 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1427 msiobj_release(&view->hdr);
1431 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1433 static const WCHAR query[] = {
1434 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1435 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1436 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1439 folder->persistent = FALSE;
1440 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1442 if (!MSI_ViewExecute( view, NULL ))
1445 if (!MSI_ViewFetch( view, &rec ))
1447 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1448 folder->persistent = TRUE;
1449 msiobj_release( &rec->hdr );
1452 msiobj_release( &view->hdr );
1454 return ERROR_SUCCESS;
1457 static UINT load_folder( MSIRECORD *row, LPVOID param )
1459 MSIPACKAGE *package = param;
1460 static WCHAR szEmpty[] = { 0 };
1461 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1464 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1465 list_init( &folder->children );
1466 folder->Directory = msi_dup_record_field( row, 1 );
1467 folder->Parent = msi_dup_record_field( row, 2 );
1468 p = msi_dup_record_field(row, 3);
1470 TRACE("%s\n", debugstr_w(folder->Directory));
1472 /* split src and target dir */
1474 src_short = folder_split_path( p, ':' );
1476 /* split the long and short paths */
1477 tgt_long = folder_split_path( tgt_short, '|' );
1478 src_long = folder_split_path( src_short, '|' );
1480 /* check for no-op dirs */
1481 if (tgt_short && !strcmpW( szDot, tgt_short ))
1482 tgt_short = szEmpty;
1483 if (src_short && !strcmpW( szDot, src_short ))
1484 src_short = szEmpty;
1487 tgt_long = tgt_short;
1490 src_short = tgt_short;
1491 src_long = tgt_long;
1495 src_long = src_short;
1497 /* FIXME: use the target short path too */
1498 folder->TargetDefault = strdupW(tgt_long);
1499 folder->SourceShortPath = strdupW(src_short);
1500 folder->SourceLongPath = strdupW(src_long);
1503 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1504 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1505 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1507 load_folder_persistence( package, folder );
1509 list_add_tail( &package->folders, &folder->entry );
1510 return ERROR_SUCCESS;
1513 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1517 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1519 list_add_tail( &parent->children, &fl->entry );
1520 return ERROR_SUCCESS;
1523 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1525 MSIPACKAGE *package = param;
1526 MSIFOLDER *parent, *child;
1528 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1529 return ERROR_FUNCTION_FAILED;
1531 if (!child->Parent) return ERROR_SUCCESS;
1533 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1534 return ERROR_FUNCTION_FAILED;
1536 return add_folder_child( parent, child );
1539 static UINT load_all_folders( MSIPACKAGE *package )
1541 static const WCHAR query[] = {
1542 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1543 '`','D','i','r','e','c','t','o','r','y','`',0};
1547 if (!list_empty(&package->folders))
1548 return ERROR_SUCCESS;
1550 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1551 if (r != ERROR_SUCCESS)
1554 r = MSI_IterateRecords( view, NULL, load_folder, package );
1555 if (r != ERROR_SUCCESS)
1557 msiobj_release( &view->hdr );
1560 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1561 msiobj_release( &view->hdr );
1565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1567 msi_set_property( package->db, szCostingComplete, szZero );
1568 msi_set_property( package->db, szRootDrive, szCRoot );
1570 load_all_folders( package );
1571 msi_load_all_components( package );
1572 msi_load_all_features( package );
1573 load_all_files( package );
1574 load_all_patches( package );
1575 load_all_media( package );
1577 return ERROR_SUCCESS;
1580 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1582 const WCHAR *action = package->script->Actions[script][index];
1583 ui_actionstart( package, action );
1584 TRACE("executing %s\n", debugstr_w(action));
1585 return ACTION_PerformAction( package, action, script );
1588 static UINT execute_script( MSIPACKAGE *package, UINT script )
1590 UINT i, rc = ERROR_SUCCESS;
1592 TRACE("executing script %u\n", script);
1594 if (!package->script)
1596 ERR("no script!\n");
1597 return ERROR_FUNCTION_FAILED;
1599 if (script == SCRIPT_ROLLBACK)
1601 for (i = package->script->ActionCount[script]; i > 0; i--)
1603 rc = execute_script_action( package, script, i - 1 );
1604 if (rc != ERROR_SUCCESS) break;
1609 for (i = 0; i < package->script->ActionCount[script]; i++)
1611 rc = execute_script_action( package, script, i );
1612 if (rc != ERROR_SUCCESS) break;
1615 msi_free_action_script(package, script);
1619 static UINT ACTION_FileCost(MSIPACKAGE *package)
1621 return ERROR_SUCCESS;
1624 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1629 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1631 if (!comp->ComponentId) continue;
1633 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1634 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1636 if (r == ERROR_SUCCESS) continue;
1638 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1639 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1641 if (r == ERROR_SUCCESS) continue;
1643 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1644 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1646 if (r == ERROR_SUCCESS) continue;
1648 comp->Installed = INSTALLSTATE_ABSENT;
1652 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1654 MSIFEATURE *feature;
1656 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1658 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1660 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1661 feature->Installed = INSTALLSTATE_ABSENT;
1663 feature->Installed = state;
1667 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1669 return (feature->Level > 0 && feature->Level <= level);
1672 static BOOL process_state_property(MSIPACKAGE* package, int level,
1673 LPCWSTR property, INSTALLSTATE state)
1676 MSIFEATURE *feature;
1678 override = msi_dup_property( package->db, property );
1682 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1684 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1687 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1689 if (!strcmpiW( override, szAll ))
1691 if (feature->Installed != state)
1693 feature->Action = state;
1694 feature->ActionRequest = state;
1699 LPWSTR ptr = override;
1700 LPWSTR ptr2 = strchrW(override,',');
1704 int len = ptr2 - ptr;
1706 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1707 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1709 if (feature->Installed != state)
1711 feature->Action = state;
1712 feature->ActionRequest = state;
1719 ptr2 = strchrW(ptr,',');
1730 static BOOL process_overrides( MSIPACKAGE *package, int level )
1732 static const WCHAR szAddLocal[] =
1733 {'A','D','D','L','O','C','A','L',0};
1734 static const WCHAR szAddSource[] =
1735 {'A','D','D','S','O','U','R','C','E',0};
1736 static const WCHAR szAdvertise[] =
1737 {'A','D','V','E','R','T','I','S','E',0};
1740 /* all these activation/deactivation things happen in order and things
1741 * later on the list override things earlier on the list.
1743 * 0 INSTALLLEVEL processing
1756 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1757 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1758 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1759 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1760 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1763 msi_set_property( package->db, szPreselected, szOne );
1768 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1771 MSICOMPONENT* component;
1772 MSIFEATURE *feature;
1774 TRACE("Checking Install Level\n");
1776 level = msi_get_property_int(package->db, szInstallLevel, 1);
1778 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1780 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1782 if (!is_feature_selected( feature, level )) continue;
1784 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1786 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1788 feature->Action = INSTALLSTATE_SOURCE;
1789 feature->ActionRequest = INSTALLSTATE_SOURCE;
1791 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1793 feature->Action = INSTALLSTATE_ADVERTISED;
1794 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1798 feature->Action = INSTALLSTATE_LOCAL;
1799 feature->ActionRequest = INSTALLSTATE_LOCAL;
1803 /* disable child features of unselected parent or follow parent */
1804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1808 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1810 if (!is_feature_selected( feature, level ))
1812 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1813 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1815 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1817 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1818 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1819 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1820 fl->feature->Action = feature->Action;
1821 fl->feature->ActionRequest = feature->ActionRequest;
1826 else /* preselected */
1828 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1830 if (!is_feature_selected( feature, level )) continue;
1832 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1834 if (feature->Installed == INSTALLSTATE_ABSENT)
1836 feature->Action = INSTALLSTATE_UNKNOWN;
1837 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1841 feature->Action = feature->Installed;
1842 feature->ActionRequest = feature->Installed;
1846 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1850 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1852 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1853 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1855 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1856 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1857 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1858 fl->feature->Action = feature->Action;
1859 fl->feature->ActionRequest = feature->ActionRequest;
1865 /* now we want to set component state based based on feature state */
1866 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1870 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1871 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1872 feature->ActionRequest, feature->Action);
1874 if (!is_feature_selected( feature, level )) continue;
1876 /* features with components that have compressed files are made local */
1877 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1879 if (cl->component->ForceLocalState &&
1880 feature->ActionRequest == INSTALLSTATE_SOURCE)
1882 feature->Action = INSTALLSTATE_LOCAL;
1883 feature->ActionRequest = INSTALLSTATE_LOCAL;
1888 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1890 component = cl->component;
1892 switch (feature->ActionRequest)
1894 case INSTALLSTATE_ABSENT:
1895 component->anyAbsent = 1;
1897 case INSTALLSTATE_ADVERTISED:
1898 component->hasAdvertiseFeature = 1;
1900 case INSTALLSTATE_SOURCE:
1901 component->hasSourceFeature = 1;
1903 case INSTALLSTATE_LOCAL:
1904 component->hasLocalFeature = 1;
1906 case INSTALLSTATE_DEFAULT:
1907 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1908 component->hasAdvertiseFeature = 1;
1909 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1910 component->hasSourceFeature = 1;
1912 component->hasLocalFeature = 1;
1920 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1922 /* check if it's local or source */
1923 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1924 (component->hasLocalFeature || component->hasSourceFeature))
1926 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1927 !component->ForceLocalState)
1929 component->Action = INSTALLSTATE_SOURCE;
1930 component->ActionRequest = INSTALLSTATE_SOURCE;
1934 component->Action = INSTALLSTATE_LOCAL;
1935 component->ActionRequest = INSTALLSTATE_LOCAL;
1940 /* if any feature is local, the component must be local too */
1941 if (component->hasLocalFeature)
1943 component->Action = INSTALLSTATE_LOCAL;
1944 component->ActionRequest = INSTALLSTATE_LOCAL;
1947 if (component->hasSourceFeature)
1949 component->Action = INSTALLSTATE_SOURCE;
1950 component->ActionRequest = INSTALLSTATE_SOURCE;
1953 if (component->hasAdvertiseFeature)
1955 component->Action = INSTALLSTATE_ADVERTISED;
1956 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1959 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1960 if (component->anyAbsent &&
1961 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1963 component->Action = INSTALLSTATE_ABSENT;
1964 component->ActionRequest = INSTALLSTATE_ABSENT;
1968 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1970 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1972 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1973 component->Action = INSTALLSTATE_LOCAL;
1974 component->ActionRequest = INSTALLSTATE_LOCAL;
1977 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1978 component->Installed == INSTALLSTATE_SOURCE &&
1979 component->hasSourceFeature)
1981 component->Action = INSTALLSTATE_UNKNOWN;
1982 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1985 TRACE("component %s (installed %d request %d action %d)\n",
1986 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1989 return ERROR_SUCCESS;
1992 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1994 MSIPACKAGE *package = param;
1996 MSIFEATURE *feature;
1998 name = MSI_RecordGetString( row, 1 );
2000 feature = msi_get_loaded_feature( package, name );
2002 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2006 Condition = MSI_RecordGetString(row,3);
2008 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2010 int level = MSI_RecordGetInteger(row,2);
2011 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2012 feature->Level = level;
2015 return ERROR_SUCCESS;
2018 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2020 static const WCHAR name[] = {'\\',0};
2021 VS_FIXEDFILEINFO *ptr, *ret;
2023 DWORD versize, handle;
2026 versize = GetFileVersionInfoSizeW( filename, &handle );
2030 version = msi_alloc( versize );
2034 GetFileVersionInfoW( filename, 0, versize, version );
2036 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2038 msi_free( version );
2042 ret = msi_alloc( sz );
2043 memcpy( ret, ptr, sz );
2045 msi_free( version );
2049 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2053 msi_parse_version_string( version, &ms, &ls );
2055 if (fi->dwFileVersionMS > ms) return 1;
2056 else if (fi->dwFileVersionMS < ms) return -1;
2057 else if (fi->dwFileVersionLS > ls) return 1;
2058 else if (fi->dwFileVersionLS < ls) return -1;
2062 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2066 msi_parse_version_string( ver1, &ms1, NULL );
2067 msi_parse_version_string( ver2, &ms2, NULL );
2069 if (ms1 > ms2) return 1;
2070 else if (ms1 < ms2) return -1;
2074 DWORD msi_get_disk_file_size( LPCWSTR filename )
2079 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2080 if (file == INVALID_HANDLE_VALUE)
2081 return INVALID_FILE_SIZE;
2083 size = GetFileSize( file, NULL );
2084 TRACE("size is %u\n", size);
2085 CloseHandle( file );
2089 BOOL msi_file_hash_matches( MSIFILE *file )
2092 MSIFILEHASHINFO hash;
2094 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2095 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2096 if (r != ERROR_SUCCESS)
2099 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2102 static WCHAR *get_temp_dir( void )
2105 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2107 GetTempPathW( MAX_PATH, tmp );
2110 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2111 if (CreateDirectoryW( dir, NULL )) break;
2113 return strdupW( dir );
2117 * msi_build_directory_name()
2119 * This function is to save messing round with directory names
2120 * It handles adding backslashes between path segments,
2121 * and can add \ at the end of the directory name if told to.
2123 * It takes a variable number of arguments.
2124 * It always allocates a new string for the result, so make sure
2125 * to free the return value when finished with it.
2127 * The first arg is the number of path segments that follow.
2128 * The arguments following count are a list of path segments.
2129 * A path segment may be NULL.
2131 * Path segments will be added with a \ separating them.
2132 * A \ will not be added after the last segment, however if the
2133 * last segment is NULL, then the last character will be a \
2135 WCHAR *msi_build_directory_name( DWORD count, ... )
2141 va_start( va, count );
2142 for (i = 0; i < count; i++)
2144 const WCHAR *str = va_arg( va, const WCHAR * );
2145 if (str) sz += strlenW( str ) + 1;
2149 dir = msi_alloc( sz * sizeof(WCHAR) );
2152 va_start( va, count );
2153 for (i = 0; i < count; i++)
2155 const WCHAR *str = va_arg( va, const WCHAR * );
2157 strcatW( dir, str );
2158 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2166 MSIASSEMBLY *assembly = file->Component->assembly;
2168 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2170 msi_free( file->TargetPath );
2171 if (assembly && !assembly->application)
2173 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2174 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2175 msi_track_tempfile( package, file->TargetPath );
2179 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2180 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2183 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2186 static UINT calculate_file_cost( MSIPACKAGE *package )
2188 VS_FIXEDFILEINFO *file_version;
2189 WCHAR *font_version;
2192 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2194 MSICOMPONENT *comp = file->Component;
2197 if (!comp->Enabled) continue;
2199 if (file->IsCompressed)
2200 comp->ForceLocalState = TRUE;
2202 set_target_path( package, file );
2204 if ((comp->assembly && !comp->assembly->installed) ||
2205 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2207 comp->Cost += file->FileSize;
2210 file_size = msi_get_disk_file_size( file->TargetPath );
2214 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2216 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2218 comp->Cost += file->FileSize - file_size;
2220 msi_free( file_version );
2223 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2225 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2227 comp->Cost += file->FileSize - file_size;
2229 msi_free( font_version );
2233 if (file_size != file->FileSize)
2235 comp->Cost += file->FileSize - file_size;
2238 return ERROR_SUCCESS;
2241 WCHAR *msi_normalize_path( const WCHAR *in )
2243 const WCHAR *p = in;
2245 int n, len = strlenW( in ) + 2;
2247 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2252 /* copy until the end of the string or a space */
2253 while (*p != ' ' && (*q = *p))
2256 /* reduce many backslashes to one */
2257 if (*p != '\\' || *q != '\\')
2261 /* quit at the end of the string */
2265 /* count the number of spaces */
2270 /* if it's leading or trailing space, skip it */
2271 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2273 else /* copy n spaces */
2274 while (n && (*q++ = *p++)) n--;
2276 while (q - ret > 0 && q[-1] == ' ') q--;
2277 if (q - ret > 0 && q[-1] != '\\')
2285 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2288 MSIFOLDER *folder, *parent, *child;
2289 WCHAR *path, *normalized_path;
2291 TRACE("resolving %s\n", debugstr_w(name));
2293 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2295 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2297 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2299 path = msi_dup_property( package->db, szRootDrive );
2302 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2304 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2306 parent = msi_get_loaded_folder( package, folder->Parent );
2307 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2310 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2312 normalized_path = msi_normalize_path( path );
2314 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2316 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2317 msi_free( normalized_path );
2320 msi_set_property( package->db, folder->Directory, normalized_path );
2321 msi_free( folder->ResolvedTarget );
2322 folder->ResolvedTarget = normalized_path;
2324 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2327 msi_resolve_target_folder( package, child->Directory, load_prop );
2329 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2332 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2334 static const WCHAR query[] = {
2335 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2336 '`','C','o','n','d','i','t','i','o','n','`',0};
2337 static const WCHAR szOutOfDiskSpace[] = {
2338 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2344 TRACE("Building directory properties\n");
2345 msi_resolve_target_folder( package, szTargetDir, TRUE );
2347 TRACE("Evaluating component conditions\n");
2348 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2350 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2352 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2353 comp->Enabled = FALSE;
2356 comp->Enabled = TRUE;
2359 /* read components states from the registry */
2360 ACTION_GetComponentInstallStates(package);
2361 ACTION_GetFeatureInstallStates(package);
2363 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2365 TRACE("Evaluating feature conditions\n");
2367 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2368 if (rc == ERROR_SUCCESS)
2370 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2371 msiobj_release( &view->hdr );
2372 if (rc != ERROR_SUCCESS)
2377 TRACE("Calculating file cost\n");
2378 calculate_file_cost( package );
2380 msi_set_property( package->db, szCostingComplete, szOne );
2381 /* set default run level if not set */
2382 level = msi_dup_property( package->db, szInstallLevel );
2384 msi_set_property( package->db, szInstallLevel, szOne );
2387 /* FIXME: check volume disk space */
2388 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2390 return MSI_SetFeatureStates(package);
2393 /* OK this value is "interpreted" and then formatted based on the
2394 first few characters */
2395 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2400 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2406 LPWSTR deformated = NULL;
2409 deformat_string(package, &value[2], &deformated);
2411 /* binary value type */
2415 *size = (strlenW(ptr)/2)+1;
2417 *size = strlenW(ptr)/2;
2419 data = msi_alloc(*size);
2425 /* if uneven pad with a zero in front */
2431 data[count] = (BYTE)strtol(byte,NULL,0);
2433 TRACE("Uneven byte count\n");
2441 data[count] = (BYTE)strtol(byte,NULL,0);
2444 msi_free(deformated);
2446 TRACE("Data %i bytes(%i)\n",*size,count);
2453 deformat_string(package, &value[1], &deformated);
2456 *size = sizeof(DWORD);
2457 data = msi_alloc(*size);
2463 if ( (*p < '0') || (*p > '9') )
2469 if (deformated[0] == '-')
2472 TRACE("DWORD %i\n",*(LPDWORD)data);
2474 msi_free(deformated);
2479 static const WCHAR szMulti[] = {'[','~',']',0};
2488 *type=REG_EXPAND_SZ;
2496 if (strstrW(value, szMulti))
2497 *type = REG_MULTI_SZ;
2499 /* remove initial delimiter */
2500 if (!strncmpW(value, szMulti, 3))
2503 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2505 /* add double NULL terminator */
2506 if (*type == REG_MULTI_SZ)
2508 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2509 data = msi_realloc_zero(data, *size);
2515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2522 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2524 *root_key = HKEY_LOCAL_MACHINE;
2529 *root_key = HKEY_CURRENT_USER;
2534 *root_key = HKEY_CLASSES_ROOT;
2538 *root_key = HKEY_CURRENT_USER;
2542 *root_key = HKEY_LOCAL_MACHINE;
2546 *root_key = HKEY_USERS;
2550 ERR("Unknown root %i\n", root);
2557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2559 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2560 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2562 if (is_64bit && package->platform == PLATFORM_INTEL &&
2563 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2568 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2569 if (!(path_32node = msi_alloc( size ))) return NULL;
2571 memcpy( path_32node, path, len * sizeof(WCHAR) );
2572 strcpyW( path_32node + len, szWow6432Node );
2573 strcatW( path_32node, szBackSlash );
2574 strcatW( path_32node, path + len );
2578 return strdupW( path );
2581 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2583 MSIPACKAGE *package = param;
2584 LPSTR value_data = NULL;
2585 HKEY root_key, hkey;
2587 LPWSTR deformated, uikey, keypath;
2588 LPCWSTR szRoot, component, name, key, value;
2592 BOOL check_first = FALSE;
2595 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2597 component = MSI_RecordGetString(row, 6);
2598 comp = msi_get_loaded_component(package,component);
2600 return ERROR_SUCCESS;
2602 comp->Action = msi_get_component_action( package, comp );
2603 if (comp->Action != INSTALLSTATE_LOCAL)
2605 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2606 return ERROR_SUCCESS;
2609 name = MSI_RecordGetString(row, 4);
2610 if( MSI_RecordIsNull(row,5) && name )
2612 /* null values can have special meanings */
2613 if (name[0]=='-' && name[1] == 0)
2614 return ERROR_SUCCESS;
2615 else if ((name[0]=='+' && name[1] == 0) ||
2616 (name[0] == '*' && name[1] == 0))
2621 root = MSI_RecordGetInteger(row,2);
2622 key = MSI_RecordGetString(row, 3);
2624 szRoot = get_root_key( package, root, &root_key );
2626 return ERROR_SUCCESS;
2628 deformat_string(package, key , &deformated);
2629 size = strlenW(deformated) + strlenW(szRoot) + 1;
2630 uikey = msi_alloc(size*sizeof(WCHAR));
2631 strcpyW(uikey,szRoot);
2632 strcatW(uikey,deformated);
2634 keypath = get_keypath( package, root_key, deformated );
2635 msi_free( deformated );
2636 if (RegCreateKeyW( root_key, keypath, &hkey ))
2638 ERR("Could not create key %s\n", debugstr_w(keypath));
2641 return ERROR_SUCCESS;
2644 value = MSI_RecordGetString(row,5);
2646 value_data = parse_value(package, value, &type, &size);
2649 value_data = (LPSTR)strdupW(szEmpty);
2650 size = sizeof(szEmpty);
2654 deformat_string(package, name, &deformated);
2658 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2660 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2665 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2666 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2668 TRACE("value %s of %s checked already exists\n",
2669 debugstr_w(deformated), debugstr_w(uikey));
2673 TRACE("Checked and setting value %s of %s\n",
2674 debugstr_w(deformated), debugstr_w(uikey));
2675 if (deformated || size)
2676 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2681 uirow = MSI_CreateRecord(3);
2682 MSI_RecordSetStringW(uirow,2,deformated);
2683 MSI_RecordSetStringW(uirow,1,uikey);
2684 if (type == REG_SZ || type == REG_EXPAND_SZ)
2685 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2686 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2687 msiobj_release( &uirow->hdr );
2689 msi_free(value_data);
2690 msi_free(deformated);
2694 return ERROR_SUCCESS;
2697 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2699 static const WCHAR query[] = {
2700 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2701 '`','R','e','g','i','s','t','r','y','`',0};
2705 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2706 if (rc != ERROR_SUCCESS)
2707 return ERROR_SUCCESS;
2709 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2710 msiobj_release(&view->hdr);
2714 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2718 DWORD num_subkeys, num_values;
2720 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2722 if ((res = RegDeleteValueW( hkey, value )))
2724 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2726 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2727 NULL, NULL, NULL, NULL );
2728 RegCloseKey( hkey );
2729 if (!res && !num_subkeys && !num_values)
2731 TRACE("removing empty key %s\n", debugstr_w(keypath));
2732 RegDeleteKeyW( root, keypath );
2736 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2739 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2741 LONG res = RegDeleteTreeW( root, keypath );
2742 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2745 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2747 MSIPACKAGE *package = param;
2748 LPCWSTR component, name, key_str, root_key_str;
2749 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2752 BOOL delete_key = FALSE;
2757 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2759 component = MSI_RecordGetString( row, 6 );
2760 comp = msi_get_loaded_component( package, component );
2762 return ERROR_SUCCESS;
2764 comp->Action = msi_get_component_action( package, comp );
2765 if (comp->Action != INSTALLSTATE_ABSENT)
2767 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2768 return ERROR_SUCCESS;
2771 name = MSI_RecordGetString( row, 4 );
2772 if (MSI_RecordIsNull( row, 5 ) && name )
2774 if (name[0] == '+' && !name[1])
2775 return ERROR_SUCCESS;
2776 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2783 root = MSI_RecordGetInteger( row, 2 );
2784 key_str = MSI_RecordGetString( row, 3 );
2786 root_key_str = get_root_key( package, root, &hkey_root );
2788 return ERROR_SUCCESS;
2790 deformat_string( package, key_str, &deformated_key );
2791 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2792 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2793 strcpyW( ui_key_str, root_key_str );
2794 strcatW( ui_key_str, deformated_key );
2796 deformat_string( package, name, &deformated_name );
2798 keypath = get_keypath( package, hkey_root, deformated_key );
2799 msi_free( deformated_key );
2800 if (delete_key) delete_reg_key( hkey_root, keypath );
2801 else delete_reg_value( hkey_root, keypath, deformated_name );
2802 msi_free( keypath );
2804 uirow = MSI_CreateRecord( 2 );
2805 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2806 MSI_RecordSetStringW( uirow, 2, deformated_name );
2807 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2808 msiobj_release( &uirow->hdr );
2810 msi_free( ui_key_str );
2811 msi_free( deformated_name );
2812 return ERROR_SUCCESS;
2815 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2817 MSIPACKAGE *package = param;
2818 LPCWSTR component, name, key_str, root_key_str;
2819 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2822 BOOL delete_key = FALSE;
2827 component = MSI_RecordGetString( row, 5 );
2828 comp = msi_get_loaded_component( package, component );
2830 return ERROR_SUCCESS;
2832 comp->Action = msi_get_component_action( package, comp );
2833 if (comp->Action != INSTALLSTATE_LOCAL)
2835 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2836 return ERROR_SUCCESS;
2839 if ((name = MSI_RecordGetString( row, 4 )))
2841 if (name[0] == '-' && !name[1])
2848 root = MSI_RecordGetInteger( row, 2 );
2849 key_str = MSI_RecordGetString( row, 3 );
2851 root_key_str = get_root_key( package, root, &hkey_root );
2853 return ERROR_SUCCESS;
2855 deformat_string( package, key_str, &deformated_key );
2856 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2857 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2858 strcpyW( ui_key_str, root_key_str );
2859 strcatW( ui_key_str, deformated_key );
2861 deformat_string( package, name, &deformated_name );
2863 keypath = get_keypath( package, hkey_root, deformated_key );
2864 msi_free( deformated_key );
2865 if (delete_key) delete_reg_key( hkey_root, keypath );
2866 else delete_reg_value( hkey_root, keypath, deformated_name );
2867 msi_free( keypath );
2869 uirow = MSI_CreateRecord( 2 );
2870 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2871 MSI_RecordSetStringW( uirow, 2, deformated_name );
2872 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2873 msiobj_release( &uirow->hdr );
2875 msi_free( ui_key_str );
2876 msi_free( deformated_name );
2877 return ERROR_SUCCESS;
2880 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2882 static const WCHAR registry_query[] = {
2883 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2884 '`','R','e','g','i','s','t','r','y','`',0};
2885 static const WCHAR remove_registry_query[] = {
2886 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2887 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2891 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2892 if (rc == ERROR_SUCCESS)
2894 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2895 msiobj_release( &view->hdr );
2896 if (rc != ERROR_SUCCESS)
2899 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2900 if (rc == ERROR_SUCCESS)
2902 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2903 msiobj_release( &view->hdr );
2904 if (rc != ERROR_SUCCESS)
2907 return ERROR_SUCCESS;
2910 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2912 package->script->CurrentlyScripting = TRUE;
2914 return ERROR_SUCCESS;
2918 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2920 static const WCHAR query[]= {
2921 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2922 '`','R','e','g','i','s','t','r','y','`',0};
2924 DWORD total = 0, count = 0;
2926 MSIFEATURE *feature;
2930 TRACE("InstallValidate\n");
2932 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2933 if (rc == ERROR_SUCCESS)
2935 rc = MSI_IterateRecords( view, &count, NULL, package );
2936 msiobj_release( &view->hdr );
2937 if (rc != ERROR_SUCCESS)
2939 total += count * REG_PROGRESS_VALUE;
2941 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2942 total += COMPONENT_PROGRESS_VALUE;
2944 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2945 total += file->FileSize;
2947 msi_ui_progress( package, 0, total, 0, 0 );
2949 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2951 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2952 debugstr_w(feature->Feature), feature->Installed,
2953 feature->ActionRequest, feature->Action);
2955 return ERROR_SUCCESS;
2958 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2960 MSIPACKAGE* package = param;
2961 LPCWSTR cond = NULL;
2962 LPCWSTR message = NULL;
2965 static const WCHAR title[]=
2966 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2968 cond = MSI_RecordGetString(row,1);
2970 r = MSI_EvaluateConditionW(package,cond);
2971 if (r == MSICONDITION_FALSE)
2973 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2976 message = MSI_RecordGetString(row,2);
2977 deformat_string(package,message,&deformated);
2978 MessageBoxW(NULL,deformated,title,MB_OK);
2979 msi_free(deformated);
2982 return ERROR_INSTALL_FAILURE;
2985 return ERROR_SUCCESS;
2988 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2990 static const WCHAR query[] = {
2991 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2992 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2996 TRACE("Checking launch conditions\n");
2998 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2999 if (rc != ERROR_SUCCESS)
3000 return ERROR_SUCCESS;
3002 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3003 msiobj_release(&view->hdr);
3007 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3011 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3013 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3015 static const WCHAR query[] = {
3016 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3017 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3018 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3019 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3020 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3023 LPWSTR deformated, buffer, deformated_name;
3026 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3030 root = MSI_RecordGetInteger(row,2);
3031 key = MSI_RecordGetString(row, 3);
3032 name = MSI_RecordGetString(row, 4);
3033 deformat_string(package, key , &deformated);
3034 deformat_string(package, name, &deformated_name);
3036 len = strlenW(deformated) + 6;
3037 if (deformated_name)
3038 len+=strlenW(deformated_name);
3040 buffer = msi_alloc( len *sizeof(WCHAR));
3042 if (deformated_name)
3043 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3045 sprintfW(buffer,fmt,root,deformated);
3047 msi_free(deformated);
3048 msi_free(deformated_name);
3049 msiobj_release(&row->hdr);
3053 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3055 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3060 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3063 return strdupW( file->TargetPath );
3068 static HKEY openSharedDLLsKey(void)
3071 static const WCHAR path[] =
3072 {'S','o','f','t','w','a','r','e','\\',
3073 'M','i','c','r','o','s','o','f','t','\\',
3074 'W','i','n','d','o','w','s','\\',
3075 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3076 'S','h','a','r','e','d','D','L','L','s',0};
3078 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3082 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3087 DWORD sz = sizeof(count);
3090 hkey = openSharedDLLsKey();
3091 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3092 if (rc != ERROR_SUCCESS)
3098 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3102 hkey = openSharedDLLsKey();
3104 msi_reg_set_val_dword( hkey, path, count );
3106 RegDeleteValueW(hkey,path);
3111 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3113 MSIFEATURE *feature;
3117 /* only refcount DLLs */
3118 if (comp->KeyPath == NULL ||
3120 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3121 comp->Attributes & msidbComponentAttributesODBCDataSource)
3125 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3126 write = (count > 0);
3128 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3132 /* increment counts */
3133 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3137 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3140 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3142 if ( cl->component == comp )
3147 /* decrement counts */
3148 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3152 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3155 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3157 if ( cl->component == comp )
3162 /* ref count all the files in the component */
3167 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3169 if (file->Component == comp)
3170 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3174 /* add a count for permanent */
3175 if (comp->Attributes & msidbComponentAttributesPermanent)
3178 comp->RefCount = count;
3181 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3184 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3188 const WCHAR prefixW[] = {'<','\\',0};
3189 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3190 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3194 strcpyW( keypath, prefixW );
3195 strcatW( keypath, comp->assembly->display_name );
3199 return resolve_keypath( package, comp );
3202 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3204 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3211 squash_guid(package->ProductCode,squished_pc);
3212 msi_set_sourcedir_props(package, FALSE);
3214 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3217 INSTALLSTATE action;
3219 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3220 if (!comp->ComponentId)
3223 squash_guid( comp->ComponentId, squished_cc );
3224 msi_free( comp->FullKeypath );
3225 comp->FullKeypath = build_full_keypath( package, comp );
3227 ACTION_RefCountComponent( package, comp );
3229 if (package->need_rollback) action = comp->Installed;
3230 else action = comp->ActionRequest;
3232 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3233 debugstr_w(comp->Component), debugstr_w(squished_cc),
3234 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3236 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3238 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3239 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3241 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3243 if (rc != ERROR_SUCCESS)
3246 if (comp->Attributes & msidbComponentAttributesPermanent)
3248 static const WCHAR szPermKey[] =
3249 { '0','0','0','0','0','0','0','0','0','0','0','0',
3250 '0','0','0','0','0','0','0','0','0','0','0','0',
3251 '0','0','0','0','0','0','0','0',0 };
3253 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3255 if (action == INSTALLSTATE_LOCAL)
3256 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3262 WCHAR source[MAX_PATH];
3263 WCHAR base[MAX_PATH];
3266 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3267 static const WCHAR query[] = {
3268 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3269 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3270 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3271 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3272 '`','D','i','s','k','I','d','`',0};
3274 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3277 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3278 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3279 ptr2 = strrchrW(source, '\\') + 1;
3280 msiobj_release(&row->hdr);
3282 lstrcpyW(base, package->PackagePath);
3283 ptr = strrchrW(base, '\\');
3286 sourcepath = msi_resolve_file_source(package, file);
3287 ptr = sourcepath + lstrlenW(base);
3288 lstrcpyW(ptr2, ptr);
3289 msi_free(sourcepath);
3291 msi_reg_set_val_str(hkey, squished_pc, source);
3295 else if (action == INSTALLSTATE_ABSENT)
3297 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3298 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3300 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3304 uirow = MSI_CreateRecord(3);
3305 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3306 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3307 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3308 msi_ui_actiondata( package, szProcessComponents, uirow );
3309 msiobj_release( &uirow->hdr );
3311 return ERROR_SUCCESS;
3322 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3323 LPWSTR lpszName, LONG_PTR lParam)
3326 typelib_struct *tl_struct = (typelib_struct*) lParam;
3327 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3331 if (!IS_INTRESOURCE(lpszName))
3333 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3337 sz = strlenW(tl_struct->source)+4;
3338 sz *= sizeof(WCHAR);
3340 if ((INT_PTR)lpszName == 1)
3341 tl_struct->path = strdupW(tl_struct->source);
3344 tl_struct->path = msi_alloc(sz);
3345 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3348 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3349 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3352 msi_free(tl_struct->path);
3353 tl_struct->path = NULL;
3358 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3359 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3361 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3365 msi_free(tl_struct->path);
3366 tl_struct->path = NULL;
3368 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3369 ITypeLib_Release(tl_struct->ptLib);
3374 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3376 MSIPACKAGE* package = param;
3380 typelib_struct tl_struct;
3385 component = MSI_RecordGetString(row,3);
3386 comp = msi_get_loaded_component(package,component);
3388 return ERROR_SUCCESS;
3390 comp->Action = msi_get_component_action( package, comp );
3391 if (comp->Action != INSTALLSTATE_LOCAL)
3393 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3394 return ERROR_SUCCESS;
3397 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3399 TRACE("component has no key path\n");
3400 return ERROR_SUCCESS;
3402 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3404 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3408 guid = MSI_RecordGetString(row,1);
3409 CLSIDFromString( guid, &tl_struct.clsid);
3410 tl_struct.source = strdupW( file->TargetPath );
3411 tl_struct.path = NULL;
3413 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3414 (LONG_PTR)&tl_struct);
3418 LPCWSTR helpid, help_path = NULL;
3421 helpid = MSI_RecordGetString(row,6);
3423 if (helpid) help_path = msi_get_target_folder( package, helpid );
3424 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3427 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3429 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3431 ITypeLib_Release(tl_struct.ptLib);
3432 msi_free(tl_struct.path);
3434 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3436 FreeLibrary(module);
3437 msi_free(tl_struct.source);
3441 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3444 ERR("Failed to load type library: %08x\n", hr);
3445 return ERROR_INSTALL_FAILURE;
3448 ITypeLib_Release(tlib);
3451 return ERROR_SUCCESS;
3454 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3456 static const WCHAR query[] = {
3457 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3458 '`','T','y','p','e','L','i','b','`',0};
3462 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3463 if (rc != ERROR_SUCCESS)
3464 return ERROR_SUCCESS;
3466 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3467 msiobj_release(&view->hdr);
3471 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3473 MSIPACKAGE *package = param;
3474 LPCWSTR component, guid;
3482 component = MSI_RecordGetString( row, 3 );
3483 comp = msi_get_loaded_component( package, component );
3485 return ERROR_SUCCESS;
3487 comp->Action = msi_get_component_action( package, comp );
3488 if (comp->Action != INSTALLSTATE_ABSENT)
3490 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3491 return ERROR_SUCCESS;
3493 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3495 guid = MSI_RecordGetString( row, 1 );
3496 CLSIDFromString( guid, &libid );
3497 version = MSI_RecordGetInteger( row, 4 );
3498 language = MSI_RecordGetInteger( row, 2 );
3501 syskind = SYS_WIN64;
3503 syskind = SYS_WIN32;
3506 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3509 WARN("Failed to unregister typelib: %08x\n", hr);
3512 return ERROR_SUCCESS;
3515 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3517 static const WCHAR query[] = {
3518 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3519 '`','T','y','p','e','L','i','b','`',0};
3523 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3524 if (rc != ERROR_SUCCESS)
3525 return ERROR_SUCCESS;
3527 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3528 msiobj_release( &view->hdr );
3532 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3534 static const WCHAR szlnk[] = {'.','l','n','k',0};
3535 LPCWSTR directory, extension, link_folder;
3536 LPWSTR link_file, filename;
3538 directory = MSI_RecordGetString( row, 2 );
3539 link_folder = msi_get_target_folder( package, directory );
3542 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3545 /* may be needed because of a bug somewhere else */
3546 msi_create_full_path( link_folder );
3548 filename = msi_dup_record_field( row, 3 );
3549 msi_reduce_to_long_filename( filename );
3551 extension = strchrW( filename, '.' );
3552 if (!extension || strcmpiW( extension, szlnk ))
3554 int len = strlenW( filename );
3555 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3556 memcpy( filename + len, szlnk, sizeof(szlnk) );
3558 link_file = msi_build_directory_name( 2, link_folder, filename );
3559 msi_free( filename );
3564 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3566 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3567 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3568 WCHAR *folder, *dest, *path;
3570 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3571 folder = msi_dup_property( package->db, szWindowsFolder );
3574 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3575 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3576 msi_free( appdata );
3578 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3579 msi_create_full_path( dest );
3580 path = msi_build_directory_name( 2, dest, icon_name );
3586 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3588 MSIPACKAGE *package = param;
3589 LPWSTR link_file, deformated, path;
3590 LPCWSTR component, target;
3592 IShellLinkW *sl = NULL;
3593 IPersistFile *pf = NULL;
3596 component = MSI_RecordGetString(row, 4);
3597 comp = msi_get_loaded_component(package, component);
3599 return ERROR_SUCCESS;
3601 comp->Action = msi_get_component_action( package, comp );
3602 if (comp->Action != INSTALLSTATE_LOCAL)
3604 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3605 return ERROR_SUCCESS;
3607 msi_ui_actiondata( package, szCreateShortcuts, row );
3609 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3610 &IID_IShellLinkW, (LPVOID *) &sl );
3614 ERR("CLSID_ShellLink not available\n");
3618 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3621 ERR("QueryInterface(IID_IPersistFile) failed\n");
3625 target = MSI_RecordGetString(row, 5);
3626 if (strchrW(target, '['))
3628 deformat_string( package, target, &path );
3629 TRACE("target path is %s\n", debugstr_w(path));
3630 IShellLinkW_SetPath( sl, path );
3635 FIXME("poorly handled shortcut format, advertised shortcut\n");
3636 IShellLinkW_SetPath(sl,comp->FullKeypath);
3639 if (!MSI_RecordIsNull(row,6))
3641 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3642 deformat_string(package, arguments, &deformated);
3643 IShellLinkW_SetArguments(sl,deformated);
3644 msi_free(deformated);
3647 if (!MSI_RecordIsNull(row,7))
3649 LPCWSTR description = MSI_RecordGetString(row, 7);
3650 IShellLinkW_SetDescription(sl, description);
3653 if (!MSI_RecordIsNull(row,8))
3654 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3656 if (!MSI_RecordIsNull(row,9))
3659 LPCWSTR icon = MSI_RecordGetString(row, 9);
3661 path = msi_build_icon_path(package, icon);
3662 index = MSI_RecordGetInteger(row,10);
3664 /* no value means 0 */
3665 if (index == MSI_NULL_INTEGER)
3668 IShellLinkW_SetIconLocation(sl, path, index);
3672 if (!MSI_RecordIsNull(row,11))
3673 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3675 if (!MSI_RecordIsNull(row,12))
3677 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3678 full_path = msi_get_target_folder( package, wkdir );
3679 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3681 link_file = get_link_file(package, row);
3683 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3684 IPersistFile_Save(pf, link_file, FALSE);
3685 msi_free(link_file);
3689 IPersistFile_Release( pf );
3691 IShellLinkW_Release( sl );
3693 return ERROR_SUCCESS;
3696 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3698 static const WCHAR query[] = {
3699 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3700 '`','S','h','o','r','t','c','u','t','`',0};
3705 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3706 if (rc != ERROR_SUCCESS)
3707 return ERROR_SUCCESS;
3709 res = CoInitialize( NULL );
3711 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3712 msiobj_release(&view->hdr);
3714 if (SUCCEEDED(res)) CoUninitialize();
3718 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3720 MSIPACKAGE *package = param;
3725 component = MSI_RecordGetString( row, 4 );
3726 comp = msi_get_loaded_component( package, component );
3728 return ERROR_SUCCESS;
3730 comp->Action = msi_get_component_action( package, comp );
3731 if (comp->Action != INSTALLSTATE_ABSENT)
3733 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3734 return ERROR_SUCCESS;
3736 msi_ui_actiondata( package, szRemoveShortcuts, row );
3738 link_file = get_link_file( package, row );
3740 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3741 if (!DeleteFileW( link_file ))
3743 WARN("Failed to remove shortcut file %u\n", GetLastError());
3745 msi_free( link_file );
3747 return ERROR_SUCCESS;
3750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3752 static const WCHAR query[] = {
3753 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3754 '`','S','h','o','r','t','c','u','t','`',0};
3758 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3759 if (rc != ERROR_SUCCESS)
3760 return ERROR_SUCCESS;
3762 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3763 msiobj_release( &view->hdr );
3767 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3769 MSIPACKAGE* package = param;
3777 FileName = MSI_RecordGetString(row,1);
3780 ERR("Unable to get FileName\n");
3781 return ERROR_SUCCESS;
3784 FilePath = msi_build_icon_path(package, FileName);
3786 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3788 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3789 FILE_ATTRIBUTE_NORMAL, NULL);
3791 if (the_file == INVALID_HANDLE_VALUE)
3793 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3795 return ERROR_SUCCESS;
3802 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3803 if (rc != ERROR_SUCCESS)
3805 ERR("Failed to get stream\n");
3806 CloseHandle(the_file);
3807 DeleteFileW(FilePath);
3810 WriteFile(the_file,buffer,sz,&write,NULL);
3811 } while (sz == 1024);
3814 CloseHandle(the_file);
3816 return ERROR_SUCCESS;
3819 static UINT msi_publish_icons(MSIPACKAGE *package)
3821 static const WCHAR query[]= {
3822 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3823 '`','I','c','o','n','`',0};
3827 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3828 if (r == ERROR_SUCCESS)
3830 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3831 msiobj_release(&view->hdr);
3832 if (r != ERROR_SUCCESS)
3835 return ERROR_SUCCESS;
3838 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3844 MSISOURCELISTINFO *info;
3846 r = RegCreateKeyW(hkey, szSourceList, &source);
3847 if (r != ERROR_SUCCESS)
3850 RegCloseKey(source);
3852 buffer = strrchrW(package->PackagePath, '\\') + 1;
3853 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3854 package->Context, MSICODE_PRODUCT,
3855 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3856 if (r != ERROR_SUCCESS)
3859 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3860 package->Context, MSICODE_PRODUCT,
3861 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3862 if (r != ERROR_SUCCESS)
3865 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3866 package->Context, MSICODE_PRODUCT,
3867 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3868 if (r != ERROR_SUCCESS)
3871 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3873 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3874 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3875 info->options, info->value);
3877 MsiSourceListSetInfoW(package->ProductCode, NULL,
3878 info->context, info->options,
3879 info->property, info->value);
3882 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3884 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3885 disk->context, disk->options,
3886 disk->disk_id, disk->volume_label, disk->disk_prompt);
3889 return ERROR_SUCCESS;
3892 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3894 MSIHANDLE hdb, suminfo;
3895 WCHAR guids[MAX_PATH];
3896 WCHAR packcode[SQUISH_GUID_SIZE];
3903 static const WCHAR szARPProductIcon[] =
3904 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3905 static const WCHAR szAssignment[] =
3906 {'A','s','s','i','g','n','m','e','n','t',0};
3907 static const WCHAR szAdvertiseFlags[] =
3908 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3909 static const WCHAR szClients[] =
3910 {'C','l','i','e','n','t','s',0};
3911 static const WCHAR szColon[] = {':',0};
3913 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3914 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3917 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3918 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3921 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3923 buffer = msi_dup_property(package->db, szARPProductIcon);
3926 LPWSTR path = msi_build_icon_path(package, buffer);
3927 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3932 buffer = msi_dup_property(package->db, szProductVersion);
3935 DWORD verdword = msi_version_str_to_dword(buffer);
3936 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3940 msi_reg_set_val_dword(hkey, szAssignment, 0);
3941 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3942 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3943 msi_reg_set_val_str(hkey, szClients, szColon);
3945 hdb = alloc_msihandle(&package->db->hdr);
3947 return ERROR_NOT_ENOUGH_MEMORY;
3949 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3950 MsiCloseHandle(hdb);
3951 if (r != ERROR_SUCCESS)
3955 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3956 NULL, guids, &size);
3957 if (r != ERROR_SUCCESS)
3960 ptr = strchrW(guids, ';');
3962 squash_guid(guids, packcode);
3963 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3966 MsiCloseHandle(suminfo);
3967 return ERROR_SUCCESS;
3970 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3975 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3977 upgrade = msi_dup_property(package->db, szUpgradeCode);
3979 return ERROR_SUCCESS;
3981 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3982 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3984 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3986 if (r != ERROR_SUCCESS)
3988 WARN("failed to open upgrade code key\n");
3990 return ERROR_SUCCESS;
3992 squash_guid(package->ProductCode, squashed_pc);
3993 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3996 return ERROR_SUCCESS;
3999 static BOOL msi_check_publish(MSIPACKAGE *package)
4001 MSIFEATURE *feature;
4003 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4005 feature->Action = msi_get_feature_action( package, feature );
4006 if (feature->Action == INSTALLSTATE_LOCAL)
4013 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4015 MSIFEATURE *feature;
4017 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4019 feature->Action = msi_get_feature_action( package, feature );
4020 if (feature->Action != INSTALLSTATE_ABSENT)
4027 static UINT msi_publish_patches( MSIPACKAGE *package )
4029 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4030 WCHAR patch_squashed[GUID_SIZE];
4031 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4033 MSIPATCHINFO *patch;
4035 WCHAR *p, *all_patches = NULL;
4038 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4039 if (r != ERROR_SUCCESS)
4040 return ERROR_FUNCTION_FAILED;
4042 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4043 if (res != ERROR_SUCCESS)
4045 r = ERROR_FUNCTION_FAILED;
4049 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4050 if (r != ERROR_SUCCESS)
4053 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4055 squash_guid( patch->patchcode, patch_squashed );
4056 len += strlenW( patch_squashed ) + 1;
4059 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4063 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4067 squash_guid( patch->patchcode, p );
4068 p += strlenW( p ) + 1;
4070 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4071 (const BYTE *)patch->transforms,
4072 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4073 if (res != ERROR_SUCCESS)
4076 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4077 if (r != ERROR_SUCCESS)
4080 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4081 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4082 RegCloseKey( patch_key );
4083 if (res != ERROR_SUCCESS)
4086 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4088 res = GetLastError();
4089 ERR("Unable to copy patch package %d\n", res);
4092 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4093 if (res != ERROR_SUCCESS)
4096 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4097 RegCloseKey( patch_key );
4098 if (res != ERROR_SUCCESS)
4102 all_patches[len] = 0;
4103 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4104 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4105 if (res != ERROR_SUCCESS)
4108 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4109 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4110 if (res != ERROR_SUCCESS)
4111 r = ERROR_FUNCTION_FAILED;
4114 RegCloseKey( product_patches_key );
4115 RegCloseKey( patches_key );
4116 RegCloseKey( product_key );
4117 msi_free( all_patches );
4121 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4124 HKEY hukey = NULL, hudkey = NULL;
4127 if (!list_empty(&package->patches))
4129 rc = msi_publish_patches(package);
4130 if (rc != ERROR_SUCCESS)
4134 /* FIXME: also need to publish if the product is in advertise mode */
4135 if (!msi_check_publish(package))
4136 return ERROR_SUCCESS;
4138 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4140 if (rc != ERROR_SUCCESS)
4143 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4144 NULL, &hudkey, TRUE);
4145 if (rc != ERROR_SUCCESS)
4148 rc = msi_publish_upgrade_code(package);
4149 if (rc != ERROR_SUCCESS)
4152 rc = msi_publish_product_properties(package, hukey);
4153 if (rc != ERROR_SUCCESS)
4156 rc = msi_publish_sourcelist(package, hukey);
4157 if (rc != ERROR_SUCCESS)
4160 rc = msi_publish_icons(package);
4163 uirow = MSI_CreateRecord( 1 );
4164 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4165 msi_ui_actiondata( package, szPublishProduct, uirow );
4166 msiobj_release( &uirow->hdr );
4169 RegCloseKey(hudkey);
4173 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4175 WCHAR *filename, *ptr, *folder, *ret;
4176 const WCHAR *dirprop;
4178 filename = msi_dup_record_field( row, 2 );
4179 if (filename && (ptr = strchrW( filename, '|' )))
4184 dirprop = MSI_RecordGetString( row, 3 );
4187 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4188 if (!folder) folder = msi_dup_property( package->db, dirprop );
4191 folder = msi_dup_property( package->db, szWindowsFolder );
4195 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4196 msi_free( filename );
4200 ret = msi_build_directory_name( 2, folder, ptr );
4202 msi_free( filename );
4207 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4209 MSIPACKAGE *package = param;
4210 LPCWSTR component, section, key, value, identifier;
4211 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4216 component = MSI_RecordGetString(row, 8);
4217 comp = msi_get_loaded_component(package,component);
4219 return ERROR_SUCCESS;
4221 comp->Action = msi_get_component_action( package, comp );
4222 if (comp->Action != INSTALLSTATE_LOCAL)
4224 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4225 return ERROR_SUCCESS;
4228 identifier = MSI_RecordGetString(row,1);
4229 section = MSI_RecordGetString(row,4);
4230 key = MSI_RecordGetString(row,5);
4231 value = MSI_RecordGetString(row,6);
4232 action = MSI_RecordGetInteger(row,7);
4234 deformat_string(package,section,&deformated_section);
4235 deformat_string(package,key,&deformated_key);
4236 deformat_string(package,value,&deformated_value);
4238 fullname = get_ini_file_name(package, row);
4242 TRACE("Adding value %s to section %s in %s\n",
4243 debugstr_w(deformated_key), debugstr_w(deformated_section),
4244 debugstr_w(fullname));
4245 WritePrivateProfileStringW(deformated_section, deformated_key,
4246 deformated_value, fullname);
4248 else if (action == 1)
4251 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4252 returned, 10, fullname);
4253 if (returned[0] == 0)
4255 TRACE("Adding value %s to section %s in %s\n",
4256 debugstr_w(deformated_key), debugstr_w(deformated_section),
4257 debugstr_w(fullname));
4259 WritePrivateProfileStringW(deformated_section, deformated_key,
4260 deformated_value, fullname);
4263 else if (action == 3)
4264 FIXME("Append to existing section not yet implemented\n");
4266 uirow = MSI_CreateRecord(4);
4267 MSI_RecordSetStringW(uirow,1,identifier);
4268 MSI_RecordSetStringW(uirow,2,deformated_section);
4269 MSI_RecordSetStringW(uirow,3,deformated_key);
4270 MSI_RecordSetStringW(uirow,4,deformated_value);
4271 msi_ui_actiondata( package, szWriteIniValues, uirow );
4272 msiobj_release( &uirow->hdr );
4275 msi_free(deformated_key);
4276 msi_free(deformated_value);
4277 msi_free(deformated_section);
4278 return ERROR_SUCCESS;
4281 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4283 static const WCHAR query[] = {
4284 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4285 '`','I','n','i','F','i','l','e','`',0};
4289 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4290 if (rc != ERROR_SUCCESS)
4291 return ERROR_SUCCESS;
4293 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4294 msiobj_release(&view->hdr);
4298 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4300 MSIPACKAGE *package = param;
4301 LPCWSTR component, section, key, value, identifier;
4302 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4307 component = MSI_RecordGetString( row, 8 );
4308 comp = msi_get_loaded_component( package, component );
4310 return ERROR_SUCCESS;
4312 comp->Action = msi_get_component_action( package, comp );
4313 if (comp->Action != INSTALLSTATE_ABSENT)
4315 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4316 return ERROR_SUCCESS;
4319 identifier = MSI_RecordGetString( row, 1 );
4320 section = MSI_RecordGetString( row, 4 );
4321 key = MSI_RecordGetString( row, 5 );
4322 value = MSI_RecordGetString( row, 6 );
4323 action = MSI_RecordGetInteger( row, 7 );
4325 deformat_string( package, section, &deformated_section );
4326 deformat_string( package, key, &deformated_key );
4327 deformat_string( package, value, &deformated_value );
4329 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4331 filename = get_ini_file_name( package, row );
4333 TRACE("Removing key %s from section %s in %s\n",
4334 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4336 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4338 WARN("Unable to remove key %u\n", GetLastError());
4340 msi_free( filename );
4343 FIXME("Unsupported action %d\n", action);
4346 uirow = MSI_CreateRecord( 4 );
4347 MSI_RecordSetStringW( uirow, 1, identifier );
4348 MSI_RecordSetStringW( uirow, 2, deformated_section );
4349 MSI_RecordSetStringW( uirow, 3, deformated_key );
4350 MSI_RecordSetStringW( uirow, 4, deformated_value );
4351 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4352 msiobj_release( &uirow->hdr );
4354 msi_free( deformated_key );
4355 msi_free( deformated_value );
4356 msi_free( deformated_section );
4357 return ERROR_SUCCESS;
4360 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4362 MSIPACKAGE *package = param;
4363 LPCWSTR component, section, key, value, identifier;
4364 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4369 component = MSI_RecordGetString( row, 8 );
4370 comp = msi_get_loaded_component( package, component );
4372 return ERROR_SUCCESS;
4374 comp->Action = msi_get_component_action( package, comp );
4375 if (comp->Action != INSTALLSTATE_LOCAL)
4377 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4378 return ERROR_SUCCESS;
4381 identifier = MSI_RecordGetString( row, 1 );
4382 section = MSI_RecordGetString( row, 4 );
4383 key = MSI_RecordGetString( row, 5 );
4384 value = MSI_RecordGetString( row, 6 );
4385 action = MSI_RecordGetInteger( row, 7 );
4387 deformat_string( package, section, &deformated_section );
4388 deformat_string( package, key, &deformated_key );
4389 deformat_string( package, value, &deformated_value );
4391 if (action == msidbIniFileActionRemoveLine)
4393 filename = get_ini_file_name( package, row );
4395 TRACE("Removing key %s from section %s in %s\n",
4396 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4398 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4400 WARN("Unable to remove key %u\n", GetLastError());
4402 msi_free( filename );
4405 FIXME("Unsupported action %d\n", action);
4407 uirow = MSI_CreateRecord( 4 );
4408 MSI_RecordSetStringW( uirow, 1, identifier );
4409 MSI_RecordSetStringW( uirow, 2, deformated_section );
4410 MSI_RecordSetStringW( uirow, 3, deformated_key );
4411 MSI_RecordSetStringW( uirow, 4, deformated_value );
4412 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4413 msiobj_release( &uirow->hdr );
4415 msi_free( deformated_key );
4416 msi_free( deformated_value );
4417 msi_free( deformated_section );
4418 return ERROR_SUCCESS;
4421 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4423 static const WCHAR query[] = {
4424 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4425 '`','I','n','i','F','i','l','e','`',0};
4426 static const WCHAR remove_query[] = {
4427 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4428 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4432 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4433 if (rc == ERROR_SUCCESS)
4435 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4436 msiobj_release( &view->hdr );
4437 if (rc != ERROR_SUCCESS)
4440 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4441 if (rc == ERROR_SUCCESS)
4443 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4444 msiobj_release( &view->hdr );
4445 if (rc != ERROR_SUCCESS)
4448 return ERROR_SUCCESS;
4451 static void register_dll( const WCHAR *dll, BOOL unregister )
4455 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4458 HRESULT (WINAPI *func_ptr)( void );
4459 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4461 func_ptr = (void *)GetProcAddress( hmod, func );
4464 HRESULT hr = func_ptr();
4466 WARN("failed to register dll 0x%08x\n", hr);
4469 WARN("entry point %s not found\n", func);
4470 FreeLibrary( hmod );
4473 WARN("failed to load library %u\n", GetLastError());
4476 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4478 MSIPACKAGE *package = param;
4483 filename = MSI_RecordGetString( row, 1 );
4484 file = msi_get_loaded_file( package, filename );
4487 WARN("unable to find file %s\n", debugstr_w(filename));
4488 return ERROR_SUCCESS;
4490 file->Component->Action = msi_get_component_action( package, file->Component );
4491 if (file->Component->Action != INSTALLSTATE_LOCAL)
4493 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4494 return ERROR_SUCCESS;
4497 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4498 register_dll( file->TargetPath, FALSE );
4500 uirow = MSI_CreateRecord( 2 );
4501 MSI_RecordSetStringW( uirow, 1, file->File );
4502 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4503 msi_ui_actiondata( package, szSelfRegModules, uirow );
4504 msiobj_release( &uirow->hdr );
4506 return ERROR_SUCCESS;
4509 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4511 static const WCHAR query[] = {
4512 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4513 '`','S','e','l','f','R','e','g','`',0};
4517 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4518 if (rc != ERROR_SUCCESS)
4519 return ERROR_SUCCESS;
4521 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4522 msiobj_release(&view->hdr);
4526 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4528 MSIPACKAGE *package = param;
4533 filename = MSI_RecordGetString( row, 1 );
4534 file = msi_get_loaded_file( package, filename );
4537 WARN("unable to find file %s\n", debugstr_w(filename));
4538 return ERROR_SUCCESS;
4540 file->Component->Action = msi_get_component_action( package, file->Component );
4541 if (file->Component->Action != INSTALLSTATE_ABSENT)
4543 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4544 return ERROR_SUCCESS;
4547 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4548 register_dll( file->TargetPath, TRUE );
4550 uirow = MSI_CreateRecord( 2 );
4551 MSI_RecordSetStringW( uirow, 1, file->File );
4552 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4553 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4554 msiobj_release( &uirow->hdr );
4556 return ERROR_SUCCESS;
4559 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4561 static const WCHAR query[] = {
4562 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4563 '`','S','e','l','f','R','e','g','`',0};
4567 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4568 if (rc != ERROR_SUCCESS)
4569 return ERROR_SUCCESS;
4571 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4572 msiobj_release( &view->hdr );
4576 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4578 MSIFEATURE *feature;
4580 HKEY hkey = NULL, userdata = NULL;
4582 if (!msi_check_publish(package))
4583 return ERROR_SUCCESS;
4585 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4587 if (rc != ERROR_SUCCESS)
4590 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4592 if (rc != ERROR_SUCCESS)
4595 /* here the guids are base 85 encoded */
4596 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4602 BOOL absent = FALSE;
4605 if (feature->Action != INSTALLSTATE_LOCAL &&
4606 feature->Action != INSTALLSTATE_SOURCE &&
4607 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4610 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4614 if (feature->Feature_Parent)
4615 size += strlenW( feature->Feature_Parent )+2;
4617 data = msi_alloc(size * sizeof(WCHAR));
4620 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4622 MSICOMPONENT* component = cl->component;
4626 if (component->ComponentId)
4628 TRACE("From %s\n",debugstr_w(component->ComponentId));
4629 CLSIDFromString(component->ComponentId, &clsid);
4630 encode_base85_guid(&clsid,buf);
4631 TRACE("to %s\n",debugstr_w(buf));
4636 if (feature->Feature_Parent)
4638 static const WCHAR sep[] = {'\2',0};
4640 strcatW(data,feature->Feature_Parent);
4643 msi_reg_set_val_str( userdata, feature->Feature, data );
4647 if (feature->Feature_Parent)
4648 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4651 size += sizeof(WCHAR);
4652 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4653 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4657 size += 2*sizeof(WCHAR);
4658 data = msi_alloc(size);
4661 if (feature->Feature_Parent)
4662 strcpyW( &data[1], feature->Feature_Parent );
4663 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4669 uirow = MSI_CreateRecord( 1 );
4670 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4671 msi_ui_actiondata( package, szPublishFeatures, uirow );
4672 msiobj_release( &uirow->hdr );
4673 /* FIXME: call msi_ui_progress? */
4678 RegCloseKey(userdata);
4682 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4688 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4690 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4692 if (r == ERROR_SUCCESS)
4694 RegDeleteValueW(hkey, feature->Feature);
4698 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4700 if (r == ERROR_SUCCESS)
4702 RegDeleteValueW(hkey, feature->Feature);
4706 uirow = MSI_CreateRecord( 1 );
4707 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4708 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4709 msiobj_release( &uirow->hdr );
4711 return ERROR_SUCCESS;
4714 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4716 MSIFEATURE *feature;
4718 if (!msi_check_unpublish(package))
4719 return ERROR_SUCCESS;
4721 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4723 msi_unpublish_feature(package, feature);
4726 return ERROR_SUCCESS;
4729 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4733 WCHAR date[9], *val, *buffer;
4734 const WCHAR *prop, *key;
4736 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4737 static const WCHAR modpath_fmt[] =
4738 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4739 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4740 static const WCHAR szModifyPath[] =
4741 {'M','o','d','i','f','y','P','a','t','h',0};
4742 static const WCHAR szUninstallString[] =
4743 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4744 static const WCHAR szEstimatedSize[] =
4745 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4746 static const WCHAR szDisplayVersion[] =
4747 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4748 static const WCHAR szInstallSource[] =
4749 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4750 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4751 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4752 static const WCHAR szAuthorizedCDFPrefix[] =
4753 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4754 static const WCHAR szARPCONTACT[] =
4755 {'A','R','P','C','O','N','T','A','C','T',0};
4756 static const WCHAR szContact[] =
4757 {'C','o','n','t','a','c','t',0};
4758 static const WCHAR szARPCOMMENTS[] =
4759 {'A','R','P','C','O','M','M','E','N','T','S',0};
4760 static const WCHAR szComments[] =
4761 {'C','o','m','m','e','n','t','s',0};
4762 static const WCHAR szProductName[] =
4763 {'P','r','o','d','u','c','t','N','a','m','e',0};
4764 static const WCHAR szDisplayName[] =
4765 {'D','i','s','p','l','a','y','N','a','m','e',0};
4766 static const WCHAR szARPHELPLINK[] =
4767 {'A','R','P','H','E','L','P','L','I','N','K',0};
4768 static const WCHAR szHelpLink[] =
4769 {'H','e','l','p','L','i','n','k',0};
4770 static const WCHAR szARPHELPTELEPHONE[] =
4771 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4772 static const WCHAR szHelpTelephone[] =
4773 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4774 static const WCHAR szARPINSTALLLOCATION[] =
4775 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4776 static const WCHAR szInstallLocation[] =
4777 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4778 static const WCHAR szManufacturer[] =
4779 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4780 static const WCHAR szPublisher[] =
4781 {'P','u','b','l','i','s','h','e','r',0};
4782 static const WCHAR szARPREADME[] =
4783 {'A','R','P','R','E','A','D','M','E',0};
4784 static const WCHAR szReadme[] =
4785 {'R','e','a','d','M','e',0};
4786 static const WCHAR szARPSIZE[] =
4787 {'A','R','P','S','I','Z','E',0};
4788 static const WCHAR szSize[] =
4789 {'S','i','z','e',0};
4790 static const WCHAR szARPURLINFOABOUT[] =
4791 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4792 static const WCHAR szURLInfoAbout[] =
4793 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4794 static const WCHAR szARPURLUPDATEINFO[] =
4795 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4796 static const WCHAR szURLUpdateInfo[] =
4797 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4798 static const WCHAR szARPSYSTEMCOMPONENT[] =
4799 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4800 static const WCHAR szSystemComponent[] =
4801 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4803 static const WCHAR *propval[] = {
4804 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4805 szARPCONTACT, szContact,
4806 szARPCOMMENTS, szComments,
4807 szProductName, szDisplayName,
4808 szARPHELPLINK, szHelpLink,
4809 szARPHELPTELEPHONE, szHelpTelephone,
4810 szARPINSTALLLOCATION, szInstallLocation,
4811 szSourceDir, szInstallSource,
4812 szManufacturer, szPublisher,
4813 szARPREADME, szReadme,
4815 szARPURLINFOABOUT, szURLInfoAbout,
4816 szARPURLUPDATEINFO, szURLUpdateInfo,
4819 const WCHAR **p = propval;
4825 val = msi_dup_property(package->db, prop);
4826 msi_reg_set_val_str(hkey, key, val);
4830 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4831 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4833 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4835 size = deformat_string(package, modpath_fmt, &buffer);
4836 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4837 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4840 /* FIXME: Write real Estimated Size when we have it */
4841 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4843 GetLocalTime(&systime);
4844 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4845 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4847 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4848 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4850 buffer = msi_dup_property(package->db, szProductVersion);
4851 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4854 DWORD verdword = msi_version_str_to_dword(buffer);
4856 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4857 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4858 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4862 return ERROR_SUCCESS;
4865 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4867 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4869 LPWSTR upgrade_code;
4870 HKEY hkey, props, upgrade_key;
4873 /* FIXME: also need to publish if the product is in advertise mode */
4874 if (!msi_check_publish(package))
4875 return ERROR_SUCCESS;
4877 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4878 if (rc != ERROR_SUCCESS)
4881 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4882 if (rc != ERROR_SUCCESS)
4885 rc = msi_publish_install_properties(package, hkey);
4886 if (rc != ERROR_SUCCESS)
4889 rc = msi_publish_install_properties(package, props);
4890 if (rc != ERROR_SUCCESS)
4893 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4896 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4897 if (rc == ERROR_SUCCESS)
4899 squash_guid( package->ProductCode, squashed_pc );
4900 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4901 RegCloseKey( upgrade_key );
4903 msi_free( upgrade_code );
4905 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4906 package->delete_on_close = FALSE;
4909 uirow = MSI_CreateRecord( 1 );
4910 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4911 msi_ui_actiondata( package, szRegisterProduct, uirow );
4912 msiobj_release( &uirow->hdr );
4915 return ERROR_SUCCESS;
4918 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4920 return execute_script(package, SCRIPT_INSTALL);
4923 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4925 MSIPACKAGE *package = param;
4926 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4927 WCHAR *p, *icon_path;
4929 if (!icon) return ERROR_SUCCESS;
4930 if ((icon_path = msi_build_icon_path( package, icon )))
4932 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4933 DeleteFileW( icon_path );
4934 if ((p = strrchrW( icon_path, '\\' )))
4937 RemoveDirectoryW( icon_path );
4939 msi_free( icon_path );
4941 return ERROR_SUCCESS;
4944 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4946 static const WCHAR query[]= {
4947 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4951 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4952 if (r == ERROR_SUCCESS)
4954 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4955 msiobj_release( &view->hdr );
4956 if (r != ERROR_SUCCESS)
4959 return ERROR_SUCCESS;
4962 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4964 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4965 WCHAR *upgrade, **features;
4966 BOOL full_uninstall = TRUE;
4967 MSIFEATURE *feature;
4968 MSIPATCHINFO *patch;
4971 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4973 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4975 features = msi_split_string( remove, ',' );
4976 for (i = 0; features && features[i]; i++)
4978 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4982 if (!full_uninstall)
4983 return ERROR_SUCCESS;
4985 MSIREG_DeleteProductKey(package->ProductCode);
4986 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4987 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4989 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4990 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4991 MSIREG_DeleteUserProductKey(package->ProductCode);
4992 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4994 upgrade = msi_dup_property(package->db, szUpgradeCode);
4997 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4998 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5002 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5004 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5005 if (!strcmpW( package->ProductCode, patch->products ))
5007 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5008 patch->delete_on_close = TRUE;
5010 /* FIXME: remove local patch package if this is the last product */
5012 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5013 package->delete_on_close = TRUE;
5015 msi_unpublish_icons( package );
5016 return ERROR_SUCCESS;
5019 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5024 /* turn off scheduling */
5025 package->script->CurrentlyScripting= FALSE;
5027 /* first do the same as an InstallExecute */
5028 rc = ACTION_InstallExecute(package);
5029 if (rc != ERROR_SUCCESS)
5032 /* then handle commit actions */
5033 rc = execute_script(package, SCRIPT_COMMIT);
5034 if (rc != ERROR_SUCCESS)
5037 remove = msi_dup_property(package->db, szRemove);
5038 rc = msi_unpublish_product(package, remove);
5043 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5045 static const WCHAR RunOnce[] = {
5046 'S','o','f','t','w','a','r','e','\\',
5047 'M','i','c','r','o','s','o','f','t','\\',
5048 'W','i','n','d','o','w','s','\\',
5049 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5050 'R','u','n','O','n','c','e',0};
5051 static const WCHAR InstallRunOnce[] = {
5052 'S','o','f','t','w','a','r','e','\\',
5053 'M','i','c','r','o','s','o','f','t','\\',
5054 'W','i','n','d','o','w','s','\\',
5055 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5056 'I','n','s','t','a','l','l','e','r','\\',
5057 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5059 static const WCHAR msiexec_fmt[] = {
5061 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5062 '\"','%','s','\"',0};
5063 static const WCHAR install_fmt[] = {
5064 '/','I',' ','\"','%','s','\"',' ',
5065 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5066 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5067 WCHAR buffer[256], sysdir[MAX_PATH];
5069 WCHAR squished_pc[100];
5071 squash_guid(package->ProductCode,squished_pc);
5073 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5074 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5075 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5078 msi_reg_set_val_str( hkey, squished_pc, buffer );
5081 TRACE("Reboot command %s\n",debugstr_w(buffer));
5083 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5084 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5086 msi_reg_set_val_str( hkey, squished_pc, buffer );
5089 return ERROR_INSTALL_SUSPEND;
5092 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5094 static const WCHAR query[] =
5095 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5096 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5097 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5098 MSIRECORD *rec, *row;
5104 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5106 rec = MSI_CreateRecord( count + 2 );
5107 str = MSI_RecordGetString( row, 1 );
5108 MSI_RecordSetStringW( rec, 0, str );
5109 msiobj_release( &row->hdr );
5110 MSI_RecordSetInteger( rec, 1, error );
5112 va_start( va, count );
5113 for (i = 0; i < count; i++)
5115 str = va_arg( va, const WCHAR *);
5116 MSI_RecordSetStringW( rec, i + 2, str );
5120 MSI_FormatRecordW( package, rec, NULL, &size );
5122 data = msi_alloc( size * sizeof(WCHAR) );
5123 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5125 msiobj_release( &rec->hdr );
5129 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5135 * We are currently doing what should be done here in the top level Install
5136 * however for Administrative and uninstalls this step will be needed
5138 if (!package->PackagePath)
5139 return ERROR_SUCCESS;
5141 msi_set_sourcedir_props(package, TRUE);
5143 attrib = GetFileAttributesW(package->db->path);
5144 if (attrib == INVALID_FILE_ATTRIBUTES)
5149 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5150 package->Context, MSICODE_PRODUCT,
5151 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5152 if (rc == ERROR_MORE_DATA)
5154 prompt = msi_alloc(size * sizeof(WCHAR));
5155 MsiSourceListGetInfoW(package->ProductCode, NULL,
5156 package->Context, MSICODE_PRODUCT,
5157 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5160 prompt = strdupW(package->db->path);
5162 msg = msi_build_error_string(package, 1302, 1, prompt);
5164 while(attrib == INVALID_FILE_ATTRIBUTES)
5166 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5170 return ERROR_INSTALL_USEREXIT;
5172 attrib = GetFileAttributesW(package->db->path);
5178 return ERROR_SUCCESS;
5183 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5186 LPWSTR buffer, productid = NULL;
5187 UINT i, rc = ERROR_SUCCESS;
5190 static const WCHAR szPropKeys[][80] =
5192 {'P','r','o','d','u','c','t','I','D',0},
5193 {'U','S','E','R','N','A','M','E',0},
5194 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5198 static const WCHAR szRegKeys[][80] =
5200 {'P','r','o','d','u','c','t','I','D',0},
5201 {'R','e','g','O','w','n','e','r',0},
5202 {'R','e','g','C','o','m','p','a','n','y',0},
5206 if (msi_check_unpublish(package))
5208 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5212 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5216 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5218 if (rc != ERROR_SUCCESS)
5221 for( i = 0; szPropKeys[i][0]; i++ )
5223 buffer = msi_dup_property( package->db, szPropKeys[i] );
5224 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5229 uirow = MSI_CreateRecord( 1 );
5230 MSI_RecordSetStringW( uirow, 1, productid );
5231 msi_ui_actiondata( package, szRegisterUser, uirow );
5232 msiobj_release( &uirow->hdr );
5234 msi_free(productid);
5240 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5244 package->script->InWhatSequence |= SEQUENCE_EXEC;
5245 rc = ACTION_ProcessExecSequence(package,FALSE);
5249 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5251 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5252 WCHAR productid_85[21], component_85[21], *ret;
5256 /* > is used if there is a component GUID and < if not. */
5258 productid_85[0] = 0;
5259 component_85[0] = 0;
5260 CLSIDFromString( package->ProductCode, &clsid );
5262 encode_base85_guid( &clsid, productid_85 );
5265 CLSIDFromString( component->ComponentId, &clsid );
5266 encode_base85_guid( &clsid, component_85 );
5269 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5270 debugstr_w(component_85));
5272 sz = 20 + strlenW( feature ) + 20 + 3;
5273 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5274 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5278 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5280 MSIPACKAGE *package = param;
5281 LPCWSTR compgroupid, component, feature, qualifier, text;
5282 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5291 feature = MSI_RecordGetString(rec, 5);
5292 feat = msi_get_loaded_feature(package, feature);
5294 return ERROR_SUCCESS;
5296 feat->Action = msi_get_feature_action( package, feat );
5297 if (feat->Action != INSTALLSTATE_LOCAL &&
5298 feat->Action != INSTALLSTATE_SOURCE &&
5299 feat->Action != INSTALLSTATE_ADVERTISED)
5301 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5302 return ERROR_SUCCESS;
5305 component = MSI_RecordGetString(rec, 3);
5306 comp = msi_get_loaded_component(package, component);
5308 return ERROR_SUCCESS;
5310 compgroupid = MSI_RecordGetString(rec,1);
5311 qualifier = MSI_RecordGetString(rec,2);
5313 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5314 if (rc != ERROR_SUCCESS)
5317 advertise = msi_create_component_advertise_string( package, comp, feature );
5318 text = MSI_RecordGetString( rec, 4 );
5321 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5322 strcpyW( p, advertise );
5324 msi_free( advertise );
5327 existing = msi_reg_get_val_str( hkey, qualifier );
5329 sz = strlenW( advertise ) + 1;
5332 for (p = existing; *p; p += len)
5334 len = strlenW( p ) + 1;
5335 if (strcmpW( advertise, p )) sz += len;
5338 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5340 rc = ERROR_OUTOFMEMORY;
5346 for (p = existing; *p; p += len)
5348 len = strlenW( p ) + 1;
5349 if (strcmpW( advertise, p ))
5351 memcpy( q, p, len * sizeof(WCHAR) );
5356 strcpyW( q, advertise );
5357 q[strlenW( q ) + 1] = 0;
5359 msi_reg_set_val_multi_str( hkey, qualifier, output );
5364 msi_free( advertise );
5365 msi_free( existing );
5368 uirow = MSI_CreateRecord( 2 );
5369 MSI_RecordSetStringW( uirow, 1, compgroupid );
5370 MSI_RecordSetStringW( uirow, 2, qualifier);
5371 msi_ui_actiondata( package, szPublishComponents, uirow );
5372 msiobj_release( &uirow->hdr );
5373 /* FIXME: call ui_progress? */
5379 * At present I am ignorning the advertised components part of this and only
5380 * focusing on the qualified component sets
5382 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5384 static const WCHAR query[] = {
5385 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5386 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5390 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5391 if (rc != ERROR_SUCCESS)
5392 return ERROR_SUCCESS;
5394 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5395 msiobj_release(&view->hdr);
5399 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5401 static const WCHAR szInstallerComponents[] = {
5402 'S','o','f','t','w','a','r','e','\\',
5403 'M','i','c','r','o','s','o','f','t','\\',
5404 'I','n','s','t','a','l','l','e','r','\\',
5405 'C','o','m','p','o','n','e','n','t','s','\\',0};
5407 MSIPACKAGE *package = param;
5408 LPCWSTR compgroupid, component, feature, qualifier;
5412 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5415 feature = MSI_RecordGetString( rec, 5 );
5416 feat = msi_get_loaded_feature( package, feature );
5418 return ERROR_SUCCESS;
5420 feat->Action = msi_get_feature_action( package, feat );
5421 if (feat->Action != INSTALLSTATE_ABSENT)
5423 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5424 return ERROR_SUCCESS;
5427 component = MSI_RecordGetString( rec, 3 );
5428 comp = msi_get_loaded_component( package, component );
5430 return ERROR_SUCCESS;
5432 compgroupid = MSI_RecordGetString( rec, 1 );
5433 qualifier = MSI_RecordGetString( rec, 2 );
5435 squash_guid( compgroupid, squashed );
5436 strcpyW( keypath, szInstallerComponents );
5437 strcatW( keypath, squashed );
5439 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5440 if (res != ERROR_SUCCESS)
5442 WARN("Unable to delete component key %d\n", res);
5445 uirow = MSI_CreateRecord( 2 );
5446 MSI_RecordSetStringW( uirow, 1, compgroupid );
5447 MSI_RecordSetStringW( uirow, 2, qualifier );
5448 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5449 msiobj_release( &uirow->hdr );
5451 return ERROR_SUCCESS;
5454 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5456 static const WCHAR query[] = {
5457 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5458 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5462 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5463 if (rc != ERROR_SUCCESS)
5464 return ERROR_SUCCESS;
5466 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5467 msiobj_release( &view->hdr );
5471 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5473 static const WCHAR query[] =
5474 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5475 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5476 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5477 MSIPACKAGE *package = param;
5478 MSICOMPONENT *component;
5481 SC_HANDLE hscm = NULL, service = NULL;
5483 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5484 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5485 DWORD serv_type, start_type, err_control;
5486 SERVICE_DESCRIPTIONW sd = {NULL};
5488 comp = MSI_RecordGetString( rec, 12 );
5489 component = msi_get_loaded_component( package, comp );
5492 WARN("service component not found\n");
5495 component->Action = msi_get_component_action( package, component );
5496 if (component->Action != INSTALLSTATE_LOCAL)
5498 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5501 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5504 ERR("Failed to open the SC Manager!\n");
5508 start_type = MSI_RecordGetInteger(rec, 5);
5509 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5512 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5513 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5514 serv_type = MSI_RecordGetInteger(rec, 4);
5515 err_control = MSI_RecordGetInteger(rec, 6);
5516 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5517 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5518 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5519 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5520 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5521 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5523 /* fetch the service path */
5524 row = MSI_QueryGetRecord(package->db, query, comp);
5527 ERR("Query failed\n");
5530 key = MSI_RecordGetString(row, 6);
5531 file = msi_get_loaded_file(package, key);
5532 msiobj_release(&row->hdr);
5535 ERR("Failed to load the service file\n");
5539 if (!args || !args[0]) image_path = file->TargetPath;
5542 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5543 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5544 return ERROR_OUTOFMEMORY;
5546 strcpyW(image_path, file->TargetPath);
5547 strcatW(image_path, szSpace);
5548 strcatW(image_path, args);
5550 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5551 start_type, err_control, image_path, load_order,
5552 NULL, depends, serv_name, pass);
5556 if (GetLastError() != ERROR_SERVICE_EXISTS)
5557 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5559 else if (sd.lpDescription)
5561 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5562 WARN("failed to set service description %u\n", GetLastError());
5565 if (image_path != file->TargetPath) msi_free(image_path);
5567 CloseServiceHandle(service);
5568 CloseServiceHandle(hscm);
5571 msi_free(sd.lpDescription);
5572 msi_free(load_order);
5573 msi_free(serv_name);
5578 return ERROR_SUCCESS;
5581 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5583 static const WCHAR query[] = {
5584 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5585 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5589 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5590 if (rc != ERROR_SUCCESS)
5591 return ERROR_SUCCESS;
5593 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5594 msiobj_release(&view->hdr);
5598 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5599 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5601 LPCWSTR *vector, *temp_vector;
5605 static const WCHAR separator[] = {'[','~',']',0};
5608 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5613 vector = msi_alloc(sizeof(LPWSTR));
5621 vector[*numargs - 1] = p;
5623 if ((q = strstrW(p, separator)))
5627 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5633 vector = temp_vector;
5642 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5644 MSIPACKAGE *package = param;
5647 SC_HANDLE scm = NULL, service = NULL;
5648 LPCWSTR component, *vector = NULL;
5649 LPWSTR name, args, display_name = NULL;
5650 DWORD event, numargs, len, wait, dummy;
5651 UINT r = ERROR_FUNCTION_FAILED;
5652 SERVICE_STATUS_PROCESS status;
5653 ULONGLONG start_time;
5655 component = MSI_RecordGetString(rec, 6);
5656 comp = msi_get_loaded_component(package, component);
5658 return ERROR_SUCCESS;
5660 comp->Action = msi_get_component_action( package, comp );
5661 if (comp->Action != INSTALLSTATE_LOCAL)
5663 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5664 return ERROR_SUCCESS;
5667 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5668 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5669 event = MSI_RecordGetInteger(rec, 3);
5670 wait = MSI_RecordGetInteger(rec, 5);
5672 if (!(event & msidbServiceControlEventStart))
5678 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5681 ERR("Failed to open the service control manager\n");
5686 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5687 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5689 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5690 GetServiceDisplayNameW( scm, name, display_name, &len );
5693 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5696 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5700 vector = msi_service_args_to_vector(args, &numargs);
5702 if (!StartServiceW(service, numargs, vector) &&
5703 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5705 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5712 /* wait for at most 30 seconds for the service to be up and running */
5713 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5714 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5716 TRACE("failed to query service status (%u)\n", GetLastError());
5719 start_time = GetTickCount64();
5720 while (status.dwCurrentState == SERVICE_START_PENDING)
5722 if (GetTickCount64() - start_time > 30000) break;
5724 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5725 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5727 TRACE("failed to query service status (%u)\n", GetLastError());
5731 if (status.dwCurrentState != SERVICE_RUNNING)
5733 WARN("service failed to start %u\n", status.dwCurrentState);
5734 r = ERROR_FUNCTION_FAILED;
5739 uirow = MSI_CreateRecord( 2 );
5740 MSI_RecordSetStringW( uirow, 1, display_name );
5741 MSI_RecordSetStringW( uirow, 2, name );
5742 msi_ui_actiondata( package, szStartServices, uirow );
5743 msiobj_release( &uirow->hdr );
5745 CloseServiceHandle(service);
5746 CloseServiceHandle(scm);
5751 msi_free(display_name);
5755 static UINT ACTION_StartServices( MSIPACKAGE *package )
5757 static const WCHAR query[] = {
5758 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5759 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5763 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5764 if (rc != ERROR_SUCCESS)
5765 return ERROR_SUCCESS;
5767 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5768 msiobj_release(&view->hdr);
5772 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5774 DWORD i, needed, count;
5775 ENUM_SERVICE_STATUSW *dependencies;
5779 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5780 0, &needed, &count))
5783 if (GetLastError() != ERROR_MORE_DATA)
5786 dependencies = msi_alloc(needed);
5790 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5791 needed, &needed, &count))
5794 for (i = 0; i < count; i++)
5796 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5797 SERVICE_STOP | SERVICE_QUERY_STATUS);
5801 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5808 msi_free(dependencies);
5812 static UINT stop_service( LPCWSTR name )
5814 SC_HANDLE scm = NULL, service = NULL;
5815 SERVICE_STATUS status;
5816 SERVICE_STATUS_PROCESS ssp;
5819 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5822 WARN("Failed to open the SCM: %d\n", GetLastError());
5826 service = OpenServiceW(scm, name,
5828 SERVICE_QUERY_STATUS |
5829 SERVICE_ENUMERATE_DEPENDENTS);
5832 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5836 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5837 sizeof(SERVICE_STATUS_PROCESS), &needed))
5839 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5843 if (ssp.dwCurrentState == SERVICE_STOPPED)
5846 stop_service_dependents(scm, service);
5848 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5849 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5852 CloseServiceHandle(service);
5853 CloseServiceHandle(scm);
5855 return ERROR_SUCCESS;
5858 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5860 MSIPACKAGE *package = param;
5864 LPWSTR name = NULL, display_name = NULL;
5868 event = MSI_RecordGetInteger( rec, 3 );
5869 if (!(event & msidbServiceControlEventStop))
5870 return ERROR_SUCCESS;
5872 component = MSI_RecordGetString( rec, 6 );
5873 comp = msi_get_loaded_component( package, component );
5875 return ERROR_SUCCESS;
5877 comp->Action = msi_get_component_action( package, comp );
5878 if (comp->Action != INSTALLSTATE_ABSENT)
5880 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5881 return ERROR_SUCCESS;
5884 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5887 ERR("Failed to open the service control manager\n");
5892 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5893 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5895 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5896 GetServiceDisplayNameW( scm, name, display_name, &len );
5898 CloseServiceHandle( scm );
5900 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5901 stop_service( name );
5904 uirow = MSI_CreateRecord( 2 );
5905 MSI_RecordSetStringW( uirow, 1, display_name );
5906 MSI_RecordSetStringW( uirow, 2, name );
5907 msi_ui_actiondata( package, szStopServices, uirow );
5908 msiobj_release( &uirow->hdr );
5911 msi_free( display_name );
5912 return ERROR_SUCCESS;
5915 static UINT ACTION_StopServices( MSIPACKAGE *package )
5917 static const WCHAR query[] = {
5918 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5919 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5923 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5924 if (rc != ERROR_SUCCESS)
5925 return ERROR_SUCCESS;
5927 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5928 msiobj_release(&view->hdr);
5932 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5934 MSIPACKAGE *package = param;
5937 LPWSTR name = NULL, display_name = NULL;
5939 SC_HANDLE scm = NULL, service = NULL;
5941 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5943 return ERROR_SUCCESS;
5945 event = MSI_RecordGetInteger( rec, 3 );
5946 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5948 comp->Action = msi_get_component_action( package, comp );
5949 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5950 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5952 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5954 return ERROR_SUCCESS;
5956 stop_service( name );
5958 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5961 WARN("Failed to open the SCM: %d\n", GetLastError());
5966 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5967 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5969 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5970 GetServiceDisplayNameW( scm, name, display_name, &len );
5973 service = OpenServiceW( scm, name, DELETE );
5976 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5980 if (!DeleteService( service ))
5981 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5984 uirow = MSI_CreateRecord( 2 );
5985 MSI_RecordSetStringW( uirow, 1, display_name );
5986 MSI_RecordSetStringW( uirow, 2, name );
5987 msi_ui_actiondata( package, szDeleteServices, uirow );
5988 msiobj_release( &uirow->hdr );
5990 CloseServiceHandle( service );
5991 CloseServiceHandle( scm );
5993 msi_free( display_name );
5995 return ERROR_SUCCESS;
5998 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6000 static const WCHAR query[] = {
6001 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6002 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6006 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6007 if (rc != ERROR_SUCCESS)
6008 return ERROR_SUCCESS;
6010 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6011 msiobj_release( &view->hdr );
6015 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6017 MSIPACKAGE *package = param;
6018 LPWSTR driver, driver_path, ptr;
6019 WCHAR outpath[MAX_PATH];
6020 MSIFILE *driver_file = NULL, *setup_file = NULL;
6023 LPCWSTR desc, file_key, component;
6025 UINT r = ERROR_SUCCESS;
6027 static const WCHAR driver_fmt[] = {
6028 'D','r','i','v','e','r','=','%','s',0};
6029 static const WCHAR setup_fmt[] = {
6030 'S','e','t','u','p','=','%','s',0};
6031 static const WCHAR usage_fmt[] = {
6032 'F','i','l','e','U','s','a','g','e','=','1',0};
6034 component = MSI_RecordGetString( rec, 2 );
6035 comp = msi_get_loaded_component( package, component );
6037 return ERROR_SUCCESS;
6039 comp->Action = msi_get_component_action( package, comp );
6040 if (comp->Action != INSTALLSTATE_LOCAL)
6042 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6043 return ERROR_SUCCESS;
6045 desc = MSI_RecordGetString(rec, 3);
6047 file_key = MSI_RecordGetString( rec, 4 );
6048 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6050 file_key = MSI_RecordGetString( rec, 5 );
6051 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6055 ERR("ODBC Driver entry not found!\n");
6056 return ERROR_FUNCTION_FAILED;
6059 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6061 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6062 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6064 driver = msi_alloc(len * sizeof(WCHAR));
6066 return ERROR_OUTOFMEMORY;
6069 lstrcpyW(ptr, desc);
6070 ptr += lstrlenW(ptr) + 1;
6072 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6077 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6081 lstrcpyW(ptr, usage_fmt);
6082 ptr += lstrlenW(ptr) + 1;
6085 if (!driver_file->TargetPath)
6087 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6088 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6090 driver_path = strdupW(driver_file->TargetPath);
6091 ptr = strrchrW(driver_path, '\\');
6092 if (ptr) *ptr = '\0';
6094 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6095 NULL, ODBC_INSTALL_COMPLETE, &usage))
6097 ERR("Failed to install SQL driver!\n");
6098 r = ERROR_FUNCTION_FAILED;
6101 uirow = MSI_CreateRecord( 5 );
6102 MSI_RecordSetStringW( uirow, 1, desc );
6103 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6104 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6105 msi_ui_actiondata( package, szInstallODBC, uirow );
6106 msiobj_release( &uirow->hdr );
6109 msi_free(driver_path);
6114 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6116 MSIPACKAGE *package = param;
6117 LPWSTR translator, translator_path, ptr;
6118 WCHAR outpath[MAX_PATH];
6119 MSIFILE *translator_file = NULL, *setup_file = NULL;
6122 LPCWSTR desc, file_key, component;
6124 UINT r = ERROR_SUCCESS;
6126 static const WCHAR translator_fmt[] = {
6127 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6128 static const WCHAR setup_fmt[] = {
6129 'S','e','t','u','p','=','%','s',0};
6131 component = MSI_RecordGetString( rec, 2 );
6132 comp = msi_get_loaded_component( package, component );
6134 return ERROR_SUCCESS;
6136 comp->Action = msi_get_component_action( package, comp );
6137 if (comp->Action != INSTALLSTATE_LOCAL)
6139 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6140 return ERROR_SUCCESS;
6142 desc = MSI_RecordGetString(rec, 3);
6144 file_key = MSI_RecordGetString( rec, 4 );
6145 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6147 file_key = MSI_RecordGetString( rec, 5 );
6148 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6150 if (!translator_file)
6152 ERR("ODBC Translator entry not found!\n");
6153 return ERROR_FUNCTION_FAILED;
6156 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6158 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6160 translator = msi_alloc(len * sizeof(WCHAR));
6162 return ERROR_OUTOFMEMORY;
6165 lstrcpyW(ptr, desc);
6166 ptr += lstrlenW(ptr) + 1;
6168 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6173 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6178 translator_path = strdupW(translator_file->TargetPath);
6179 ptr = strrchrW(translator_path, '\\');
6180 if (ptr) *ptr = '\0';
6182 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6183 NULL, ODBC_INSTALL_COMPLETE, &usage))
6185 ERR("Failed to install SQL translator!\n");
6186 r = ERROR_FUNCTION_FAILED;
6189 uirow = MSI_CreateRecord( 5 );
6190 MSI_RecordSetStringW( uirow, 1, desc );
6191 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6192 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6193 msi_ui_actiondata( package, szInstallODBC, uirow );
6194 msiobj_release( &uirow->hdr );
6196 msi_free(translator);
6197 msi_free(translator_path);
6202 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6204 MSIPACKAGE *package = param;
6207 LPCWSTR desc, driver, component;
6208 WORD request = ODBC_ADD_SYS_DSN;
6211 UINT r = ERROR_SUCCESS;
6214 static const WCHAR attrs_fmt[] = {
6215 'D','S','N','=','%','s',0 };
6217 component = MSI_RecordGetString( rec, 2 );
6218 comp = msi_get_loaded_component( package, component );
6220 return ERROR_SUCCESS;
6222 comp->Action = msi_get_component_action( package, comp );
6223 if (comp->Action != INSTALLSTATE_LOCAL)
6225 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6226 return ERROR_SUCCESS;
6229 desc = MSI_RecordGetString(rec, 3);
6230 driver = MSI_RecordGetString(rec, 4);
6231 registration = MSI_RecordGetInteger(rec, 5);
6233 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6234 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6236 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6237 attrs = msi_alloc(len * sizeof(WCHAR));
6239 return ERROR_OUTOFMEMORY;
6241 len = sprintfW(attrs, attrs_fmt, desc);
6244 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6246 ERR("Failed to install SQL data source!\n");
6247 r = ERROR_FUNCTION_FAILED;
6250 uirow = MSI_CreateRecord( 5 );
6251 MSI_RecordSetStringW( uirow, 1, desc );
6252 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6253 MSI_RecordSetInteger( uirow, 3, request );
6254 msi_ui_actiondata( package, szInstallODBC, uirow );
6255 msiobj_release( &uirow->hdr );
6262 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6264 static const WCHAR driver_query[] = {
6265 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6266 'O','D','B','C','D','r','i','v','e','r',0};
6267 static const WCHAR translator_query[] = {
6268 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6269 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6270 static const WCHAR source_query[] = {
6271 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6272 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6276 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6277 if (rc == ERROR_SUCCESS)
6279 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6280 msiobj_release(&view->hdr);
6281 if (rc != ERROR_SUCCESS)
6284 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6285 if (rc == ERROR_SUCCESS)
6287 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6288 msiobj_release(&view->hdr);
6289 if (rc != ERROR_SUCCESS)
6292 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6293 if (rc == ERROR_SUCCESS)
6295 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6296 msiobj_release(&view->hdr);
6297 if (rc != ERROR_SUCCESS)
6300 return ERROR_SUCCESS;
6303 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6305 MSIPACKAGE *package = param;
6309 LPCWSTR desc, component;
6311 component = MSI_RecordGetString( rec, 2 );
6312 comp = msi_get_loaded_component( package, component );
6314 return ERROR_SUCCESS;
6316 comp->Action = msi_get_component_action( package, comp );
6317 if (comp->Action != INSTALLSTATE_ABSENT)
6319 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6320 return ERROR_SUCCESS;
6323 desc = MSI_RecordGetString( rec, 3 );
6324 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6326 WARN("Failed to remove ODBC driver\n");
6330 FIXME("Usage count reached 0\n");
6333 uirow = MSI_CreateRecord( 2 );
6334 MSI_RecordSetStringW( uirow, 1, desc );
6335 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6336 msi_ui_actiondata( package, szRemoveODBC, uirow );
6337 msiobj_release( &uirow->hdr );
6339 return ERROR_SUCCESS;
6342 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6344 MSIPACKAGE *package = param;
6348 LPCWSTR desc, component;
6350 component = MSI_RecordGetString( rec, 2 );
6351 comp = msi_get_loaded_component( package, component );
6353 return ERROR_SUCCESS;
6355 comp->Action = msi_get_component_action( package, comp );
6356 if (comp->Action != INSTALLSTATE_ABSENT)
6358 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6359 return ERROR_SUCCESS;
6362 desc = MSI_RecordGetString( rec, 3 );
6363 if (!SQLRemoveTranslatorW( desc, &usage ))
6365 WARN("Failed to remove ODBC translator\n");
6369 FIXME("Usage count reached 0\n");
6372 uirow = MSI_CreateRecord( 2 );
6373 MSI_RecordSetStringW( uirow, 1, desc );
6374 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6375 msi_ui_actiondata( package, szRemoveODBC, uirow );
6376 msiobj_release( &uirow->hdr );
6378 return ERROR_SUCCESS;
6381 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6383 MSIPACKAGE *package = param;
6387 LPCWSTR desc, driver, component;
6388 WORD request = ODBC_REMOVE_SYS_DSN;
6392 static const WCHAR attrs_fmt[] = {
6393 'D','S','N','=','%','s',0 };
6395 component = MSI_RecordGetString( rec, 2 );
6396 comp = msi_get_loaded_component( package, component );
6398 return ERROR_SUCCESS;
6400 comp->Action = msi_get_component_action( package, comp );
6401 if (comp->Action != INSTALLSTATE_ABSENT)
6403 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6404 return ERROR_SUCCESS;
6407 desc = MSI_RecordGetString( rec, 3 );
6408 driver = MSI_RecordGetString( rec, 4 );
6409 registration = MSI_RecordGetInteger( rec, 5 );
6411 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6412 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6414 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6415 attrs = msi_alloc( len * sizeof(WCHAR) );
6417 return ERROR_OUTOFMEMORY;
6419 FIXME("Use ODBCSourceAttribute table\n");
6421 len = sprintfW( attrs, attrs_fmt, desc );
6424 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6426 WARN("Failed to remove ODBC data source\n");
6430 uirow = MSI_CreateRecord( 3 );
6431 MSI_RecordSetStringW( uirow, 1, desc );
6432 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6433 MSI_RecordSetInteger( uirow, 3, request );
6434 msi_ui_actiondata( package, szRemoveODBC, uirow );
6435 msiobj_release( &uirow->hdr );
6437 return ERROR_SUCCESS;
6440 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6442 static const WCHAR driver_query[] = {
6443 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6444 'O','D','B','C','D','r','i','v','e','r',0};
6445 static const WCHAR translator_query[] = {
6446 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6447 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6448 static const WCHAR source_query[] = {
6449 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6450 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6454 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6455 if (rc == ERROR_SUCCESS)
6457 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6458 msiobj_release( &view->hdr );
6459 if (rc != ERROR_SUCCESS)
6462 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6463 if (rc == ERROR_SUCCESS)
6465 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6466 msiobj_release( &view->hdr );
6467 if (rc != ERROR_SUCCESS)
6470 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6471 if (rc == ERROR_SUCCESS)
6473 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6474 msiobj_release( &view->hdr );
6475 if (rc != ERROR_SUCCESS)
6478 return ERROR_SUCCESS;
6481 #define ENV_ACT_SETALWAYS 0x1
6482 #define ENV_ACT_SETABSENT 0x2
6483 #define ENV_ACT_REMOVE 0x4
6484 #define ENV_ACT_REMOVEMATCH 0x8
6486 #define ENV_MOD_MACHINE 0x20000000
6487 #define ENV_MOD_APPEND 0x40000000
6488 #define ENV_MOD_PREFIX 0x80000000
6489 #define ENV_MOD_MASK 0xC0000000
6491 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6493 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6495 LPCWSTR cptr = *name;
6497 static const WCHAR prefix[] = {'[','~',']',0};
6498 static const int prefix_len = 3;
6504 *flags |= ENV_ACT_SETALWAYS;
6505 else if (*cptr == '+')
6506 *flags |= ENV_ACT_SETABSENT;
6507 else if (*cptr == '-')
6508 *flags |= ENV_ACT_REMOVE;
6509 else if (*cptr == '!')
6510 *flags |= ENV_ACT_REMOVEMATCH;
6511 else if (*cptr == '*')
6512 *flags |= ENV_MOD_MACHINE;
6522 ERR("Missing environment variable\n");
6523 return ERROR_FUNCTION_FAILED;
6528 LPCWSTR ptr = *value;
6529 if (!strncmpW(ptr, prefix, prefix_len))
6531 if (ptr[prefix_len] == szSemiColon[0])
6533 *flags |= ENV_MOD_APPEND;
6534 *value += lstrlenW(prefix);
6541 else if (lstrlenW(*value) >= prefix_len)
6543 ptr += lstrlenW(ptr) - prefix_len;
6544 if (!strcmpW( ptr, prefix ))
6546 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6548 *flags |= ENV_MOD_PREFIX;
6549 /* the "[~]" will be removed by deformat_string */;
6559 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6560 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6561 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6562 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6564 ERR("Invalid flags: %08x\n", *flags);
6565 return ERROR_FUNCTION_FAILED;
6569 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6571 return ERROR_SUCCESS;
6574 static UINT open_env_key( DWORD flags, HKEY *key )
6576 static const WCHAR user_env[] =
6577 {'E','n','v','i','r','o','n','m','e','n','t',0};
6578 static const WCHAR machine_env[] =
6579 {'S','y','s','t','e','m','\\',
6580 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6581 'C','o','n','t','r','o','l','\\',
6582 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6583 'E','n','v','i','r','o','n','m','e','n','t',0};
6588 if (flags & ENV_MOD_MACHINE)
6591 root = HKEY_LOCAL_MACHINE;
6596 root = HKEY_CURRENT_USER;
6599 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6600 if (res != ERROR_SUCCESS)
6602 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6603 return ERROR_FUNCTION_FAILED;
6606 return ERROR_SUCCESS;
6609 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6611 MSIPACKAGE *package = param;
6612 LPCWSTR name, value, component;
6613 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6614 DWORD flags, type, size;
6621 component = MSI_RecordGetString(rec, 4);
6622 comp = msi_get_loaded_component(package, component);
6624 return ERROR_SUCCESS;
6626 comp->Action = msi_get_component_action( package, comp );
6627 if (comp->Action != INSTALLSTATE_LOCAL)
6629 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6630 return ERROR_SUCCESS;
6632 name = MSI_RecordGetString(rec, 2);
6633 value = MSI_RecordGetString(rec, 3);
6635 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6637 res = env_parse_flags(&name, &value, &flags);
6638 if (res != ERROR_SUCCESS || !value)
6641 if (value && !deformat_string(package, value, &deformatted))
6643 res = ERROR_OUTOFMEMORY;
6647 value = deformatted;
6649 res = open_env_key( flags, &env );
6650 if (res != ERROR_SUCCESS)
6653 if (flags & ENV_MOD_MACHINE)
6654 action |= 0x20000000;
6658 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6659 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6660 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6663 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6667 /* Nothing to do. */
6670 res = ERROR_SUCCESS;
6674 /* If we are appending but the string was empty, strip ; */
6675 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6677 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6678 newval = strdupW(value);
6681 res = ERROR_OUTOFMEMORY;
6689 /* Contrary to MSDN, +-variable to [~];path works */
6690 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6692 res = ERROR_SUCCESS;
6696 data = msi_alloc(size);
6700 return ERROR_OUTOFMEMORY;
6703 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6704 if (res != ERROR_SUCCESS)
6707 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6710 res = RegDeleteValueW(env, name);
6711 if (res != ERROR_SUCCESS)
6712 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6716 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6717 if (flags & ENV_MOD_MASK)
6721 if (flags & ENV_MOD_APPEND) multiplier++;
6722 if (flags & ENV_MOD_PREFIX) multiplier++;
6723 mod_size = lstrlenW(value) * multiplier;
6724 size += mod_size * sizeof(WCHAR);
6727 newval = msi_alloc(size);
6731 res = ERROR_OUTOFMEMORY;
6735 if (flags & ENV_MOD_PREFIX)
6737 lstrcpyW(newval, value);
6738 ptr = newval + lstrlenW(value);
6739 action |= 0x80000000;
6742 lstrcpyW(ptr, data);
6744 if (flags & ENV_MOD_APPEND)
6746 lstrcatW(newval, value);
6747 action |= 0x40000000;
6750 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6751 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6754 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6758 uirow = MSI_CreateRecord( 3 );
6759 MSI_RecordSetStringW( uirow, 1, name );
6760 MSI_RecordSetStringW( uirow, 2, newval );
6761 MSI_RecordSetInteger( uirow, 3, action );
6762 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6763 msiobj_release( &uirow->hdr );
6765 if (env) RegCloseKey(env);
6766 msi_free(deformatted);
6772 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6774 static const WCHAR query[] = {
6775 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6776 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6780 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6781 if (rc != ERROR_SUCCESS)
6782 return ERROR_SUCCESS;
6784 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6785 msiobj_release(&view->hdr);
6789 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6791 MSIPACKAGE *package = param;
6792 LPCWSTR name, value, component;
6793 LPWSTR deformatted = NULL;
6802 component = MSI_RecordGetString( rec, 4 );
6803 comp = msi_get_loaded_component( package, component );
6805 return ERROR_SUCCESS;
6807 comp->Action = msi_get_component_action( package, comp );
6808 if (comp->Action != INSTALLSTATE_ABSENT)
6810 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6811 return ERROR_SUCCESS;
6813 name = MSI_RecordGetString( rec, 2 );
6814 value = MSI_RecordGetString( rec, 3 );
6816 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6818 r = env_parse_flags( &name, &value, &flags );
6819 if (r != ERROR_SUCCESS)
6822 if (!(flags & ENV_ACT_REMOVE))
6824 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6825 return ERROR_SUCCESS;
6828 if (value && !deformat_string( package, value, &deformatted ))
6829 return ERROR_OUTOFMEMORY;
6831 value = deformatted;
6833 r = open_env_key( flags, &env );
6834 if (r != ERROR_SUCCESS)
6840 if (flags & ENV_MOD_MACHINE)
6841 action |= 0x20000000;
6843 TRACE("Removing %s\n", debugstr_w(name));
6845 res = RegDeleteValueW( env, name );
6846 if (res != ERROR_SUCCESS)
6848 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6853 uirow = MSI_CreateRecord( 3 );
6854 MSI_RecordSetStringW( uirow, 1, name );
6855 MSI_RecordSetStringW( uirow, 2, value );
6856 MSI_RecordSetInteger( uirow, 3, action );
6857 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6858 msiobj_release( &uirow->hdr );
6860 if (env) RegCloseKey( env );
6861 msi_free( deformatted );
6865 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6867 static const WCHAR query[] = {
6868 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6869 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6873 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6874 if (rc != ERROR_SUCCESS)
6875 return ERROR_SUCCESS;
6877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6878 msiobj_release( &view->hdr );
6882 UINT msi_validate_product_id( MSIPACKAGE *package )
6884 LPWSTR key, template, id;
6885 UINT r = ERROR_SUCCESS;
6887 id = msi_dup_property( package->db, szProductID );
6891 return ERROR_SUCCESS;
6893 template = msi_dup_property( package->db, szPIDTemplate );
6894 key = msi_dup_property( package->db, szPIDKEY );
6895 if (key && template)
6897 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6898 r = msi_set_property( package->db, szProductID, key );
6900 msi_free( template );
6905 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6907 return msi_validate_product_id( package );
6910 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6913 package->need_reboot_at_end = 1;
6914 return ERROR_SUCCESS;
6917 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6919 static const WCHAR szAvailableFreeReg[] =
6920 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6922 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6924 TRACE("%p %d kilobytes\n", package, space);
6926 uirow = MSI_CreateRecord( 1 );
6927 MSI_RecordSetInteger( uirow, 1, space );
6928 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6929 msiobj_release( &uirow->hdr );
6931 return ERROR_SUCCESS;
6934 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6936 TRACE("%p\n", package);
6938 msi_set_property( package->db, szRollbackDisabled, szOne );
6939 return ERROR_SUCCESS;
6942 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6944 FIXME("%p\n", package);
6945 return ERROR_SUCCESS;
6948 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6950 static const WCHAR driver_query[] = {
6951 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6952 'O','D','B','C','D','r','i','v','e','r',0};
6953 static const WCHAR translator_query[] = {
6954 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6955 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6959 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6960 if (r == ERROR_SUCCESS)
6963 r = MSI_IterateRecords( view, &count, NULL, package );
6964 msiobj_release( &view->hdr );
6965 if (r != ERROR_SUCCESS)
6967 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6969 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6970 if (r == ERROR_SUCCESS)
6973 r = MSI_IterateRecords( view, &count, NULL, package );
6974 msiobj_release( &view->hdr );
6975 if (r != ERROR_SUCCESS)
6977 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6979 return ERROR_SUCCESS;
6982 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6984 MSIPACKAGE *package = param;
6985 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6988 if ((value = msi_dup_property( package->db, property )))
6990 FIXME("remove %s\n", debugstr_w(value));
6993 return ERROR_SUCCESS;
6996 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6998 static const WCHAR query[] = {
6999 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7000 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7004 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7005 if (r == ERROR_SUCCESS)
7007 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7008 msiobj_release( &view->hdr );
7009 if (r != ERROR_SUCCESS)
7012 return ERROR_SUCCESS;
7015 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7017 MSIPACKAGE *package = param;
7018 int attributes = MSI_RecordGetInteger( rec, 5 );
7020 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7022 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7023 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7024 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7025 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7029 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7031 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7032 if (r != ERROR_SUCCESS)
7033 return ERROR_SUCCESS;
7037 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7038 if (r != ERROR_SUCCESS)
7039 return ERROR_SUCCESS;
7041 RegCloseKey( hkey );
7043 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7044 debugstr_w(upgrade_code), debugstr_w(version_min),
7045 debugstr_w(version_max), debugstr_w(language));
7047 return ERROR_SUCCESS;
7050 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7052 static const WCHAR query[] = {
7053 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7054 'U','p','g','r','a','d','e',0};
7058 if (msi_get_property_int( package->db, szInstalled, 0 ))
7060 TRACE("product is installed, skipping action\n");
7061 return ERROR_SUCCESS;
7063 if (msi_get_property_int( package->db, szPreselected, 0 ))
7065 TRACE("Preselected property is set, not migrating feature states\n");
7066 return ERROR_SUCCESS;
7068 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7069 if (r == ERROR_SUCCESS)
7071 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7072 msiobj_release( &view->hdr );
7073 if (r != ERROR_SUCCESS)
7076 return ERROR_SUCCESS;
7079 static void bind_image( const char *filename, const char *path )
7081 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7083 WARN("failed to bind image %u\n", GetLastError());
7087 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7091 MSIPACKAGE *package = param;
7092 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7093 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7094 char *filenameA, *pathA;
7095 WCHAR *pathW, **path_list;
7097 if (!(file = msi_get_loaded_file( package, key )))
7099 WARN("file %s not found\n", debugstr_w(key));
7100 return ERROR_SUCCESS;
7102 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7103 path_list = msi_split_string( paths, ';' );
7104 if (!path_list) bind_image( filenameA, NULL );
7107 for (i = 0; path_list[i] && path_list[i][0]; i++)
7109 deformat_string( package, path_list[i], &pathW );
7110 if ((pathA = strdupWtoA( pathW )))
7112 bind_image( filenameA, pathA );
7118 msi_free( path_list );
7119 msi_free( filenameA );
7120 return ERROR_SUCCESS;
7123 static UINT ACTION_BindImage( MSIPACKAGE *package )
7125 static const WCHAR query[] = {
7126 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7127 'B','i','n','d','I','m','a','g','e',0};
7131 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7132 if (r == ERROR_SUCCESS)
7134 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7135 msiobj_release( &view->hdr );
7136 if (r != ERROR_SUCCESS)
7139 return ERROR_SUCCESS;
7142 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7144 static const WCHAR query[] = {
7145 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7150 r = MSI_OpenQuery( package->db, &view, query, table );
7151 if (r == ERROR_SUCCESS)
7153 r = MSI_IterateRecords(view, &count, NULL, package);
7154 msiobj_release(&view->hdr);
7155 if (r != ERROR_SUCCESS)
7158 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7159 return ERROR_SUCCESS;
7162 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7164 static const WCHAR table[] = {
7165 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7166 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7169 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7171 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7172 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7175 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7177 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7178 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7181 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7183 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7184 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7187 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7189 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7190 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7195 const WCHAR *action;
7196 UINT (*handler)(MSIPACKAGE *);
7197 const WCHAR *action_rollback;
7201 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7202 { szAppSearch, ACTION_AppSearch, NULL },
7203 { szBindImage, ACTION_BindImage, NULL },
7204 { szCCPSearch, ACTION_CCPSearch, NULL },
7205 { szCostFinalize, ACTION_CostFinalize, NULL },
7206 { szCostInitialize, ACTION_CostInitialize, NULL },
7207 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7208 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7209 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7210 { szDisableRollback, ACTION_DisableRollback, NULL },
7211 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7212 { szExecuteAction, ACTION_ExecuteAction, NULL },
7213 { szFileCost, ACTION_FileCost, NULL },
7214 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7215 { szForceReboot, ACTION_ForceReboot, NULL },
7216 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7217 { szInstallExecute, ACTION_InstallExecute, NULL },
7218 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7219 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7220 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7221 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7222 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7223 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7224 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7225 { szInstallValidate, ACTION_InstallValidate, NULL },
7226 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7227 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7228 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7229 { szMoveFiles, ACTION_MoveFiles, NULL },
7230 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7231 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7232 { szPatchFiles, ACTION_PatchFiles, NULL },
7233 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7234 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7235 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7236 { szPublishProduct, ACTION_PublishProduct, NULL },
7237 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7238 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7239 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7240 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7241 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7242 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7243 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7244 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7245 { szRegisterUser, ACTION_RegisterUser, NULL },
7246 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7247 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7248 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7249 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7250 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7251 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7252 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7253 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7254 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7255 { szResolveSource, ACTION_ResolveSource, NULL },
7256 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7257 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7258 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7259 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7260 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7261 { szStartServices, ACTION_StartServices, szStopServices },
7262 { szStopServices, ACTION_StopServices, szStartServices },
7263 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7264 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7265 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7266 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7267 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7268 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7269 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7270 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7271 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7272 { szValidateProductID, ACTION_ValidateProductID, NULL },
7273 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7274 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7275 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7276 { NULL, NULL, NULL }
7279 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7285 while (StandardActions[i].action != NULL)
7287 if (!strcmpW( StandardActions[i].action, action ))
7289 ui_actionstart( package, action );
7290 if (StandardActions[i].handler)
7292 ui_actioninfo( package, action, TRUE, 0 );
7293 *rc = StandardActions[i].handler( package );
7294 ui_actioninfo( package, action, FALSE, *rc );
7296 if (StandardActions[i].action_rollback && !package->need_rollback)
7298 TRACE("scheduling rollback action\n");
7299 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7304 FIXME("unhandled standard action %s\n", debugstr_w(action));
7305 *rc = ERROR_SUCCESS;
7315 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7317 UINT rc = ERROR_SUCCESS;
7320 TRACE("Performing action (%s)\n", debugstr_w(action));
7322 handled = ACTION_HandleStandardAction(package, action, &rc);
7325 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7329 WARN("unhandled msi action %s\n", debugstr_w(action));
7330 rc = ERROR_FUNCTION_NOT_CALLED;
7336 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7338 UINT rc = ERROR_SUCCESS;
7339 BOOL handled = FALSE;
7341 TRACE("Performing action (%s)\n", debugstr_w(action));
7343 package->action_progress_increment = 0;
7344 handled = ACTION_HandleStandardAction(package, action, &rc);
7347 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7349 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7354 WARN("unhandled msi action %s\n", debugstr_w(action));
7355 rc = ERROR_FUNCTION_NOT_CALLED;
7361 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7363 UINT rc = ERROR_SUCCESS;
7366 static const WCHAR query[] =
7367 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7368 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7369 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7370 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7371 static const WCHAR ui_query[] =
7372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7373 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7374 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7375 ' ', '=',' ','%','i',0};
7377 if (needs_ui_sequence(package))
7378 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7380 row = MSI_QueryGetRecord(package->db, query, seq);
7384 LPCWSTR action, cond;
7386 TRACE("Running the actions\n");
7388 /* check conditions */
7389 cond = MSI_RecordGetString(row, 2);
7391 /* this is a hack to skip errors in the condition code */
7392 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7394 msiobj_release(&row->hdr);
7395 return ERROR_SUCCESS;
7398 action = MSI_RecordGetString(row, 1);
7401 ERR("failed to fetch action\n");
7402 msiobj_release(&row->hdr);
7403 return ERROR_FUNCTION_FAILED;
7406 if (needs_ui_sequence(package))
7407 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7409 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7411 msiobj_release(&row->hdr);
7417 /****************************************************
7418 * TOP level entry points
7419 *****************************************************/
7421 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7422 LPCWSTR szCommandLine )
7424 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7425 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7426 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7427 WCHAR *reinstall = NULL;
7431 msi_set_property( package->db, szAction, szInstall );
7433 package->script->InWhatSequence = SEQUENCE_INSTALL;
7440 dir = strdupW(szPackagePath);
7441 p = strrchrW(dir, '\\');
7445 file = szPackagePath + (p - dir);
7450 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7451 GetCurrentDirectoryW(MAX_PATH, dir);
7452 lstrcatW(dir, szBackSlash);
7453 file = szPackagePath;
7456 msi_free( package->PackagePath );
7457 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7458 if (!package->PackagePath)
7461 return ERROR_OUTOFMEMORY;
7464 lstrcpyW(package->PackagePath, dir);
7465 lstrcatW(package->PackagePath, file);
7468 msi_set_sourcedir_props(package, FALSE);
7471 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7472 if (rc != ERROR_SUCCESS)
7475 msi_apply_transforms( package );
7476 msi_apply_patches( package );
7478 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7480 TRACE("setting reinstall property\n");
7481 msi_set_property( package->db, szReinstall, szAll );
7484 /* properties may have been added by a transform */
7485 msi_clone_properties( package );
7487 msi_parse_command_line( package, szCommandLine, FALSE );
7488 msi_adjust_privilege_properties( package );
7489 msi_set_context( package );
7491 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7493 TRACE("disabling rollback\n");
7494 msi_set_property( package->db, szRollbackDisabled, szOne );
7497 if (needs_ui_sequence( package))
7499 package->script->InWhatSequence |= SEQUENCE_UI;
7500 rc = ACTION_ProcessUISequence(package);
7501 ui_exists = ui_sequence_exists(package);
7502 if (rc == ERROR_SUCCESS || !ui_exists)
7504 package->script->InWhatSequence |= SEQUENCE_EXEC;
7505 rc = ACTION_ProcessExecSequence(package, ui_exists);
7509 rc = ACTION_ProcessExecSequence(package, FALSE);
7511 package->script->CurrentlyScripting = FALSE;
7513 /* process the ending type action */
7514 if (rc == ERROR_SUCCESS)
7515 ACTION_PerformActionSequence(package, -1);
7516 else if (rc == ERROR_INSTALL_USEREXIT)
7517 ACTION_PerformActionSequence(package, -2);
7518 else if (rc == ERROR_INSTALL_SUSPEND)
7519 ACTION_PerformActionSequence(package, -4);
7522 ACTION_PerformActionSequence(package, -3);
7523 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7525 package->need_rollback = TRUE;
7529 /* finish up running custom actions */
7530 ACTION_FinishCustomActions(package);
7532 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7534 WARN("installation failed, running rollback script\n");
7535 execute_script( package, SCRIPT_ROLLBACK );
7537 msi_free( reinstall );
7539 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7540 return ERROR_SUCCESS_REBOOT_REQUIRED;