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( MSICOMPONENT *comp, 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 || is_wow64) &&
2563 !(comp->Attributes & msidbComponentAttributes64bit) &&
2564 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2569 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2570 if (!(path_32node = msi_alloc( size ))) return NULL;
2572 memcpy( path_32node, path, len * sizeof(WCHAR) );
2573 strcpyW( path_32node + len, szWow6432Node );
2574 strcatW( path_32node, szBackSlash );
2575 strcatW( path_32node, path + len );
2578 return strdupW( path );
2581 static BOOL is_special_entry( const WCHAR *name, const WCHAR *value )
2583 return (name && (name[0] == '*' || name[0] == '+') && !name[1] && !value);
2586 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2588 MSIPACKAGE *package = param;
2589 LPSTR value_data = NULL;
2590 HKEY root_key, hkey;
2592 LPWSTR deformated, uikey, keypath;
2593 LPCWSTR szRoot, component, name, key, value;
2597 BOOL check_first = FALSE;
2600 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2602 component = MSI_RecordGetString(row, 6);
2603 comp = msi_get_loaded_component(package,component);
2605 return ERROR_SUCCESS;
2607 comp->Action = msi_get_component_action( package, comp );
2608 if (comp->Action != INSTALLSTATE_LOCAL)
2610 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2611 return ERROR_SUCCESS;
2614 name = MSI_RecordGetString(row, 4);
2615 if( MSI_RecordIsNull(row,5) && name )
2617 /* null values can have special meanings */
2618 if (name[0]=='-' && name[1] == 0)
2619 return ERROR_SUCCESS;
2620 if ((name[0] == '+' || name[0] == '*') && !name[1])
2624 root = MSI_RecordGetInteger(row,2);
2625 key = MSI_RecordGetString(row, 3);
2627 szRoot = get_root_key( package, root, &root_key );
2629 return ERROR_SUCCESS;
2631 deformat_string(package, key , &deformated);
2632 size = strlenW(deformated) + strlenW(szRoot) + 1;
2633 uikey = msi_alloc(size*sizeof(WCHAR));
2634 strcpyW(uikey,szRoot);
2635 strcatW(uikey,deformated);
2637 keypath = get_keypath( comp, root_key, deformated );
2638 msi_free( deformated );
2639 if (RegCreateKeyExW( root_key, keypath, 0, NULL, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, NULL, &hkey, NULL ))
2641 ERR("Could not create key %s\n", debugstr_w(keypath));
2644 return ERROR_SUCCESS;
2647 value = MSI_RecordGetString(row,5);
2649 value_data = parse_value(package, value, &type, &size);
2652 value_data = (LPSTR)strdupW(szEmpty);
2653 size = sizeof(szEmpty);
2657 deformat_string(package, name, &deformated);
2658 if (!is_special_entry( name , value ))
2662 TRACE("Setting value %s of %s\n", debugstr_w(deformated),
2664 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2669 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2670 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2672 TRACE("value %s of %s checked already exists\n", debugstr_w(deformated),
2677 TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated),
2679 if (deformated || size)
2680 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2686 uirow = MSI_CreateRecord(3);
2687 MSI_RecordSetStringW(uirow,2,deformated);
2688 MSI_RecordSetStringW(uirow,1,uikey);
2689 if (type == REG_SZ || type == REG_EXPAND_SZ)
2690 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2691 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2692 msiobj_release( &uirow->hdr );
2694 msi_free(value_data);
2695 msi_free(deformated);
2699 return ERROR_SUCCESS;
2702 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2704 static const WCHAR query[] = {
2705 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2706 '`','R','e','g','i','s','t','r','y','`',0};
2710 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2711 if (rc != ERROR_SUCCESS)
2712 return ERROR_SUCCESS;
2714 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2715 msiobj_release(&view->hdr);
2719 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2723 DWORD num_subkeys, num_values;
2725 if (!(res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey )))
2727 if ((res = RegDeleteValueW( hkey, value )))
2729 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2731 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2732 NULL, NULL, NULL, NULL );
2733 RegCloseKey( hkey );
2734 if (!res && !num_subkeys && !num_values)
2736 TRACE("removing empty key %s\n", debugstr_w(keypath));
2737 RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 );
2741 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2744 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2747 LONG res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey );
2750 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2753 res = RegDeleteTreeW( hkey, NULL );
2754 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(keypath), res);
2755 res = RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 );
2756 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2757 RegCloseKey( hkey );
2760 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2762 MSIPACKAGE *package = param;
2763 LPCWSTR component, name, key_str, root_key_str;
2764 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2767 BOOL delete_key = FALSE;
2772 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2774 component = MSI_RecordGetString( row, 6 );
2775 comp = msi_get_loaded_component( package, component );
2777 return ERROR_SUCCESS;
2779 comp->Action = msi_get_component_action( package, comp );
2780 if (comp->Action != INSTALLSTATE_ABSENT)
2782 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2783 return ERROR_SUCCESS;
2786 name = MSI_RecordGetString( row, 4 );
2787 if (MSI_RecordIsNull( row, 5 ) && name )
2789 if (name[0] == '+' && !name[1])
2790 return ERROR_SUCCESS;
2791 if ((name[0] == '-' || name[0] == '*') && !name[1])
2798 root = MSI_RecordGetInteger( row, 2 );
2799 key_str = MSI_RecordGetString( row, 3 );
2801 root_key_str = get_root_key( package, root, &hkey_root );
2803 return ERROR_SUCCESS;
2805 deformat_string( package, key_str, &deformated_key );
2806 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2807 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2808 strcpyW( ui_key_str, root_key_str );
2809 strcatW( ui_key_str, deformated_key );
2811 deformat_string( package, name, &deformated_name );
2813 keypath = get_keypath( comp, hkey_root, deformated_key );
2814 msi_free( deformated_key );
2815 if (delete_key) delete_reg_key( hkey_root, keypath );
2816 else delete_reg_value( hkey_root, keypath, deformated_name );
2817 msi_free( keypath );
2819 uirow = MSI_CreateRecord( 2 );
2820 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2821 MSI_RecordSetStringW( uirow, 2, deformated_name );
2822 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2823 msiobj_release( &uirow->hdr );
2825 msi_free( ui_key_str );
2826 msi_free( deformated_name );
2827 return ERROR_SUCCESS;
2830 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2832 MSIPACKAGE *package = param;
2833 LPCWSTR component, name, key_str, root_key_str;
2834 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2837 BOOL delete_key = FALSE;
2842 component = MSI_RecordGetString( row, 5 );
2843 comp = msi_get_loaded_component( package, component );
2845 return ERROR_SUCCESS;
2847 comp->Action = msi_get_component_action( package, comp );
2848 if (comp->Action != INSTALLSTATE_LOCAL)
2850 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2851 return ERROR_SUCCESS;
2854 if ((name = MSI_RecordGetString( row, 4 )))
2856 if (name[0] == '-' && !name[1])
2863 root = MSI_RecordGetInteger( row, 2 );
2864 key_str = MSI_RecordGetString( row, 3 );
2866 root_key_str = get_root_key( package, root, &hkey_root );
2868 return ERROR_SUCCESS;
2870 deformat_string( package, key_str, &deformated_key );
2871 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2872 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2873 strcpyW( ui_key_str, root_key_str );
2874 strcatW( ui_key_str, deformated_key );
2876 deformat_string( package, name, &deformated_name );
2878 keypath = get_keypath( comp, hkey_root, deformated_key );
2879 msi_free( deformated_key );
2880 if (delete_key) delete_reg_key( hkey_root, keypath );
2881 else delete_reg_value( hkey_root, keypath, deformated_name );
2882 msi_free( keypath );
2884 uirow = MSI_CreateRecord( 2 );
2885 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2886 MSI_RecordSetStringW( uirow, 2, deformated_name );
2887 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2888 msiobj_release( &uirow->hdr );
2890 msi_free( ui_key_str );
2891 msi_free( deformated_name );
2892 return ERROR_SUCCESS;
2895 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2897 static const WCHAR registry_query[] = {
2898 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2899 '`','R','e','g','i','s','t','r','y','`',0};
2900 static const WCHAR remove_registry_query[] = {
2901 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2902 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2906 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2907 if (rc == ERROR_SUCCESS)
2909 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2910 msiobj_release( &view->hdr );
2911 if (rc != ERROR_SUCCESS)
2914 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2915 if (rc == ERROR_SUCCESS)
2917 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2918 msiobj_release( &view->hdr );
2919 if (rc != ERROR_SUCCESS)
2922 return ERROR_SUCCESS;
2925 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2927 package->script->CurrentlyScripting = TRUE;
2929 return ERROR_SUCCESS;
2933 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2935 static const WCHAR query[]= {
2936 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2937 '`','R','e','g','i','s','t','r','y','`',0};
2939 DWORD total = 0, count = 0;
2941 MSIFEATURE *feature;
2945 TRACE("InstallValidate\n");
2947 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2948 if (rc == ERROR_SUCCESS)
2950 rc = MSI_IterateRecords( view, &count, NULL, package );
2951 msiobj_release( &view->hdr );
2952 if (rc != ERROR_SUCCESS)
2954 total += count * REG_PROGRESS_VALUE;
2956 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2957 total += COMPONENT_PROGRESS_VALUE;
2959 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2960 total += file->FileSize;
2962 msi_ui_progress( package, 0, total, 0, 0 );
2964 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2966 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2967 debugstr_w(feature->Feature), feature->Installed,
2968 feature->ActionRequest, feature->Action);
2970 return ERROR_SUCCESS;
2973 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2975 MSIPACKAGE* package = param;
2976 LPCWSTR cond = NULL;
2977 LPCWSTR message = NULL;
2980 static const WCHAR title[]=
2981 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2983 cond = MSI_RecordGetString(row,1);
2985 r = MSI_EvaluateConditionW(package,cond);
2986 if (r == MSICONDITION_FALSE)
2988 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2991 message = MSI_RecordGetString(row,2);
2992 deformat_string(package,message,&deformated);
2993 MessageBoxW(NULL,deformated,title,MB_OK);
2994 msi_free(deformated);
2997 return ERROR_INSTALL_FAILURE;
3000 return ERROR_SUCCESS;
3003 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3005 static const WCHAR query[] = {
3006 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3007 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3011 TRACE("Checking launch conditions\n");
3013 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3014 if (rc != ERROR_SUCCESS)
3015 return ERROR_SUCCESS;
3017 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3018 msiobj_release(&view->hdr);
3022 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3026 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3028 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3030 static const WCHAR query[] = {
3031 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3032 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3033 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3034 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3035 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3038 LPWSTR deformated, buffer, deformated_name;
3041 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3045 root = MSI_RecordGetInteger(row,2);
3046 key = MSI_RecordGetString(row, 3);
3047 name = MSI_RecordGetString(row, 4);
3048 deformat_string(package, key , &deformated);
3049 deformat_string(package, name, &deformated_name);
3051 len = strlenW(deformated) + 6;
3052 if (deformated_name)
3053 len+=strlenW(deformated_name);
3055 buffer = msi_alloc( len *sizeof(WCHAR));
3057 if (deformated_name)
3058 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3060 sprintfW(buffer,fmt,root,deformated);
3062 msi_free(deformated);
3063 msi_free(deformated_name);
3064 msiobj_release(&row->hdr);
3068 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3070 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3075 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3078 return strdupW( file->TargetPath );
3083 static HKEY openSharedDLLsKey(void)
3086 static const WCHAR path[] =
3087 {'S','o','f','t','w','a','r','e','\\',
3088 'M','i','c','r','o','s','o','f','t','\\',
3089 'W','i','n','d','o','w','s','\\',
3090 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3091 'S','h','a','r','e','d','D','L','L','s',0};
3093 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3097 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3102 DWORD sz = sizeof(count);
3105 hkey = openSharedDLLsKey();
3106 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3107 if (rc != ERROR_SUCCESS)
3113 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3117 hkey = openSharedDLLsKey();
3119 msi_reg_set_val_dword( hkey, path, count );
3121 RegDeleteValueW(hkey,path);
3126 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3128 MSIFEATURE *feature;
3132 /* only refcount DLLs */
3133 if (comp->KeyPath == NULL ||
3135 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3136 comp->Attributes & msidbComponentAttributesODBCDataSource)
3140 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3141 write = (count > 0);
3143 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3147 /* increment counts */
3148 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3152 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3155 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3157 if ( cl->component == comp )
3162 /* decrement counts */
3163 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3167 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3170 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3172 if ( cl->component == comp )
3177 /* ref count all the files in the component */
3182 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3184 if (file->Component == comp)
3185 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3189 /* add a count for permanent */
3190 if (comp->Attributes & msidbComponentAttributesPermanent)
3193 comp->RefCount = count;
3196 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3199 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3203 const WCHAR prefixW[] = {'<','\\',0};
3204 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3205 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3209 strcpyW( keypath, prefixW );
3210 strcatW( keypath, comp->assembly->display_name );
3214 return resolve_keypath( package, comp );
3217 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3219 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3226 squash_guid(package->ProductCode,squished_pc);
3227 msi_set_sourcedir_props(package, FALSE);
3229 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3232 INSTALLSTATE action;
3234 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3235 if (!comp->ComponentId)
3238 squash_guid( comp->ComponentId, squished_cc );
3239 msi_free( comp->FullKeypath );
3240 comp->FullKeypath = build_full_keypath( package, comp );
3242 ACTION_RefCountComponent( package, comp );
3244 if (package->need_rollback) action = comp->Installed;
3245 else action = comp->ActionRequest;
3247 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3248 debugstr_w(comp->Component), debugstr_w(squished_cc),
3249 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3251 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3253 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3254 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3256 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3258 if (rc != ERROR_SUCCESS)
3261 if (comp->Attributes & msidbComponentAttributesPermanent)
3263 static const WCHAR szPermKey[] =
3264 { '0','0','0','0','0','0','0','0','0','0','0','0',
3265 '0','0','0','0','0','0','0','0','0','0','0','0',
3266 '0','0','0','0','0','0','0','0',0 };
3268 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3270 if (action == INSTALLSTATE_LOCAL)
3271 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3277 WCHAR source[MAX_PATH];
3278 WCHAR base[MAX_PATH];
3281 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3282 static const WCHAR query[] = {
3283 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3284 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3285 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3286 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3287 '`','D','i','s','k','I','d','`',0};
3289 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3292 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3293 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3294 ptr2 = strrchrW(source, '\\') + 1;
3295 msiobj_release(&row->hdr);
3297 lstrcpyW(base, package->PackagePath);
3298 ptr = strrchrW(base, '\\');
3301 sourcepath = msi_resolve_file_source(package, file);
3302 ptr = sourcepath + lstrlenW(base);
3303 lstrcpyW(ptr2, ptr);
3304 msi_free(sourcepath);
3306 msi_reg_set_val_str(hkey, squished_pc, source);
3310 else if (action == INSTALLSTATE_ABSENT)
3312 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3313 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3315 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3319 uirow = MSI_CreateRecord(3);
3320 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3321 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3322 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3323 msi_ui_actiondata( package, szProcessComponents, uirow );
3324 msiobj_release( &uirow->hdr );
3326 return ERROR_SUCCESS;
3337 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3338 LPWSTR lpszName, LONG_PTR lParam)
3341 typelib_struct *tl_struct = (typelib_struct*) lParam;
3342 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3346 if (!IS_INTRESOURCE(lpszName))
3348 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3352 sz = strlenW(tl_struct->source)+4;
3353 sz *= sizeof(WCHAR);
3355 if ((INT_PTR)lpszName == 1)
3356 tl_struct->path = strdupW(tl_struct->source);
3359 tl_struct->path = msi_alloc(sz);
3360 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3363 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3364 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3367 msi_free(tl_struct->path);
3368 tl_struct->path = NULL;
3373 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3374 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3376 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3380 msi_free(tl_struct->path);
3381 tl_struct->path = NULL;
3383 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3384 ITypeLib_Release(tl_struct->ptLib);
3389 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3391 MSIPACKAGE* package = param;
3395 typelib_struct tl_struct;
3400 component = MSI_RecordGetString(row,3);
3401 comp = msi_get_loaded_component(package,component);
3403 return ERROR_SUCCESS;
3405 comp->Action = msi_get_component_action( package, comp );
3406 if (comp->Action != INSTALLSTATE_LOCAL)
3408 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3409 return ERROR_SUCCESS;
3412 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3414 TRACE("component has no key path\n");
3415 return ERROR_SUCCESS;
3417 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3419 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3423 guid = MSI_RecordGetString(row,1);
3424 CLSIDFromString( guid, &tl_struct.clsid);
3425 tl_struct.source = strdupW( file->TargetPath );
3426 tl_struct.path = NULL;
3428 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3429 (LONG_PTR)&tl_struct);
3433 LPCWSTR helpid, help_path = NULL;
3436 helpid = MSI_RecordGetString(row,6);
3438 if (helpid) help_path = msi_get_target_folder( package, helpid );
3439 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3442 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3444 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3446 ITypeLib_Release(tl_struct.ptLib);
3447 msi_free(tl_struct.path);
3449 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3451 FreeLibrary(module);
3452 msi_free(tl_struct.source);
3456 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3459 ERR("Failed to load type library: %08x\n", hr);
3460 return ERROR_INSTALL_FAILURE;
3463 ITypeLib_Release(tlib);
3466 return ERROR_SUCCESS;
3469 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3471 static const WCHAR query[] = {
3472 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3473 '`','T','y','p','e','L','i','b','`',0};
3477 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3478 if (rc != ERROR_SUCCESS)
3479 return ERROR_SUCCESS;
3481 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3482 msiobj_release(&view->hdr);
3486 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3488 MSIPACKAGE *package = param;
3489 LPCWSTR component, guid;
3497 component = MSI_RecordGetString( row, 3 );
3498 comp = msi_get_loaded_component( package, component );
3500 return ERROR_SUCCESS;
3502 comp->Action = msi_get_component_action( package, comp );
3503 if (comp->Action != INSTALLSTATE_ABSENT)
3505 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3506 return ERROR_SUCCESS;
3508 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3510 guid = MSI_RecordGetString( row, 1 );
3511 CLSIDFromString( guid, &libid );
3512 version = MSI_RecordGetInteger( row, 4 );
3513 language = MSI_RecordGetInteger( row, 2 );
3516 syskind = SYS_WIN64;
3518 syskind = SYS_WIN32;
3521 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3524 WARN("Failed to unregister typelib: %08x\n", hr);
3527 return ERROR_SUCCESS;
3530 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3532 static const WCHAR query[] = {
3533 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3534 '`','T','y','p','e','L','i','b','`',0};
3538 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3539 if (rc != ERROR_SUCCESS)
3540 return ERROR_SUCCESS;
3542 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3543 msiobj_release( &view->hdr );
3547 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3549 static const WCHAR szlnk[] = {'.','l','n','k',0};
3550 LPCWSTR directory, extension, link_folder;
3551 LPWSTR link_file, filename;
3553 directory = MSI_RecordGetString( row, 2 );
3554 link_folder = msi_get_target_folder( package, directory );
3557 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3560 /* may be needed because of a bug somewhere else */
3561 msi_create_full_path( link_folder );
3563 filename = msi_dup_record_field( row, 3 );
3564 msi_reduce_to_long_filename( filename );
3566 extension = strchrW( filename, '.' );
3567 if (!extension || strcmpiW( extension, szlnk ))
3569 int len = strlenW( filename );
3570 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3571 memcpy( filename + len, szlnk, sizeof(szlnk) );
3573 link_file = msi_build_directory_name( 2, link_folder, filename );
3574 msi_free( filename );
3579 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3581 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3582 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3583 WCHAR *folder, *dest, *path;
3585 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3586 folder = msi_dup_property( package->db, szWindowsFolder );
3589 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3590 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3591 msi_free( appdata );
3593 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3594 msi_create_full_path( dest );
3595 path = msi_build_directory_name( 2, dest, icon_name );
3601 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3603 MSIPACKAGE *package = param;
3604 LPWSTR link_file, deformated, path;
3605 LPCWSTR component, target;
3607 IShellLinkW *sl = NULL;
3608 IPersistFile *pf = NULL;
3611 component = MSI_RecordGetString(row, 4);
3612 comp = msi_get_loaded_component(package, component);
3614 return ERROR_SUCCESS;
3616 comp->Action = msi_get_component_action( package, comp );
3617 if (comp->Action != INSTALLSTATE_LOCAL)
3619 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3620 return ERROR_SUCCESS;
3622 msi_ui_actiondata( package, szCreateShortcuts, row );
3624 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3625 &IID_IShellLinkW, (LPVOID *) &sl );
3629 ERR("CLSID_ShellLink not available\n");
3633 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3636 ERR("QueryInterface(IID_IPersistFile) failed\n");
3640 target = MSI_RecordGetString(row, 5);
3641 if (strchrW(target, '['))
3643 deformat_string( package, target, &path );
3644 TRACE("target path is %s\n", debugstr_w(path));
3645 IShellLinkW_SetPath( sl, path );
3650 FIXME("poorly handled shortcut format, advertised shortcut\n");
3651 IShellLinkW_SetPath(sl,comp->FullKeypath);
3654 if (!MSI_RecordIsNull(row,6))
3656 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3657 deformat_string(package, arguments, &deformated);
3658 IShellLinkW_SetArguments(sl,deformated);
3659 msi_free(deformated);
3662 if (!MSI_RecordIsNull(row,7))
3664 LPCWSTR description = MSI_RecordGetString(row, 7);
3665 IShellLinkW_SetDescription(sl, description);
3668 if (!MSI_RecordIsNull(row,8))
3669 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3671 if (!MSI_RecordIsNull(row,9))
3674 LPCWSTR icon = MSI_RecordGetString(row, 9);
3676 path = msi_build_icon_path(package, icon);
3677 index = MSI_RecordGetInteger(row,10);
3679 /* no value means 0 */
3680 if (index == MSI_NULL_INTEGER)
3683 IShellLinkW_SetIconLocation(sl, path, index);
3687 if (!MSI_RecordIsNull(row,11))
3688 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3690 if (!MSI_RecordIsNull(row,12))
3692 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3693 full_path = msi_get_target_folder( package, wkdir );
3694 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3696 link_file = get_link_file(package, row);
3698 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3699 IPersistFile_Save(pf, link_file, FALSE);
3700 msi_free(link_file);
3704 IPersistFile_Release( pf );
3706 IShellLinkW_Release( sl );
3708 return ERROR_SUCCESS;
3711 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3713 static const WCHAR query[] = {
3714 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3715 '`','S','h','o','r','t','c','u','t','`',0};
3720 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3721 if (rc != ERROR_SUCCESS)
3722 return ERROR_SUCCESS;
3724 res = CoInitialize( NULL );
3726 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3727 msiobj_release(&view->hdr);
3729 if (SUCCEEDED(res)) CoUninitialize();
3733 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3735 MSIPACKAGE *package = param;
3740 component = MSI_RecordGetString( row, 4 );
3741 comp = msi_get_loaded_component( package, component );
3743 return ERROR_SUCCESS;
3745 comp->Action = msi_get_component_action( package, comp );
3746 if (comp->Action != INSTALLSTATE_ABSENT)
3748 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3749 return ERROR_SUCCESS;
3751 msi_ui_actiondata( package, szRemoveShortcuts, row );
3753 link_file = get_link_file( package, row );
3755 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3756 if (!DeleteFileW( link_file ))
3758 WARN("Failed to remove shortcut file %u\n", GetLastError());
3760 msi_free( link_file );
3762 return ERROR_SUCCESS;
3765 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3767 static const WCHAR query[] = {
3768 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3769 '`','S','h','o','r','t','c','u','t','`',0};
3773 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3774 if (rc != ERROR_SUCCESS)
3775 return ERROR_SUCCESS;
3777 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3778 msiobj_release( &view->hdr );
3782 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3784 MSIPACKAGE* package = param;
3792 FileName = MSI_RecordGetString(row,1);
3795 ERR("Unable to get FileName\n");
3796 return ERROR_SUCCESS;
3799 FilePath = msi_build_icon_path(package, FileName);
3801 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3803 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3804 FILE_ATTRIBUTE_NORMAL, NULL);
3806 if (the_file == INVALID_HANDLE_VALUE)
3808 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3810 return ERROR_SUCCESS;
3817 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3818 if (rc != ERROR_SUCCESS)
3820 ERR("Failed to get stream\n");
3821 CloseHandle(the_file);
3822 DeleteFileW(FilePath);
3825 WriteFile(the_file,buffer,sz,&write,NULL);
3826 } while (sz == 1024);
3829 CloseHandle(the_file);
3831 return ERROR_SUCCESS;
3834 static UINT msi_publish_icons(MSIPACKAGE *package)
3836 static const WCHAR query[]= {
3837 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3838 '`','I','c','o','n','`',0};
3842 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3843 if (r == ERROR_SUCCESS)
3845 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3846 msiobj_release(&view->hdr);
3847 if (r != ERROR_SUCCESS)
3850 return ERROR_SUCCESS;
3853 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3859 MSISOURCELISTINFO *info;
3861 r = RegCreateKeyW(hkey, szSourceList, &source);
3862 if (r != ERROR_SUCCESS)
3865 RegCloseKey(source);
3867 buffer = strrchrW(package->PackagePath, '\\') + 1;
3868 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3869 package->Context, MSICODE_PRODUCT,
3870 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3871 if (r != ERROR_SUCCESS)
3874 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3875 package->Context, MSICODE_PRODUCT,
3876 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3877 if (r != ERROR_SUCCESS)
3880 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3881 package->Context, MSICODE_PRODUCT,
3882 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3883 if (r != ERROR_SUCCESS)
3886 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3888 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3889 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3890 info->options, info->value);
3892 MsiSourceListSetInfoW(package->ProductCode, NULL,
3893 info->context, info->options,
3894 info->property, info->value);
3897 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3899 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3900 disk->context, disk->options,
3901 disk->disk_id, disk->volume_label, disk->disk_prompt);
3904 return ERROR_SUCCESS;
3907 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3909 MSIHANDLE hdb, suminfo;
3910 WCHAR guids[MAX_PATH];
3911 WCHAR packcode[SQUISH_GUID_SIZE];
3918 static const WCHAR szARPProductIcon[] =
3919 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3920 static const WCHAR szAssignment[] =
3921 {'A','s','s','i','g','n','m','e','n','t',0};
3922 static const WCHAR szAdvertiseFlags[] =
3923 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3924 static const WCHAR szClients[] =
3925 {'C','l','i','e','n','t','s',0};
3926 static const WCHAR szColon[] = {':',0};
3928 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3929 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3932 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3933 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3936 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3938 buffer = msi_dup_property(package->db, szARPProductIcon);
3941 LPWSTR path = msi_build_icon_path(package, buffer);
3942 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3947 buffer = msi_dup_property(package->db, szProductVersion);
3950 DWORD verdword = msi_version_str_to_dword(buffer);
3951 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3955 msi_reg_set_val_dword(hkey, szAssignment, 0);
3956 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3957 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3958 msi_reg_set_val_str(hkey, szClients, szColon);
3960 hdb = alloc_msihandle(&package->db->hdr);
3962 return ERROR_NOT_ENOUGH_MEMORY;
3964 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3965 MsiCloseHandle(hdb);
3966 if (r != ERROR_SUCCESS)
3970 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3971 NULL, guids, &size);
3972 if (r != ERROR_SUCCESS)
3975 ptr = strchrW(guids, ';');
3977 squash_guid(guids, packcode);
3978 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3981 MsiCloseHandle(suminfo);
3982 return ERROR_SUCCESS;
3985 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3990 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3992 upgrade = msi_dup_property(package->db, szUpgradeCode);
3994 return ERROR_SUCCESS;
3996 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3997 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3999 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4001 if (r != ERROR_SUCCESS)
4003 WARN("failed to open upgrade code key\n");
4005 return ERROR_SUCCESS;
4007 squash_guid(package->ProductCode, squashed_pc);
4008 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4011 return ERROR_SUCCESS;
4014 static BOOL msi_check_publish(MSIPACKAGE *package)
4016 MSIFEATURE *feature;
4018 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4020 feature->Action = msi_get_feature_action( package, feature );
4021 if (feature->Action == INSTALLSTATE_LOCAL)
4028 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4030 MSIFEATURE *feature;
4032 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4034 feature->Action = msi_get_feature_action( package, feature );
4035 if (feature->Action != INSTALLSTATE_ABSENT)
4042 static UINT msi_publish_patches( MSIPACKAGE *package )
4044 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4045 WCHAR patch_squashed[GUID_SIZE];
4046 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4048 MSIPATCHINFO *patch;
4050 WCHAR *p, *all_patches = NULL;
4053 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4054 if (r != ERROR_SUCCESS)
4055 return ERROR_FUNCTION_FAILED;
4057 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4058 if (res != ERROR_SUCCESS)
4060 r = ERROR_FUNCTION_FAILED;
4064 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4065 if (r != ERROR_SUCCESS)
4068 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4070 squash_guid( patch->patchcode, patch_squashed );
4071 len += strlenW( patch_squashed ) + 1;
4074 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4078 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4082 squash_guid( patch->patchcode, p );
4083 p += strlenW( p ) + 1;
4085 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4086 (const BYTE *)patch->transforms,
4087 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4088 if (res != ERROR_SUCCESS)
4091 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4092 if (r != ERROR_SUCCESS)
4095 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4096 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4097 RegCloseKey( patch_key );
4098 if (res != ERROR_SUCCESS)
4101 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4103 res = GetLastError();
4104 ERR("Unable to copy patch package %d\n", res);
4107 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4108 if (res != ERROR_SUCCESS)
4111 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4112 RegCloseKey( patch_key );
4113 if (res != ERROR_SUCCESS)
4117 all_patches[len] = 0;
4118 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4119 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4120 if (res != ERROR_SUCCESS)
4123 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4124 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4125 if (res != ERROR_SUCCESS)
4126 r = ERROR_FUNCTION_FAILED;
4129 RegCloseKey( product_patches_key );
4130 RegCloseKey( patches_key );
4131 RegCloseKey( product_key );
4132 msi_free( all_patches );
4136 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4139 HKEY hukey = NULL, hudkey = NULL;
4142 if (!list_empty(&package->patches))
4144 rc = msi_publish_patches(package);
4145 if (rc != ERROR_SUCCESS)
4149 /* FIXME: also need to publish if the product is in advertise mode */
4150 if (!msi_check_publish(package))
4151 return ERROR_SUCCESS;
4153 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4155 if (rc != ERROR_SUCCESS)
4158 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4159 NULL, &hudkey, TRUE);
4160 if (rc != ERROR_SUCCESS)
4163 rc = msi_publish_upgrade_code(package);
4164 if (rc != ERROR_SUCCESS)
4167 rc = msi_publish_product_properties(package, hukey);
4168 if (rc != ERROR_SUCCESS)
4171 rc = msi_publish_sourcelist(package, hukey);
4172 if (rc != ERROR_SUCCESS)
4175 rc = msi_publish_icons(package);
4178 uirow = MSI_CreateRecord( 1 );
4179 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4180 msi_ui_actiondata( package, szPublishProduct, uirow );
4181 msiobj_release( &uirow->hdr );
4184 RegCloseKey(hudkey);
4188 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4190 WCHAR *filename, *ptr, *folder, *ret;
4191 const WCHAR *dirprop;
4193 filename = msi_dup_record_field( row, 2 );
4194 if (filename && (ptr = strchrW( filename, '|' )))
4199 dirprop = MSI_RecordGetString( row, 3 );
4202 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4203 if (!folder) folder = msi_dup_property( package->db, dirprop );
4206 folder = msi_dup_property( package->db, szWindowsFolder );
4210 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4211 msi_free( filename );
4215 ret = msi_build_directory_name( 2, folder, ptr );
4217 msi_free( filename );
4222 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4224 MSIPACKAGE *package = param;
4225 LPCWSTR component, section, key, value, identifier;
4226 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4231 component = MSI_RecordGetString(row, 8);
4232 comp = msi_get_loaded_component(package,component);
4234 return ERROR_SUCCESS;
4236 comp->Action = msi_get_component_action( package, comp );
4237 if (comp->Action != INSTALLSTATE_LOCAL)
4239 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4240 return ERROR_SUCCESS;
4243 identifier = MSI_RecordGetString(row,1);
4244 section = MSI_RecordGetString(row,4);
4245 key = MSI_RecordGetString(row,5);
4246 value = MSI_RecordGetString(row,6);
4247 action = MSI_RecordGetInteger(row,7);
4249 deformat_string(package,section,&deformated_section);
4250 deformat_string(package,key,&deformated_key);
4251 deformat_string(package,value,&deformated_value);
4253 fullname = get_ini_file_name(package, row);
4257 TRACE("Adding value %s to section %s in %s\n",
4258 debugstr_w(deformated_key), debugstr_w(deformated_section),
4259 debugstr_w(fullname));
4260 WritePrivateProfileStringW(deformated_section, deformated_key,
4261 deformated_value, fullname);
4263 else if (action == 1)
4266 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4267 returned, 10, fullname);
4268 if (returned[0] == 0)
4270 TRACE("Adding value %s to section %s in %s\n",
4271 debugstr_w(deformated_key), debugstr_w(deformated_section),
4272 debugstr_w(fullname));
4274 WritePrivateProfileStringW(deformated_section, deformated_key,
4275 deformated_value, fullname);
4278 else if (action == 3)
4279 FIXME("Append to existing section not yet implemented\n");
4281 uirow = MSI_CreateRecord(4);
4282 MSI_RecordSetStringW(uirow,1,identifier);
4283 MSI_RecordSetStringW(uirow,2,deformated_section);
4284 MSI_RecordSetStringW(uirow,3,deformated_key);
4285 MSI_RecordSetStringW(uirow,4,deformated_value);
4286 msi_ui_actiondata( package, szWriteIniValues, uirow );
4287 msiobj_release( &uirow->hdr );
4290 msi_free(deformated_key);
4291 msi_free(deformated_value);
4292 msi_free(deformated_section);
4293 return ERROR_SUCCESS;
4296 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4298 static const WCHAR query[] = {
4299 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4300 '`','I','n','i','F','i','l','e','`',0};
4304 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4305 if (rc != ERROR_SUCCESS)
4306 return ERROR_SUCCESS;
4308 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4309 msiobj_release(&view->hdr);
4313 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4315 MSIPACKAGE *package = param;
4316 LPCWSTR component, section, key, value, identifier;
4317 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4322 component = MSI_RecordGetString( row, 8 );
4323 comp = msi_get_loaded_component( package, component );
4325 return ERROR_SUCCESS;
4327 comp->Action = msi_get_component_action( package, comp );
4328 if (comp->Action != INSTALLSTATE_ABSENT)
4330 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4331 return ERROR_SUCCESS;
4334 identifier = MSI_RecordGetString( row, 1 );
4335 section = MSI_RecordGetString( row, 4 );
4336 key = MSI_RecordGetString( row, 5 );
4337 value = MSI_RecordGetString( row, 6 );
4338 action = MSI_RecordGetInteger( row, 7 );
4340 deformat_string( package, section, &deformated_section );
4341 deformat_string( package, key, &deformated_key );
4342 deformat_string( package, value, &deformated_value );
4344 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4346 filename = get_ini_file_name( package, row );
4348 TRACE("Removing key %s from section %s in %s\n",
4349 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4351 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4353 WARN("Unable to remove key %u\n", GetLastError());
4355 msi_free( filename );
4358 FIXME("Unsupported action %d\n", action);
4361 uirow = MSI_CreateRecord( 4 );
4362 MSI_RecordSetStringW( uirow, 1, identifier );
4363 MSI_RecordSetStringW( uirow, 2, deformated_section );
4364 MSI_RecordSetStringW( uirow, 3, deformated_key );
4365 MSI_RecordSetStringW( uirow, 4, deformated_value );
4366 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4367 msiobj_release( &uirow->hdr );
4369 msi_free( deformated_key );
4370 msi_free( deformated_value );
4371 msi_free( deformated_section );
4372 return ERROR_SUCCESS;
4375 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4377 MSIPACKAGE *package = param;
4378 LPCWSTR component, section, key, value, identifier;
4379 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4384 component = MSI_RecordGetString( row, 8 );
4385 comp = msi_get_loaded_component( package, component );
4387 return ERROR_SUCCESS;
4389 comp->Action = msi_get_component_action( package, comp );
4390 if (comp->Action != INSTALLSTATE_LOCAL)
4392 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4393 return ERROR_SUCCESS;
4396 identifier = MSI_RecordGetString( row, 1 );
4397 section = MSI_RecordGetString( row, 4 );
4398 key = MSI_RecordGetString( row, 5 );
4399 value = MSI_RecordGetString( row, 6 );
4400 action = MSI_RecordGetInteger( row, 7 );
4402 deformat_string( package, section, &deformated_section );
4403 deformat_string( package, key, &deformated_key );
4404 deformat_string( package, value, &deformated_value );
4406 if (action == msidbIniFileActionRemoveLine)
4408 filename = get_ini_file_name( package, row );
4410 TRACE("Removing key %s from section %s in %s\n",
4411 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4413 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4415 WARN("Unable to remove key %u\n", GetLastError());
4417 msi_free( filename );
4420 FIXME("Unsupported action %d\n", action);
4422 uirow = MSI_CreateRecord( 4 );
4423 MSI_RecordSetStringW( uirow, 1, identifier );
4424 MSI_RecordSetStringW( uirow, 2, deformated_section );
4425 MSI_RecordSetStringW( uirow, 3, deformated_key );
4426 MSI_RecordSetStringW( uirow, 4, deformated_value );
4427 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4428 msiobj_release( &uirow->hdr );
4430 msi_free( deformated_key );
4431 msi_free( deformated_value );
4432 msi_free( deformated_section );
4433 return ERROR_SUCCESS;
4436 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4438 static const WCHAR query[] = {
4439 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4440 '`','I','n','i','F','i','l','e','`',0};
4441 static const WCHAR remove_query[] = {
4442 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4443 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4447 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4448 if (rc == ERROR_SUCCESS)
4450 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4451 msiobj_release( &view->hdr );
4452 if (rc != ERROR_SUCCESS)
4455 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4456 if (rc == ERROR_SUCCESS)
4458 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4459 msiobj_release( &view->hdr );
4460 if (rc != ERROR_SUCCESS)
4463 return ERROR_SUCCESS;
4466 static void register_dll( const WCHAR *dll, BOOL unregister )
4470 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4473 HRESULT (WINAPI *func_ptr)( void );
4474 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4476 func_ptr = (void *)GetProcAddress( hmod, func );
4479 HRESULT hr = func_ptr();
4481 WARN("failed to register dll 0x%08x\n", hr);
4484 WARN("entry point %s not found\n", func);
4485 FreeLibrary( hmod );
4488 WARN("failed to load library %u\n", GetLastError());
4491 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4493 MSIPACKAGE *package = param;
4498 filename = MSI_RecordGetString( row, 1 );
4499 file = msi_get_loaded_file( package, filename );
4502 WARN("unable to find file %s\n", debugstr_w(filename));
4503 return ERROR_SUCCESS;
4505 file->Component->Action = msi_get_component_action( package, file->Component );
4506 if (file->Component->Action != INSTALLSTATE_LOCAL)
4508 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4509 return ERROR_SUCCESS;
4512 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4513 register_dll( file->TargetPath, FALSE );
4515 uirow = MSI_CreateRecord( 2 );
4516 MSI_RecordSetStringW( uirow, 1, file->File );
4517 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4518 msi_ui_actiondata( package, szSelfRegModules, uirow );
4519 msiobj_release( &uirow->hdr );
4521 return ERROR_SUCCESS;
4524 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4526 static const WCHAR query[] = {
4527 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4528 '`','S','e','l','f','R','e','g','`',0};
4532 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4533 if (rc != ERROR_SUCCESS)
4534 return ERROR_SUCCESS;
4536 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4537 msiobj_release(&view->hdr);
4541 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4543 MSIPACKAGE *package = param;
4548 filename = MSI_RecordGetString( row, 1 );
4549 file = msi_get_loaded_file( package, filename );
4552 WARN("unable to find file %s\n", debugstr_w(filename));
4553 return ERROR_SUCCESS;
4555 file->Component->Action = msi_get_component_action( package, file->Component );
4556 if (file->Component->Action != INSTALLSTATE_ABSENT)
4558 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4559 return ERROR_SUCCESS;
4562 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4563 register_dll( file->TargetPath, TRUE );
4565 uirow = MSI_CreateRecord( 2 );
4566 MSI_RecordSetStringW( uirow, 1, file->File );
4567 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4568 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4569 msiobj_release( &uirow->hdr );
4571 return ERROR_SUCCESS;
4574 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4576 static const WCHAR query[] = {
4577 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4578 '`','S','e','l','f','R','e','g','`',0};
4582 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4583 if (rc != ERROR_SUCCESS)
4584 return ERROR_SUCCESS;
4586 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4587 msiobj_release( &view->hdr );
4591 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4593 MSIFEATURE *feature;
4595 HKEY hkey = NULL, userdata = NULL;
4597 if (!msi_check_publish(package))
4598 return ERROR_SUCCESS;
4600 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4602 if (rc != ERROR_SUCCESS)
4605 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4607 if (rc != ERROR_SUCCESS)
4610 /* here the guids are base 85 encoded */
4611 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4617 BOOL absent = FALSE;
4620 if (feature->Action != INSTALLSTATE_LOCAL &&
4621 feature->Action != INSTALLSTATE_SOURCE &&
4622 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4625 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4629 if (feature->Feature_Parent)
4630 size += strlenW( feature->Feature_Parent )+2;
4632 data = msi_alloc(size * sizeof(WCHAR));
4635 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4637 MSICOMPONENT* component = cl->component;
4641 if (component->ComponentId)
4643 TRACE("From %s\n",debugstr_w(component->ComponentId));
4644 CLSIDFromString(component->ComponentId, &clsid);
4645 encode_base85_guid(&clsid,buf);
4646 TRACE("to %s\n",debugstr_w(buf));
4651 if (feature->Feature_Parent)
4653 static const WCHAR sep[] = {'\2',0};
4655 strcatW(data,feature->Feature_Parent);
4658 msi_reg_set_val_str( userdata, feature->Feature, data );
4662 if (feature->Feature_Parent)
4663 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4666 size += sizeof(WCHAR);
4667 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4668 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4672 size += 2*sizeof(WCHAR);
4673 data = msi_alloc(size);
4676 if (feature->Feature_Parent)
4677 strcpyW( &data[1], feature->Feature_Parent );
4678 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4684 uirow = MSI_CreateRecord( 1 );
4685 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4686 msi_ui_actiondata( package, szPublishFeatures, uirow );
4687 msiobj_release( &uirow->hdr );
4688 /* FIXME: call msi_ui_progress? */
4693 RegCloseKey(userdata);
4697 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4703 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4705 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4707 if (r == ERROR_SUCCESS)
4709 RegDeleteValueW(hkey, feature->Feature);
4713 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4715 if (r == ERROR_SUCCESS)
4717 RegDeleteValueW(hkey, feature->Feature);
4721 uirow = MSI_CreateRecord( 1 );
4722 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4723 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4724 msiobj_release( &uirow->hdr );
4726 return ERROR_SUCCESS;
4729 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4731 MSIFEATURE *feature;
4733 if (!msi_check_unpublish(package))
4734 return ERROR_SUCCESS;
4736 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4738 msi_unpublish_feature(package, feature);
4741 return ERROR_SUCCESS;
4744 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4748 WCHAR date[9], *val, *buffer;
4749 const WCHAR *prop, *key;
4751 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4752 static const WCHAR modpath_fmt[] =
4753 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4754 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4755 static const WCHAR szModifyPath[] =
4756 {'M','o','d','i','f','y','P','a','t','h',0};
4757 static const WCHAR szUninstallString[] =
4758 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4759 static const WCHAR szEstimatedSize[] =
4760 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4761 static const WCHAR szDisplayVersion[] =
4762 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4763 static const WCHAR szInstallSource[] =
4764 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4765 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4766 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4767 static const WCHAR szAuthorizedCDFPrefix[] =
4768 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4769 static const WCHAR szARPCONTACT[] =
4770 {'A','R','P','C','O','N','T','A','C','T',0};
4771 static const WCHAR szContact[] =
4772 {'C','o','n','t','a','c','t',0};
4773 static const WCHAR szARPCOMMENTS[] =
4774 {'A','R','P','C','O','M','M','E','N','T','S',0};
4775 static const WCHAR szComments[] =
4776 {'C','o','m','m','e','n','t','s',0};
4777 static const WCHAR szProductName[] =
4778 {'P','r','o','d','u','c','t','N','a','m','e',0};
4779 static const WCHAR szDisplayName[] =
4780 {'D','i','s','p','l','a','y','N','a','m','e',0};
4781 static const WCHAR szARPHELPLINK[] =
4782 {'A','R','P','H','E','L','P','L','I','N','K',0};
4783 static const WCHAR szHelpLink[] =
4784 {'H','e','l','p','L','i','n','k',0};
4785 static const WCHAR szARPHELPTELEPHONE[] =
4786 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4787 static const WCHAR szHelpTelephone[] =
4788 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4789 static const WCHAR szARPINSTALLLOCATION[] =
4790 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4791 static const WCHAR szInstallLocation[] =
4792 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4793 static const WCHAR szManufacturer[] =
4794 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4795 static const WCHAR szPublisher[] =
4796 {'P','u','b','l','i','s','h','e','r',0};
4797 static const WCHAR szARPREADME[] =
4798 {'A','R','P','R','E','A','D','M','E',0};
4799 static const WCHAR szReadme[] =
4800 {'R','e','a','d','M','e',0};
4801 static const WCHAR szARPSIZE[] =
4802 {'A','R','P','S','I','Z','E',0};
4803 static const WCHAR szSize[] =
4804 {'S','i','z','e',0};
4805 static const WCHAR szARPURLINFOABOUT[] =
4806 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4807 static const WCHAR szURLInfoAbout[] =
4808 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4809 static const WCHAR szARPURLUPDATEINFO[] =
4810 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4811 static const WCHAR szURLUpdateInfo[] =
4812 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4813 static const WCHAR szARPSYSTEMCOMPONENT[] =
4814 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4815 static const WCHAR szSystemComponent[] =
4816 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4818 static const WCHAR *propval[] = {
4819 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4820 szARPCONTACT, szContact,
4821 szARPCOMMENTS, szComments,
4822 szProductName, szDisplayName,
4823 szARPHELPLINK, szHelpLink,
4824 szARPHELPTELEPHONE, szHelpTelephone,
4825 szARPINSTALLLOCATION, szInstallLocation,
4826 szSourceDir, szInstallSource,
4827 szManufacturer, szPublisher,
4828 szARPREADME, szReadme,
4830 szARPURLINFOABOUT, szURLInfoAbout,
4831 szARPURLUPDATEINFO, szURLUpdateInfo,
4834 const WCHAR **p = propval;
4840 val = msi_dup_property(package->db, prop);
4841 msi_reg_set_val_str(hkey, key, val);
4845 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4846 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4848 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4850 size = deformat_string(package, modpath_fmt, &buffer);
4851 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4852 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4855 /* FIXME: Write real Estimated Size when we have it */
4856 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4858 GetLocalTime(&systime);
4859 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4860 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4862 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4863 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4865 buffer = msi_dup_property(package->db, szProductVersion);
4866 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4869 DWORD verdword = msi_version_str_to_dword(buffer);
4871 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4872 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4873 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4877 return ERROR_SUCCESS;
4880 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4882 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4884 LPWSTR upgrade_code;
4885 HKEY hkey, props, upgrade_key;
4888 /* FIXME: also need to publish if the product is in advertise mode */
4889 if (!msi_check_publish(package))
4890 return ERROR_SUCCESS;
4892 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4893 if (rc != ERROR_SUCCESS)
4896 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4897 if (rc != ERROR_SUCCESS)
4900 rc = msi_publish_install_properties(package, hkey);
4901 if (rc != ERROR_SUCCESS)
4904 rc = msi_publish_install_properties(package, props);
4905 if (rc != ERROR_SUCCESS)
4908 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4911 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4912 if (rc == ERROR_SUCCESS)
4914 squash_guid( package->ProductCode, squashed_pc );
4915 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4916 RegCloseKey( upgrade_key );
4918 msi_free( upgrade_code );
4920 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4921 package->delete_on_close = FALSE;
4924 uirow = MSI_CreateRecord( 1 );
4925 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4926 msi_ui_actiondata( package, szRegisterProduct, uirow );
4927 msiobj_release( &uirow->hdr );
4930 return ERROR_SUCCESS;
4933 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4935 return execute_script(package, SCRIPT_INSTALL);
4938 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4940 MSIPACKAGE *package = param;
4941 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4942 WCHAR *p, *icon_path;
4944 if (!icon) return ERROR_SUCCESS;
4945 if ((icon_path = msi_build_icon_path( package, icon )))
4947 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4948 DeleteFileW( icon_path );
4949 if ((p = strrchrW( icon_path, '\\' )))
4952 RemoveDirectoryW( icon_path );
4954 msi_free( icon_path );
4956 return ERROR_SUCCESS;
4959 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4961 static const WCHAR query[]= {
4962 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4966 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4967 if (r == ERROR_SUCCESS)
4969 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4970 msiobj_release( &view->hdr );
4971 if (r != ERROR_SUCCESS)
4974 return ERROR_SUCCESS;
4977 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4979 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4980 WCHAR *upgrade, **features;
4981 BOOL full_uninstall = TRUE;
4982 MSIFEATURE *feature;
4983 MSIPATCHINFO *patch;
4986 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4988 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4990 features = msi_split_string( remove, ',' );
4991 for (i = 0; features && features[i]; i++)
4993 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4997 if (!full_uninstall)
4998 return ERROR_SUCCESS;
5000 MSIREG_DeleteProductKey(package->ProductCode);
5001 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5002 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5004 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5005 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5006 MSIREG_DeleteUserProductKey(package->ProductCode);
5007 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5009 upgrade = msi_dup_property(package->db, szUpgradeCode);
5012 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5013 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5017 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5019 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5020 if (!strcmpW( package->ProductCode, patch->products ))
5022 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5023 patch->delete_on_close = TRUE;
5025 /* FIXME: remove local patch package if this is the last product */
5027 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5028 package->delete_on_close = TRUE;
5030 msi_unpublish_icons( package );
5031 return ERROR_SUCCESS;
5034 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5039 /* turn off scheduling */
5040 package->script->CurrentlyScripting= FALSE;
5042 /* first do the same as an InstallExecute */
5043 rc = ACTION_InstallExecute(package);
5044 if (rc != ERROR_SUCCESS)
5047 /* then handle commit actions */
5048 rc = execute_script(package, SCRIPT_COMMIT);
5049 if (rc != ERROR_SUCCESS)
5052 remove = msi_dup_property(package->db, szRemove);
5053 rc = msi_unpublish_product(package, remove);
5058 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5060 static const WCHAR RunOnce[] = {
5061 'S','o','f','t','w','a','r','e','\\',
5062 'M','i','c','r','o','s','o','f','t','\\',
5063 'W','i','n','d','o','w','s','\\',
5064 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5065 'R','u','n','O','n','c','e',0};
5066 static const WCHAR InstallRunOnce[] = {
5067 'S','o','f','t','w','a','r','e','\\',
5068 'M','i','c','r','o','s','o','f','t','\\',
5069 'W','i','n','d','o','w','s','\\',
5070 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5071 'I','n','s','t','a','l','l','e','r','\\',
5072 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5074 static const WCHAR msiexec_fmt[] = {
5076 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5077 '\"','%','s','\"',0};
5078 static const WCHAR install_fmt[] = {
5079 '/','I',' ','\"','%','s','\"',' ',
5080 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5081 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5082 WCHAR buffer[256], sysdir[MAX_PATH];
5084 WCHAR squished_pc[100];
5086 squash_guid(package->ProductCode,squished_pc);
5088 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5089 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5090 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5093 msi_reg_set_val_str( hkey, squished_pc, buffer );
5096 TRACE("Reboot command %s\n",debugstr_w(buffer));
5098 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5099 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5101 msi_reg_set_val_str( hkey, squished_pc, buffer );
5104 return ERROR_INSTALL_SUSPEND;
5107 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5109 static const WCHAR query[] =
5110 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5111 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5112 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5113 MSIRECORD *rec, *row;
5119 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5121 rec = MSI_CreateRecord( count + 2 );
5122 str = MSI_RecordGetString( row, 1 );
5123 MSI_RecordSetStringW( rec, 0, str );
5124 msiobj_release( &row->hdr );
5125 MSI_RecordSetInteger( rec, 1, error );
5127 va_start( va, count );
5128 for (i = 0; i < count; i++)
5130 str = va_arg( va, const WCHAR *);
5131 MSI_RecordSetStringW( rec, i + 2, str );
5135 MSI_FormatRecordW( package, rec, NULL, &size );
5137 data = msi_alloc( size * sizeof(WCHAR) );
5138 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5140 msiobj_release( &rec->hdr );
5144 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5150 * We are currently doing what should be done here in the top level Install
5151 * however for Administrative and uninstalls this step will be needed
5153 if (!package->PackagePath)
5154 return ERROR_SUCCESS;
5156 msi_set_sourcedir_props(package, TRUE);
5158 attrib = GetFileAttributesW(package->db->path);
5159 if (attrib == INVALID_FILE_ATTRIBUTES)
5164 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5165 package->Context, MSICODE_PRODUCT,
5166 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5167 if (rc == ERROR_MORE_DATA)
5169 prompt = msi_alloc(size * sizeof(WCHAR));
5170 MsiSourceListGetInfoW(package->ProductCode, NULL,
5171 package->Context, MSICODE_PRODUCT,
5172 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5175 prompt = strdupW(package->db->path);
5177 msg = msi_build_error_string(package, 1302, 1, prompt);
5179 while(attrib == INVALID_FILE_ATTRIBUTES)
5181 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5185 return ERROR_INSTALL_USEREXIT;
5187 attrib = GetFileAttributesW(package->db->path);
5193 return ERROR_SUCCESS;
5198 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5201 LPWSTR buffer, productid = NULL;
5202 UINT i, rc = ERROR_SUCCESS;
5205 static const WCHAR szPropKeys[][80] =
5207 {'P','r','o','d','u','c','t','I','D',0},
5208 {'U','S','E','R','N','A','M','E',0},
5209 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5213 static const WCHAR szRegKeys[][80] =
5215 {'P','r','o','d','u','c','t','I','D',0},
5216 {'R','e','g','O','w','n','e','r',0},
5217 {'R','e','g','C','o','m','p','a','n','y',0},
5221 if (msi_check_unpublish(package))
5223 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5227 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5231 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5233 if (rc != ERROR_SUCCESS)
5236 for( i = 0; szPropKeys[i][0]; i++ )
5238 buffer = msi_dup_property( package->db, szPropKeys[i] );
5239 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5244 uirow = MSI_CreateRecord( 1 );
5245 MSI_RecordSetStringW( uirow, 1, productid );
5246 msi_ui_actiondata( package, szRegisterUser, uirow );
5247 msiobj_release( &uirow->hdr );
5249 msi_free(productid);
5255 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5259 package->script->InWhatSequence |= SEQUENCE_EXEC;
5260 rc = ACTION_ProcessExecSequence(package,FALSE);
5264 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5266 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5267 WCHAR productid_85[21], component_85[21], *ret;
5271 /* > is used if there is a component GUID and < if not. */
5273 productid_85[0] = 0;
5274 component_85[0] = 0;
5275 CLSIDFromString( package->ProductCode, &clsid );
5277 encode_base85_guid( &clsid, productid_85 );
5280 CLSIDFromString( component->ComponentId, &clsid );
5281 encode_base85_guid( &clsid, component_85 );
5284 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5285 debugstr_w(component_85));
5287 sz = 20 + strlenW( feature ) + 20 + 3;
5288 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5289 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5293 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5295 MSIPACKAGE *package = param;
5296 LPCWSTR compgroupid, component, feature, qualifier, text;
5297 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5306 feature = MSI_RecordGetString(rec, 5);
5307 feat = msi_get_loaded_feature(package, feature);
5309 return ERROR_SUCCESS;
5311 feat->Action = msi_get_feature_action( package, feat );
5312 if (feat->Action != INSTALLSTATE_LOCAL &&
5313 feat->Action != INSTALLSTATE_SOURCE &&
5314 feat->Action != INSTALLSTATE_ADVERTISED)
5316 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5317 return ERROR_SUCCESS;
5320 component = MSI_RecordGetString(rec, 3);
5321 comp = msi_get_loaded_component(package, component);
5323 return ERROR_SUCCESS;
5325 compgroupid = MSI_RecordGetString(rec,1);
5326 qualifier = MSI_RecordGetString(rec,2);
5328 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5329 if (rc != ERROR_SUCCESS)
5332 advertise = msi_create_component_advertise_string( package, comp, feature );
5333 text = MSI_RecordGetString( rec, 4 );
5336 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5337 strcpyW( p, advertise );
5339 msi_free( advertise );
5342 existing = msi_reg_get_val_str( hkey, qualifier );
5344 sz = strlenW( advertise ) + 1;
5347 for (p = existing; *p; p += len)
5349 len = strlenW( p ) + 1;
5350 if (strcmpW( advertise, p )) sz += len;
5353 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5355 rc = ERROR_OUTOFMEMORY;
5361 for (p = existing; *p; p += len)
5363 len = strlenW( p ) + 1;
5364 if (strcmpW( advertise, p ))
5366 memcpy( q, p, len * sizeof(WCHAR) );
5371 strcpyW( q, advertise );
5372 q[strlenW( q ) + 1] = 0;
5374 msi_reg_set_val_multi_str( hkey, qualifier, output );
5379 msi_free( advertise );
5380 msi_free( existing );
5383 uirow = MSI_CreateRecord( 2 );
5384 MSI_RecordSetStringW( uirow, 1, compgroupid );
5385 MSI_RecordSetStringW( uirow, 2, qualifier);
5386 msi_ui_actiondata( package, szPublishComponents, uirow );
5387 msiobj_release( &uirow->hdr );
5388 /* FIXME: call ui_progress? */
5394 * At present I am ignorning the advertised components part of this and only
5395 * focusing on the qualified component sets
5397 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5399 static const WCHAR query[] = {
5400 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5401 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5405 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5406 if (rc != ERROR_SUCCESS)
5407 return ERROR_SUCCESS;
5409 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5410 msiobj_release(&view->hdr);
5414 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5416 static const WCHAR szInstallerComponents[] = {
5417 'S','o','f','t','w','a','r','e','\\',
5418 'M','i','c','r','o','s','o','f','t','\\',
5419 'I','n','s','t','a','l','l','e','r','\\',
5420 'C','o','m','p','o','n','e','n','t','s','\\',0};
5422 MSIPACKAGE *package = param;
5423 LPCWSTR compgroupid, component, feature, qualifier;
5427 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5430 feature = MSI_RecordGetString( rec, 5 );
5431 feat = msi_get_loaded_feature( package, feature );
5433 return ERROR_SUCCESS;
5435 feat->Action = msi_get_feature_action( package, feat );
5436 if (feat->Action != INSTALLSTATE_ABSENT)
5438 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5439 return ERROR_SUCCESS;
5442 component = MSI_RecordGetString( rec, 3 );
5443 comp = msi_get_loaded_component( package, component );
5445 return ERROR_SUCCESS;
5447 compgroupid = MSI_RecordGetString( rec, 1 );
5448 qualifier = MSI_RecordGetString( rec, 2 );
5450 squash_guid( compgroupid, squashed );
5451 strcpyW( keypath, szInstallerComponents );
5452 strcatW( keypath, squashed );
5454 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5455 if (res != ERROR_SUCCESS)
5457 WARN("Unable to delete component key %d\n", res);
5460 uirow = MSI_CreateRecord( 2 );
5461 MSI_RecordSetStringW( uirow, 1, compgroupid );
5462 MSI_RecordSetStringW( uirow, 2, qualifier );
5463 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5464 msiobj_release( &uirow->hdr );
5466 return ERROR_SUCCESS;
5469 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5471 static const WCHAR query[] = {
5472 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5473 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5477 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5478 if (rc != ERROR_SUCCESS)
5479 return ERROR_SUCCESS;
5481 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5482 msiobj_release( &view->hdr );
5486 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5488 static const WCHAR query[] =
5489 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5490 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5491 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5492 MSIPACKAGE *package = param;
5493 MSICOMPONENT *component;
5496 SC_HANDLE hscm = NULL, service = NULL;
5498 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5499 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5500 DWORD serv_type, start_type, err_control;
5501 SERVICE_DESCRIPTIONW sd = {NULL};
5503 comp = MSI_RecordGetString( rec, 12 );
5504 component = msi_get_loaded_component( package, comp );
5507 WARN("service component not found\n");
5510 component->Action = msi_get_component_action( package, component );
5511 if (component->Action != INSTALLSTATE_LOCAL)
5513 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5516 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5519 ERR("Failed to open the SC Manager!\n");
5523 start_type = MSI_RecordGetInteger(rec, 5);
5524 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5527 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5528 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5529 serv_type = MSI_RecordGetInteger(rec, 4);
5530 err_control = MSI_RecordGetInteger(rec, 6);
5531 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5532 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5533 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5534 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5535 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5536 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5538 /* fetch the service path */
5539 row = MSI_QueryGetRecord(package->db, query, comp);
5542 ERR("Query failed\n");
5545 key = MSI_RecordGetString(row, 6);
5546 file = msi_get_loaded_file(package, key);
5547 msiobj_release(&row->hdr);
5550 ERR("Failed to load the service file\n");
5554 if (!args || !args[0]) image_path = file->TargetPath;
5557 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5558 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5559 return ERROR_OUTOFMEMORY;
5561 strcpyW(image_path, file->TargetPath);
5562 strcatW(image_path, szSpace);
5563 strcatW(image_path, args);
5565 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5566 start_type, err_control, image_path, load_order,
5567 NULL, depends, serv_name, pass);
5571 if (GetLastError() != ERROR_SERVICE_EXISTS)
5572 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5574 else if (sd.lpDescription)
5576 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5577 WARN("failed to set service description %u\n", GetLastError());
5580 if (image_path != file->TargetPath) msi_free(image_path);
5582 CloseServiceHandle(service);
5583 CloseServiceHandle(hscm);
5586 msi_free(sd.lpDescription);
5587 msi_free(load_order);
5588 msi_free(serv_name);
5593 return ERROR_SUCCESS;
5596 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5598 static const WCHAR query[] = {
5599 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5600 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5604 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5605 if (rc != ERROR_SUCCESS)
5606 return ERROR_SUCCESS;
5608 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5609 msiobj_release(&view->hdr);
5613 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5614 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5616 LPCWSTR *vector, *temp_vector;
5620 static const WCHAR separator[] = {'[','~',']',0};
5623 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5628 vector = msi_alloc(sizeof(LPWSTR));
5636 vector[*numargs - 1] = p;
5638 if ((q = strstrW(p, separator)))
5642 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5648 vector = temp_vector;
5657 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5659 MSIPACKAGE *package = param;
5662 SC_HANDLE scm = NULL, service = NULL;
5663 LPCWSTR component, *vector = NULL;
5664 LPWSTR name, args, display_name = NULL;
5665 DWORD event, numargs, len, wait, dummy;
5666 UINT r = ERROR_FUNCTION_FAILED;
5667 SERVICE_STATUS_PROCESS status;
5668 ULONGLONG start_time;
5670 component = MSI_RecordGetString(rec, 6);
5671 comp = msi_get_loaded_component(package, component);
5673 return ERROR_SUCCESS;
5675 comp->Action = msi_get_component_action( package, comp );
5676 if (comp->Action != INSTALLSTATE_LOCAL)
5678 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5679 return ERROR_SUCCESS;
5682 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5683 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5684 event = MSI_RecordGetInteger(rec, 3);
5685 wait = MSI_RecordGetInteger(rec, 5);
5687 if (!(event & msidbServiceControlEventStart))
5693 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5696 ERR("Failed to open the service control manager\n");
5701 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5702 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5704 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5705 GetServiceDisplayNameW( scm, name, display_name, &len );
5708 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5711 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5715 vector = msi_service_args_to_vector(args, &numargs);
5717 if (!StartServiceW(service, numargs, vector) &&
5718 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5720 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5727 /* wait for at most 30 seconds for the service to be up and running */
5728 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5729 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5731 TRACE("failed to query service status (%u)\n", GetLastError());
5734 start_time = GetTickCount64();
5735 while (status.dwCurrentState == SERVICE_START_PENDING)
5737 if (GetTickCount64() - start_time > 30000) break;
5739 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5740 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5742 TRACE("failed to query service status (%u)\n", GetLastError());
5746 if (status.dwCurrentState != SERVICE_RUNNING)
5748 WARN("service failed to start %u\n", status.dwCurrentState);
5749 r = ERROR_FUNCTION_FAILED;
5754 uirow = MSI_CreateRecord( 2 );
5755 MSI_RecordSetStringW( uirow, 1, display_name );
5756 MSI_RecordSetStringW( uirow, 2, name );
5757 msi_ui_actiondata( package, szStartServices, uirow );
5758 msiobj_release( &uirow->hdr );
5760 CloseServiceHandle(service);
5761 CloseServiceHandle(scm);
5766 msi_free(display_name);
5770 static UINT ACTION_StartServices( MSIPACKAGE *package )
5772 static const WCHAR query[] = {
5773 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5774 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5778 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5779 if (rc != ERROR_SUCCESS)
5780 return ERROR_SUCCESS;
5782 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5783 msiobj_release(&view->hdr);
5787 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5789 DWORD i, needed, count;
5790 ENUM_SERVICE_STATUSW *dependencies;
5794 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5795 0, &needed, &count))
5798 if (GetLastError() != ERROR_MORE_DATA)
5801 dependencies = msi_alloc(needed);
5805 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5806 needed, &needed, &count))
5809 for (i = 0; i < count; i++)
5811 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5812 SERVICE_STOP | SERVICE_QUERY_STATUS);
5816 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5823 msi_free(dependencies);
5827 static UINT stop_service( LPCWSTR name )
5829 SC_HANDLE scm = NULL, service = NULL;
5830 SERVICE_STATUS status;
5831 SERVICE_STATUS_PROCESS ssp;
5834 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5837 WARN("Failed to open the SCM: %d\n", GetLastError());
5841 service = OpenServiceW(scm, name,
5843 SERVICE_QUERY_STATUS |
5844 SERVICE_ENUMERATE_DEPENDENTS);
5847 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5851 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5852 sizeof(SERVICE_STATUS_PROCESS), &needed))
5854 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5858 if (ssp.dwCurrentState == SERVICE_STOPPED)
5861 stop_service_dependents(scm, service);
5863 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5864 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5867 CloseServiceHandle(service);
5868 CloseServiceHandle(scm);
5870 return ERROR_SUCCESS;
5873 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5875 MSIPACKAGE *package = param;
5879 LPWSTR name = NULL, display_name = NULL;
5883 event = MSI_RecordGetInteger( rec, 3 );
5884 if (!(event & msidbServiceControlEventStop))
5885 return ERROR_SUCCESS;
5887 component = MSI_RecordGetString( rec, 6 );
5888 comp = msi_get_loaded_component( package, component );
5890 return ERROR_SUCCESS;
5892 comp->Action = msi_get_component_action( package, comp );
5893 if (comp->Action != INSTALLSTATE_ABSENT)
5895 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5896 return ERROR_SUCCESS;
5899 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5902 ERR("Failed to open the service control manager\n");
5907 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5908 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5910 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5911 GetServiceDisplayNameW( scm, name, display_name, &len );
5913 CloseServiceHandle( scm );
5915 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5916 stop_service( name );
5919 uirow = MSI_CreateRecord( 2 );
5920 MSI_RecordSetStringW( uirow, 1, display_name );
5921 MSI_RecordSetStringW( uirow, 2, name );
5922 msi_ui_actiondata( package, szStopServices, uirow );
5923 msiobj_release( &uirow->hdr );
5926 msi_free( display_name );
5927 return ERROR_SUCCESS;
5930 static UINT ACTION_StopServices( MSIPACKAGE *package )
5932 static const WCHAR query[] = {
5933 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5934 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5938 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5939 if (rc != ERROR_SUCCESS)
5940 return ERROR_SUCCESS;
5942 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5943 msiobj_release(&view->hdr);
5947 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5949 MSIPACKAGE *package = param;
5952 LPWSTR name = NULL, display_name = NULL;
5954 SC_HANDLE scm = NULL, service = NULL;
5956 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5958 return ERROR_SUCCESS;
5960 event = MSI_RecordGetInteger( rec, 3 );
5961 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5963 comp->Action = msi_get_component_action( package, comp );
5964 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5965 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5967 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5969 return ERROR_SUCCESS;
5971 stop_service( name );
5973 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5976 WARN("Failed to open the SCM: %d\n", GetLastError());
5981 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5982 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5984 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5985 GetServiceDisplayNameW( scm, name, display_name, &len );
5988 service = OpenServiceW( scm, name, DELETE );
5991 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5995 if (!DeleteService( service ))
5996 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5999 uirow = MSI_CreateRecord( 2 );
6000 MSI_RecordSetStringW( uirow, 1, display_name );
6001 MSI_RecordSetStringW( uirow, 2, name );
6002 msi_ui_actiondata( package, szDeleteServices, uirow );
6003 msiobj_release( &uirow->hdr );
6005 CloseServiceHandle( service );
6006 CloseServiceHandle( scm );
6008 msi_free( display_name );
6010 return ERROR_SUCCESS;
6013 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6015 static const WCHAR query[] = {
6016 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6017 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6021 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6022 if (rc != ERROR_SUCCESS)
6023 return ERROR_SUCCESS;
6025 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6026 msiobj_release( &view->hdr );
6030 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6032 MSIPACKAGE *package = param;
6033 LPWSTR driver, driver_path, ptr;
6034 WCHAR outpath[MAX_PATH];
6035 MSIFILE *driver_file = NULL, *setup_file = NULL;
6038 LPCWSTR desc, file_key, component;
6040 UINT r = ERROR_SUCCESS;
6042 static const WCHAR driver_fmt[] = {
6043 'D','r','i','v','e','r','=','%','s',0};
6044 static const WCHAR setup_fmt[] = {
6045 'S','e','t','u','p','=','%','s',0};
6046 static const WCHAR usage_fmt[] = {
6047 'F','i','l','e','U','s','a','g','e','=','1',0};
6049 component = MSI_RecordGetString( rec, 2 );
6050 comp = msi_get_loaded_component( package, component );
6052 return ERROR_SUCCESS;
6054 comp->Action = msi_get_component_action( package, comp );
6055 if (comp->Action != INSTALLSTATE_LOCAL)
6057 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6058 return ERROR_SUCCESS;
6060 desc = MSI_RecordGetString(rec, 3);
6062 file_key = MSI_RecordGetString( rec, 4 );
6063 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6065 file_key = MSI_RecordGetString( rec, 5 );
6066 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6070 ERR("ODBC Driver entry not found!\n");
6071 return ERROR_FUNCTION_FAILED;
6074 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6076 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6077 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6079 driver = msi_alloc(len * sizeof(WCHAR));
6081 return ERROR_OUTOFMEMORY;
6084 lstrcpyW(ptr, desc);
6085 ptr += lstrlenW(ptr) + 1;
6087 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6092 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6096 lstrcpyW(ptr, usage_fmt);
6097 ptr += lstrlenW(ptr) + 1;
6100 if (!driver_file->TargetPath)
6102 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6103 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6105 driver_path = strdupW(driver_file->TargetPath);
6106 ptr = strrchrW(driver_path, '\\');
6107 if (ptr) *ptr = '\0';
6109 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6110 NULL, ODBC_INSTALL_COMPLETE, &usage))
6112 ERR("Failed to install SQL driver!\n");
6113 r = ERROR_FUNCTION_FAILED;
6116 uirow = MSI_CreateRecord( 5 );
6117 MSI_RecordSetStringW( uirow, 1, desc );
6118 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6119 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6120 msi_ui_actiondata( package, szInstallODBC, uirow );
6121 msiobj_release( &uirow->hdr );
6124 msi_free(driver_path);
6129 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6131 MSIPACKAGE *package = param;
6132 LPWSTR translator, translator_path, ptr;
6133 WCHAR outpath[MAX_PATH];
6134 MSIFILE *translator_file = NULL, *setup_file = NULL;
6137 LPCWSTR desc, file_key, component;
6139 UINT r = ERROR_SUCCESS;
6141 static const WCHAR translator_fmt[] = {
6142 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6143 static const WCHAR setup_fmt[] = {
6144 'S','e','t','u','p','=','%','s',0};
6146 component = MSI_RecordGetString( rec, 2 );
6147 comp = msi_get_loaded_component( package, component );
6149 return ERROR_SUCCESS;
6151 comp->Action = msi_get_component_action( package, comp );
6152 if (comp->Action != INSTALLSTATE_LOCAL)
6154 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6155 return ERROR_SUCCESS;
6157 desc = MSI_RecordGetString(rec, 3);
6159 file_key = MSI_RecordGetString( rec, 4 );
6160 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6162 file_key = MSI_RecordGetString( rec, 5 );
6163 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6165 if (!translator_file)
6167 ERR("ODBC Translator entry not found!\n");
6168 return ERROR_FUNCTION_FAILED;
6171 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6173 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6175 translator = msi_alloc(len * sizeof(WCHAR));
6177 return ERROR_OUTOFMEMORY;
6180 lstrcpyW(ptr, desc);
6181 ptr += lstrlenW(ptr) + 1;
6183 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6188 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6193 translator_path = strdupW(translator_file->TargetPath);
6194 ptr = strrchrW(translator_path, '\\');
6195 if (ptr) *ptr = '\0';
6197 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6198 NULL, ODBC_INSTALL_COMPLETE, &usage))
6200 ERR("Failed to install SQL translator!\n");
6201 r = ERROR_FUNCTION_FAILED;
6204 uirow = MSI_CreateRecord( 5 );
6205 MSI_RecordSetStringW( uirow, 1, desc );
6206 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6207 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6208 msi_ui_actiondata( package, szInstallODBC, uirow );
6209 msiobj_release( &uirow->hdr );
6211 msi_free(translator);
6212 msi_free(translator_path);
6217 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6219 MSIPACKAGE *package = param;
6222 LPCWSTR desc, driver, component;
6223 WORD request = ODBC_ADD_SYS_DSN;
6226 UINT r = ERROR_SUCCESS;
6229 static const WCHAR attrs_fmt[] = {
6230 'D','S','N','=','%','s',0 };
6232 component = MSI_RecordGetString( rec, 2 );
6233 comp = msi_get_loaded_component( package, component );
6235 return ERROR_SUCCESS;
6237 comp->Action = msi_get_component_action( package, comp );
6238 if (comp->Action != INSTALLSTATE_LOCAL)
6240 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6241 return ERROR_SUCCESS;
6244 desc = MSI_RecordGetString(rec, 3);
6245 driver = MSI_RecordGetString(rec, 4);
6246 registration = MSI_RecordGetInteger(rec, 5);
6248 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6249 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6251 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6252 attrs = msi_alloc(len * sizeof(WCHAR));
6254 return ERROR_OUTOFMEMORY;
6256 len = sprintfW(attrs, attrs_fmt, desc);
6259 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6261 ERR("Failed to install SQL data source!\n");
6262 r = ERROR_FUNCTION_FAILED;
6265 uirow = MSI_CreateRecord( 5 );
6266 MSI_RecordSetStringW( uirow, 1, desc );
6267 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6268 MSI_RecordSetInteger( uirow, 3, request );
6269 msi_ui_actiondata( package, szInstallODBC, uirow );
6270 msiobj_release( &uirow->hdr );
6277 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6279 static const WCHAR driver_query[] = {
6280 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6281 'O','D','B','C','D','r','i','v','e','r',0};
6282 static const WCHAR translator_query[] = {
6283 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6284 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6285 static const WCHAR source_query[] = {
6286 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6287 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6291 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6292 if (rc == ERROR_SUCCESS)
6294 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6295 msiobj_release(&view->hdr);
6296 if (rc != ERROR_SUCCESS)
6299 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6300 if (rc == ERROR_SUCCESS)
6302 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6303 msiobj_release(&view->hdr);
6304 if (rc != ERROR_SUCCESS)
6307 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6308 if (rc == ERROR_SUCCESS)
6310 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6311 msiobj_release(&view->hdr);
6312 if (rc != ERROR_SUCCESS)
6315 return ERROR_SUCCESS;
6318 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6320 MSIPACKAGE *package = param;
6324 LPCWSTR desc, component;
6326 component = MSI_RecordGetString( rec, 2 );
6327 comp = msi_get_loaded_component( package, component );
6329 return ERROR_SUCCESS;
6331 comp->Action = msi_get_component_action( package, comp );
6332 if (comp->Action != INSTALLSTATE_ABSENT)
6334 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6335 return ERROR_SUCCESS;
6338 desc = MSI_RecordGetString( rec, 3 );
6339 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6341 WARN("Failed to remove ODBC driver\n");
6345 FIXME("Usage count reached 0\n");
6348 uirow = MSI_CreateRecord( 2 );
6349 MSI_RecordSetStringW( uirow, 1, desc );
6350 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6351 msi_ui_actiondata( package, szRemoveODBC, uirow );
6352 msiobj_release( &uirow->hdr );
6354 return ERROR_SUCCESS;
6357 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6359 MSIPACKAGE *package = param;
6363 LPCWSTR desc, component;
6365 component = MSI_RecordGetString( rec, 2 );
6366 comp = msi_get_loaded_component( package, component );
6368 return ERROR_SUCCESS;
6370 comp->Action = msi_get_component_action( package, comp );
6371 if (comp->Action != INSTALLSTATE_ABSENT)
6373 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6374 return ERROR_SUCCESS;
6377 desc = MSI_RecordGetString( rec, 3 );
6378 if (!SQLRemoveTranslatorW( desc, &usage ))
6380 WARN("Failed to remove ODBC translator\n");
6384 FIXME("Usage count reached 0\n");
6387 uirow = MSI_CreateRecord( 2 );
6388 MSI_RecordSetStringW( uirow, 1, desc );
6389 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6390 msi_ui_actiondata( package, szRemoveODBC, uirow );
6391 msiobj_release( &uirow->hdr );
6393 return ERROR_SUCCESS;
6396 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6398 MSIPACKAGE *package = param;
6402 LPCWSTR desc, driver, component;
6403 WORD request = ODBC_REMOVE_SYS_DSN;
6407 static const WCHAR attrs_fmt[] = {
6408 'D','S','N','=','%','s',0 };
6410 component = MSI_RecordGetString( rec, 2 );
6411 comp = msi_get_loaded_component( package, component );
6413 return ERROR_SUCCESS;
6415 comp->Action = msi_get_component_action( package, comp );
6416 if (comp->Action != INSTALLSTATE_ABSENT)
6418 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6419 return ERROR_SUCCESS;
6422 desc = MSI_RecordGetString( rec, 3 );
6423 driver = MSI_RecordGetString( rec, 4 );
6424 registration = MSI_RecordGetInteger( rec, 5 );
6426 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6427 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6429 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6430 attrs = msi_alloc( len * sizeof(WCHAR) );
6432 return ERROR_OUTOFMEMORY;
6434 FIXME("Use ODBCSourceAttribute table\n");
6436 len = sprintfW( attrs, attrs_fmt, desc );
6439 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6441 WARN("Failed to remove ODBC data source\n");
6445 uirow = MSI_CreateRecord( 3 );
6446 MSI_RecordSetStringW( uirow, 1, desc );
6447 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6448 MSI_RecordSetInteger( uirow, 3, request );
6449 msi_ui_actiondata( package, szRemoveODBC, uirow );
6450 msiobj_release( &uirow->hdr );
6452 return ERROR_SUCCESS;
6455 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6457 static const WCHAR driver_query[] = {
6458 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6459 'O','D','B','C','D','r','i','v','e','r',0};
6460 static const WCHAR translator_query[] = {
6461 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6462 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6463 static const WCHAR source_query[] = {
6464 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6465 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6469 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6470 if (rc == ERROR_SUCCESS)
6472 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6473 msiobj_release( &view->hdr );
6474 if (rc != ERROR_SUCCESS)
6477 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6478 if (rc == ERROR_SUCCESS)
6480 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6481 msiobj_release( &view->hdr );
6482 if (rc != ERROR_SUCCESS)
6485 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6486 if (rc == ERROR_SUCCESS)
6488 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6489 msiobj_release( &view->hdr );
6490 if (rc != ERROR_SUCCESS)
6493 return ERROR_SUCCESS;
6496 #define ENV_ACT_SETALWAYS 0x1
6497 #define ENV_ACT_SETABSENT 0x2
6498 #define ENV_ACT_REMOVE 0x4
6499 #define ENV_ACT_REMOVEMATCH 0x8
6501 #define ENV_MOD_MACHINE 0x20000000
6502 #define ENV_MOD_APPEND 0x40000000
6503 #define ENV_MOD_PREFIX 0x80000000
6504 #define ENV_MOD_MASK 0xC0000000
6506 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6508 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6510 LPCWSTR cptr = *name;
6512 static const WCHAR prefix[] = {'[','~',']',0};
6513 static const int prefix_len = 3;
6519 *flags |= ENV_ACT_SETALWAYS;
6520 else if (*cptr == '+')
6521 *flags |= ENV_ACT_SETABSENT;
6522 else if (*cptr == '-')
6523 *flags |= ENV_ACT_REMOVE;
6524 else if (*cptr == '!')
6525 *flags |= ENV_ACT_REMOVEMATCH;
6526 else if (*cptr == '*')
6527 *flags |= ENV_MOD_MACHINE;
6537 ERR("Missing environment variable\n");
6538 return ERROR_FUNCTION_FAILED;
6543 LPCWSTR ptr = *value;
6544 if (!strncmpW(ptr, prefix, prefix_len))
6546 if (ptr[prefix_len] == szSemiColon[0])
6548 *flags |= ENV_MOD_APPEND;
6549 *value += lstrlenW(prefix);
6556 else if (lstrlenW(*value) >= prefix_len)
6558 ptr += lstrlenW(ptr) - prefix_len;
6559 if (!strcmpW( ptr, prefix ))
6561 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6563 *flags |= ENV_MOD_PREFIX;
6564 /* the "[~]" will be removed by deformat_string */;
6574 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6575 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6576 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6577 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6579 ERR("Invalid flags: %08x\n", *flags);
6580 return ERROR_FUNCTION_FAILED;
6584 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6586 return ERROR_SUCCESS;
6589 static UINT open_env_key( DWORD flags, HKEY *key )
6591 static const WCHAR user_env[] =
6592 {'E','n','v','i','r','o','n','m','e','n','t',0};
6593 static const WCHAR machine_env[] =
6594 {'S','y','s','t','e','m','\\',
6595 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6596 'C','o','n','t','r','o','l','\\',
6597 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6598 'E','n','v','i','r','o','n','m','e','n','t',0};
6603 if (flags & ENV_MOD_MACHINE)
6606 root = HKEY_LOCAL_MACHINE;
6611 root = HKEY_CURRENT_USER;
6614 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6615 if (res != ERROR_SUCCESS)
6617 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6618 return ERROR_FUNCTION_FAILED;
6621 return ERROR_SUCCESS;
6624 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6626 MSIPACKAGE *package = param;
6627 LPCWSTR name, value, component;
6628 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6629 DWORD flags, type, size;
6636 component = MSI_RecordGetString(rec, 4);
6637 comp = msi_get_loaded_component(package, component);
6639 return ERROR_SUCCESS;
6641 comp->Action = msi_get_component_action( package, comp );
6642 if (comp->Action != INSTALLSTATE_LOCAL)
6644 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6645 return ERROR_SUCCESS;
6647 name = MSI_RecordGetString(rec, 2);
6648 value = MSI_RecordGetString(rec, 3);
6650 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6652 res = env_parse_flags(&name, &value, &flags);
6653 if (res != ERROR_SUCCESS || !value)
6656 if (value && !deformat_string(package, value, &deformatted))
6658 res = ERROR_OUTOFMEMORY;
6662 value = deformatted;
6664 res = open_env_key( flags, &env );
6665 if (res != ERROR_SUCCESS)
6668 if (flags & ENV_MOD_MACHINE)
6669 action |= 0x20000000;
6673 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6674 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6675 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6678 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6682 /* Nothing to do. */
6685 res = ERROR_SUCCESS;
6689 /* If we are appending but the string was empty, strip ; */
6690 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6692 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6693 newval = strdupW(value);
6696 res = ERROR_OUTOFMEMORY;
6704 /* Contrary to MSDN, +-variable to [~];path works */
6705 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6707 res = ERROR_SUCCESS;
6711 data = msi_alloc(size);
6715 return ERROR_OUTOFMEMORY;
6718 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6719 if (res != ERROR_SUCCESS)
6722 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6725 res = RegDeleteValueW(env, name);
6726 if (res != ERROR_SUCCESS)
6727 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6731 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6732 if (flags & ENV_MOD_MASK)
6736 if (flags & ENV_MOD_APPEND) multiplier++;
6737 if (flags & ENV_MOD_PREFIX) multiplier++;
6738 mod_size = lstrlenW(value) * multiplier;
6739 size += mod_size * sizeof(WCHAR);
6742 newval = msi_alloc(size);
6746 res = ERROR_OUTOFMEMORY;
6750 if (flags & ENV_MOD_PREFIX)
6752 lstrcpyW(newval, value);
6753 ptr = newval + lstrlenW(value);
6754 action |= 0x80000000;
6757 lstrcpyW(ptr, data);
6759 if (flags & ENV_MOD_APPEND)
6761 lstrcatW(newval, value);
6762 action |= 0x40000000;
6765 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6766 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6769 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6773 uirow = MSI_CreateRecord( 3 );
6774 MSI_RecordSetStringW( uirow, 1, name );
6775 MSI_RecordSetStringW( uirow, 2, newval );
6776 MSI_RecordSetInteger( uirow, 3, action );
6777 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6778 msiobj_release( &uirow->hdr );
6780 if (env) RegCloseKey(env);
6781 msi_free(deformatted);
6787 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6789 static const WCHAR query[] = {
6790 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6791 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6795 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6796 if (rc != ERROR_SUCCESS)
6797 return ERROR_SUCCESS;
6799 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6800 msiobj_release(&view->hdr);
6804 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6806 MSIPACKAGE *package = param;
6807 LPCWSTR name, value, component;
6808 LPWSTR deformatted = NULL;
6817 component = MSI_RecordGetString( rec, 4 );
6818 comp = msi_get_loaded_component( package, component );
6820 return ERROR_SUCCESS;
6822 comp->Action = msi_get_component_action( package, comp );
6823 if (comp->Action != INSTALLSTATE_ABSENT)
6825 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6826 return ERROR_SUCCESS;
6828 name = MSI_RecordGetString( rec, 2 );
6829 value = MSI_RecordGetString( rec, 3 );
6831 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6833 r = env_parse_flags( &name, &value, &flags );
6834 if (r != ERROR_SUCCESS)
6837 if (!(flags & ENV_ACT_REMOVE))
6839 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6840 return ERROR_SUCCESS;
6843 if (value && !deformat_string( package, value, &deformatted ))
6844 return ERROR_OUTOFMEMORY;
6846 value = deformatted;
6848 r = open_env_key( flags, &env );
6849 if (r != ERROR_SUCCESS)
6855 if (flags & ENV_MOD_MACHINE)
6856 action |= 0x20000000;
6858 TRACE("Removing %s\n", debugstr_w(name));
6860 res = RegDeleteValueW( env, name );
6861 if (res != ERROR_SUCCESS)
6863 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6868 uirow = MSI_CreateRecord( 3 );
6869 MSI_RecordSetStringW( uirow, 1, name );
6870 MSI_RecordSetStringW( uirow, 2, value );
6871 MSI_RecordSetInteger( uirow, 3, action );
6872 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6873 msiobj_release( &uirow->hdr );
6875 if (env) RegCloseKey( env );
6876 msi_free( deformatted );
6880 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6882 static const WCHAR query[] = {
6883 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6884 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6888 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6889 if (rc != ERROR_SUCCESS)
6890 return ERROR_SUCCESS;
6892 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6893 msiobj_release( &view->hdr );
6897 UINT msi_validate_product_id( MSIPACKAGE *package )
6899 LPWSTR key, template, id;
6900 UINT r = ERROR_SUCCESS;
6902 id = msi_dup_property( package->db, szProductID );
6906 return ERROR_SUCCESS;
6908 template = msi_dup_property( package->db, szPIDTemplate );
6909 key = msi_dup_property( package->db, szPIDKEY );
6910 if (key && template)
6912 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6913 r = msi_set_property( package->db, szProductID, key );
6915 msi_free( template );
6920 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6922 return msi_validate_product_id( package );
6925 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6928 package->need_reboot_at_end = 1;
6929 return ERROR_SUCCESS;
6932 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6934 static const WCHAR szAvailableFreeReg[] =
6935 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6937 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6939 TRACE("%p %d kilobytes\n", package, space);
6941 uirow = MSI_CreateRecord( 1 );
6942 MSI_RecordSetInteger( uirow, 1, space );
6943 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6944 msiobj_release( &uirow->hdr );
6946 return ERROR_SUCCESS;
6949 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6951 TRACE("%p\n", package);
6953 msi_set_property( package->db, szRollbackDisabled, szOne );
6954 return ERROR_SUCCESS;
6957 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6959 FIXME("%p\n", package);
6960 return ERROR_SUCCESS;
6963 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6965 static const WCHAR driver_query[] = {
6966 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6967 'O','D','B','C','D','r','i','v','e','r',0};
6968 static const WCHAR translator_query[] = {
6969 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6970 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6974 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6975 if (r == ERROR_SUCCESS)
6978 r = MSI_IterateRecords( view, &count, NULL, package );
6979 msiobj_release( &view->hdr );
6980 if (r != ERROR_SUCCESS)
6982 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6984 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6985 if (r == ERROR_SUCCESS)
6988 r = MSI_IterateRecords( view, &count, NULL, package );
6989 msiobj_release( &view->hdr );
6990 if (r != ERROR_SUCCESS)
6992 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6994 return ERROR_SUCCESS;
6997 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6999 MSIPACKAGE *package = param;
7000 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7003 if ((value = msi_dup_property( package->db, property )))
7005 FIXME("remove %s\n", debugstr_w(value));
7008 return ERROR_SUCCESS;
7011 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7013 static const WCHAR query[] = {
7014 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7015 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7019 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7020 if (r == ERROR_SUCCESS)
7022 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7023 msiobj_release( &view->hdr );
7024 if (r != ERROR_SUCCESS)
7027 return ERROR_SUCCESS;
7030 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7032 MSIPACKAGE *package = param;
7033 int attributes = MSI_RecordGetInteger( rec, 5 );
7035 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7037 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7038 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7039 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7040 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7044 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7046 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7047 if (r != ERROR_SUCCESS)
7048 return ERROR_SUCCESS;
7052 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7053 if (r != ERROR_SUCCESS)
7054 return ERROR_SUCCESS;
7056 RegCloseKey( hkey );
7058 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7059 debugstr_w(upgrade_code), debugstr_w(version_min),
7060 debugstr_w(version_max), debugstr_w(language));
7062 return ERROR_SUCCESS;
7065 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7067 static const WCHAR query[] = {
7068 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7069 'U','p','g','r','a','d','e',0};
7073 if (msi_get_property_int( package->db, szInstalled, 0 ))
7075 TRACE("product is installed, skipping action\n");
7076 return ERROR_SUCCESS;
7078 if (msi_get_property_int( package->db, szPreselected, 0 ))
7080 TRACE("Preselected property is set, not migrating feature states\n");
7081 return ERROR_SUCCESS;
7083 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7084 if (r == ERROR_SUCCESS)
7086 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7087 msiobj_release( &view->hdr );
7088 if (r != ERROR_SUCCESS)
7091 return ERROR_SUCCESS;
7094 static void bind_image( const char *filename, const char *path )
7096 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7098 WARN("failed to bind image %u\n", GetLastError());
7102 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7106 MSIPACKAGE *package = param;
7107 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7108 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7109 char *filenameA, *pathA;
7110 WCHAR *pathW, **path_list;
7112 if (!(file = msi_get_loaded_file( package, key )))
7114 WARN("file %s not found\n", debugstr_w(key));
7115 return ERROR_SUCCESS;
7117 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7118 path_list = msi_split_string( paths, ';' );
7119 if (!path_list) bind_image( filenameA, NULL );
7122 for (i = 0; path_list[i] && path_list[i][0]; i++)
7124 deformat_string( package, path_list[i], &pathW );
7125 if ((pathA = strdupWtoA( pathW )))
7127 bind_image( filenameA, pathA );
7133 msi_free( path_list );
7134 msi_free( filenameA );
7135 return ERROR_SUCCESS;
7138 static UINT ACTION_BindImage( MSIPACKAGE *package )
7140 static const WCHAR query[] = {
7141 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7142 'B','i','n','d','I','m','a','g','e',0};
7146 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7147 if (r == ERROR_SUCCESS)
7149 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7150 msiobj_release( &view->hdr );
7151 if (r != ERROR_SUCCESS)
7154 return ERROR_SUCCESS;
7157 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7159 static const WCHAR query[] = {
7160 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7165 r = MSI_OpenQuery( package->db, &view, query, table );
7166 if (r == ERROR_SUCCESS)
7168 r = MSI_IterateRecords(view, &count, NULL, package);
7169 msiobj_release(&view->hdr);
7170 if (r != ERROR_SUCCESS)
7173 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7174 return ERROR_SUCCESS;
7177 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7179 static const WCHAR table[] = {
7180 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7181 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7184 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7186 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7187 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7190 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7192 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7193 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7196 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7198 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7199 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7202 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7204 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7205 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7210 const WCHAR *action;
7211 UINT (*handler)(MSIPACKAGE *);
7212 const WCHAR *action_rollback;
7216 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7217 { szAppSearch, ACTION_AppSearch, NULL },
7218 { szBindImage, ACTION_BindImage, NULL },
7219 { szCCPSearch, ACTION_CCPSearch, NULL },
7220 { szCostFinalize, ACTION_CostFinalize, NULL },
7221 { szCostInitialize, ACTION_CostInitialize, NULL },
7222 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7223 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7224 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7225 { szDisableRollback, ACTION_DisableRollback, NULL },
7226 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7227 { szExecuteAction, ACTION_ExecuteAction, NULL },
7228 { szFileCost, ACTION_FileCost, NULL },
7229 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7230 { szForceReboot, ACTION_ForceReboot, NULL },
7231 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7232 { szInstallExecute, ACTION_InstallExecute, NULL },
7233 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7234 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7235 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7236 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7237 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7238 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7239 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7240 { szInstallValidate, ACTION_InstallValidate, NULL },
7241 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7242 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7243 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7244 { szMoveFiles, ACTION_MoveFiles, NULL },
7245 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7246 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7247 { szPatchFiles, ACTION_PatchFiles, NULL },
7248 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7249 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7250 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7251 { szPublishProduct, ACTION_PublishProduct, NULL },
7252 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7253 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7254 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7255 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7256 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7257 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7258 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7259 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7260 { szRegisterUser, ACTION_RegisterUser, NULL },
7261 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7262 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7263 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7264 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7265 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7266 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7267 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7268 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7269 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7270 { szResolveSource, ACTION_ResolveSource, NULL },
7271 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7272 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7273 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7274 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7275 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7276 { szStartServices, ACTION_StartServices, szStopServices },
7277 { szStopServices, ACTION_StopServices, szStartServices },
7278 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7279 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7280 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7281 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7282 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7283 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7284 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7285 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7286 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7287 { szValidateProductID, ACTION_ValidateProductID, NULL },
7288 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7289 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7290 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7291 { NULL, NULL, NULL }
7294 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7300 while (StandardActions[i].action != NULL)
7302 if (!strcmpW( StandardActions[i].action, action ))
7304 ui_actionstart( package, action );
7305 if (StandardActions[i].handler)
7307 ui_actioninfo( package, action, TRUE, 0 );
7308 *rc = StandardActions[i].handler( package );
7309 ui_actioninfo( package, action, FALSE, *rc );
7311 if (StandardActions[i].action_rollback && !package->need_rollback)
7313 TRACE("scheduling rollback action\n");
7314 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7319 FIXME("unhandled standard action %s\n", debugstr_w(action));
7320 *rc = ERROR_SUCCESS;
7330 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7332 UINT rc = ERROR_SUCCESS;
7335 TRACE("Performing action (%s)\n", debugstr_w(action));
7337 handled = ACTION_HandleStandardAction(package, action, &rc);
7340 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7344 WARN("unhandled msi action %s\n", debugstr_w(action));
7345 rc = ERROR_FUNCTION_NOT_CALLED;
7351 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7353 UINT rc = ERROR_SUCCESS;
7354 BOOL handled = FALSE;
7356 TRACE("Performing action (%s)\n", debugstr_w(action));
7358 package->action_progress_increment = 0;
7359 handled = ACTION_HandleStandardAction(package, action, &rc);
7362 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7364 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7369 WARN("unhandled msi action %s\n", debugstr_w(action));
7370 rc = ERROR_FUNCTION_NOT_CALLED;
7376 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7378 UINT rc = ERROR_SUCCESS;
7381 static const WCHAR query[] =
7382 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7383 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7384 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7385 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7386 static const WCHAR ui_query[] =
7387 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7388 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7389 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7390 ' ', '=',' ','%','i',0};
7392 if (needs_ui_sequence(package))
7393 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7395 row = MSI_QueryGetRecord(package->db, query, seq);
7399 LPCWSTR action, cond;
7401 TRACE("Running the actions\n");
7403 /* check conditions */
7404 cond = MSI_RecordGetString(row, 2);
7406 /* this is a hack to skip errors in the condition code */
7407 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7409 msiobj_release(&row->hdr);
7410 return ERROR_SUCCESS;
7413 action = MSI_RecordGetString(row, 1);
7416 ERR("failed to fetch action\n");
7417 msiobj_release(&row->hdr);
7418 return ERROR_FUNCTION_FAILED;
7421 if (needs_ui_sequence(package))
7422 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7424 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7426 msiobj_release(&row->hdr);
7432 /****************************************************
7433 * TOP level entry points
7434 *****************************************************/
7436 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7437 LPCWSTR szCommandLine )
7439 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7440 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7441 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7442 WCHAR *reinstall = NULL;
7446 msi_set_property( package->db, szAction, szInstall );
7448 package->script->InWhatSequence = SEQUENCE_INSTALL;
7455 dir = strdupW(szPackagePath);
7456 p = strrchrW(dir, '\\');
7460 file = szPackagePath + (p - dir);
7465 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7466 GetCurrentDirectoryW(MAX_PATH, dir);
7467 lstrcatW(dir, szBackSlash);
7468 file = szPackagePath;
7471 msi_free( package->PackagePath );
7472 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7473 if (!package->PackagePath)
7476 return ERROR_OUTOFMEMORY;
7479 lstrcpyW(package->PackagePath, dir);
7480 lstrcatW(package->PackagePath, file);
7483 msi_set_sourcedir_props(package, FALSE);
7486 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7487 if (rc != ERROR_SUCCESS)
7490 msi_apply_transforms( package );
7491 msi_apply_patches( package );
7493 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7495 TRACE("setting reinstall property\n");
7496 msi_set_property( package->db, szReinstall, szAll );
7499 /* properties may have been added by a transform */
7500 msi_clone_properties( package );
7502 msi_parse_command_line( package, szCommandLine, FALSE );
7503 msi_adjust_privilege_properties( package );
7504 msi_set_context( package );
7506 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7508 TRACE("disabling rollback\n");
7509 msi_set_property( package->db, szRollbackDisabled, szOne );
7512 if (needs_ui_sequence( package))
7514 package->script->InWhatSequence |= SEQUENCE_UI;
7515 rc = ACTION_ProcessUISequence(package);
7516 ui_exists = ui_sequence_exists(package);
7517 if (rc == ERROR_SUCCESS || !ui_exists)
7519 package->script->InWhatSequence |= SEQUENCE_EXEC;
7520 rc = ACTION_ProcessExecSequence(package, ui_exists);
7524 rc = ACTION_ProcessExecSequence(package, FALSE);
7526 package->script->CurrentlyScripting = FALSE;
7528 /* process the ending type action */
7529 if (rc == ERROR_SUCCESS)
7530 ACTION_PerformActionSequence(package, -1);
7531 else if (rc == ERROR_INSTALL_USEREXIT)
7532 ACTION_PerformActionSequence(package, -2);
7533 else if (rc == ERROR_INSTALL_SUSPEND)
7534 ACTION_PerformActionSequence(package, -4);
7537 ACTION_PerformActionSequence(package, -3);
7538 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7540 package->need_rollback = TRUE;
7544 /* finish up running custom actions */
7545 ACTION_FinishCustomActions(package);
7547 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7549 WARN("installation failed, running rollback script\n");
7550 execute_script( package, SCRIPT_ROLLBACK );
7552 msi_free( reinstall );
7554 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7555 return ERROR_SUCCESS_REBOOT_REQUIRED;