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 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, DWORD *size)
2399 data = (LPSTR)strdupW(szEmpty);
2400 *size = sizeof(szEmpty);
2404 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2410 LPWSTR deformated = NULL;
2413 deformat_string(package, &value[2], &deformated);
2415 /* binary value type */
2419 *size = (strlenW(ptr)/2)+1;
2421 *size = strlenW(ptr)/2;
2423 data = msi_alloc(*size);
2429 /* if uneven pad with a zero in front */
2435 data[count] = (BYTE)strtol(byte,NULL,0);
2437 TRACE("Uneven byte count\n");
2445 data[count] = (BYTE)strtol(byte,NULL,0);
2448 msi_free(deformated);
2450 TRACE("Data %i bytes(%i)\n",*size,count);
2457 deformat_string(package, &value[1], &deformated);
2460 *size = sizeof(DWORD);
2461 data = msi_alloc(*size);
2467 if ( (*p < '0') || (*p > '9') )
2473 if (deformated[0] == '-')
2476 TRACE("DWORD %i\n",*(LPDWORD)data);
2478 msi_free(deformated);
2483 static const WCHAR szMulti[] = {'[','~',']',0};
2492 *type=REG_EXPAND_SZ;
2500 if (strstrW(value, szMulti))
2501 *type = REG_MULTI_SZ;
2503 /* remove initial delimiter */
2504 if (!strncmpW(value, szMulti, 3))
2507 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2509 /* add double NULL terminator */
2510 if (*type == REG_MULTI_SZ)
2512 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2513 data = msi_realloc_zero(data, *size);
2519 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2526 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2528 *root_key = HKEY_LOCAL_MACHINE;
2533 *root_key = HKEY_CURRENT_USER;
2538 *root_key = HKEY_CLASSES_ROOT;
2542 *root_key = HKEY_CURRENT_USER;
2546 *root_key = HKEY_LOCAL_MACHINE;
2550 *root_key = HKEY_USERS;
2554 ERR("Unknown root %i\n", root);
2561 static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2563 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2564 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2566 if ((is_64bit || is_wow64) &&
2567 !(comp->Attributes & msidbComponentAttributes64bit) &&
2568 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2573 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2574 if (!(path_32node = msi_alloc( size ))) return NULL;
2576 memcpy( path_32node, path, len * sizeof(WCHAR) );
2577 strcpyW( path_32node + len, szWow6432Node );
2578 strcatW( path_32node, szBackSlash );
2579 strcatW( path_32node, path + len );
2582 return strdupW( path );
2585 static BOOL is_special_entry( const WCHAR *name )
2587 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2590 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2592 MSIPACKAGE *package = param;
2594 HKEY root_key, hkey;
2596 LPWSTR deformated, uikey, keypath;
2597 LPCWSTR szRoot, component, name, key;
2601 BOOL check_first = FALSE;
2604 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2606 component = MSI_RecordGetString(row, 6);
2607 comp = msi_get_loaded_component(package,component);
2609 return ERROR_SUCCESS;
2611 comp->Action = msi_get_component_action( package, comp );
2612 if (comp->Action != INSTALLSTATE_LOCAL)
2614 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2615 return ERROR_SUCCESS;
2618 name = MSI_RecordGetString(row, 4);
2619 if( MSI_RecordIsNull(row,5) && name )
2621 /* null values can have special meanings */
2622 if (name[0]=='-' && name[1] == 0)
2623 return ERROR_SUCCESS;
2624 if ((name[0] == '+' || name[0] == '*') && !name[1])
2628 root = MSI_RecordGetInteger(row,2);
2629 key = MSI_RecordGetString(row, 3);
2631 szRoot = get_root_key( package, root, &root_key );
2633 return ERROR_SUCCESS;
2635 deformat_string(package, key , &deformated);
2636 size = strlenW(deformated) + strlenW(szRoot) + 1;
2637 uikey = msi_alloc(size*sizeof(WCHAR));
2638 strcpyW(uikey,szRoot);
2639 strcatW(uikey,deformated);
2641 keypath = get_keypath( comp, root_key, deformated );
2642 msi_free( deformated );
2643 if (RegCreateKeyExW( root_key, keypath, 0, NULL, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, NULL, &hkey, NULL ))
2645 ERR("Could not create key %s\n", debugstr_w(keypath));
2648 return ERROR_FUNCTION_FAILED;
2650 value = parse_value(package, MSI_RecordGetString(row, 5), &type, &size);
2651 deformat_string(package, name, &deformated);
2653 if (!is_special_entry( name ))
2657 TRACE("Setting value %s of %s\n", debugstr_w(deformated),
2659 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2664 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2665 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2667 TRACE("value %s of %s checked already exists\n", debugstr_w(deformated),
2672 TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated),
2674 if (deformated || size)
2675 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size);
2681 uirow = MSI_CreateRecord(3);
2682 MSI_RecordSetStringW(uirow,2,deformated);
2683 MSI_RecordSetStringW(uirow,1,uikey);
2684 if (type == REG_SZ || type == REG_EXPAND_SZ)
2685 MSI_RecordSetStringW(uirow, 3, (LPWSTR)value);
2686 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2687 msiobj_release( &uirow->hdr );
2690 msi_free(deformated);
2694 return ERROR_SUCCESS;
2697 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2699 static const WCHAR query[] = {
2700 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2701 '`','R','e','g','i','s','t','r','y','`',0};
2705 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2706 if (rc != ERROR_SUCCESS)
2707 return ERROR_SUCCESS;
2709 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2710 msiobj_release(&view->hdr);
2714 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2718 DWORD num_subkeys, num_values;
2720 if (!(res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey )))
2722 if ((res = RegDeleteValueW( hkey, value )))
2724 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2726 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2727 NULL, NULL, NULL, NULL );
2728 RegCloseKey( hkey );
2729 if (!res && !num_subkeys && !num_values)
2731 TRACE("removing empty key %s\n", debugstr_w(keypath));
2732 RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 );
2736 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2739 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2742 LONG res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey );
2745 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2748 res = RegDeleteTreeW( hkey, NULL );
2749 if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(keypath), res);
2750 res = RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 );
2751 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2752 RegCloseKey( hkey );
2755 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2757 MSIPACKAGE *package = param;
2758 LPCWSTR component, name, key_str, root_key_str;
2759 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2762 BOOL delete_key = FALSE;
2767 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2769 component = MSI_RecordGetString( row, 6 );
2770 comp = msi_get_loaded_component( package, component );
2772 return ERROR_SUCCESS;
2774 comp->Action = msi_get_component_action( package, comp );
2775 if (comp->Action != INSTALLSTATE_ABSENT)
2777 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2778 return ERROR_SUCCESS;
2781 name = MSI_RecordGetString( row, 4 );
2782 if (MSI_RecordIsNull( row, 5 ) && name )
2784 if (name[0] == '+' && !name[1])
2785 return ERROR_SUCCESS;
2786 if ((name[0] == '-' || name[0] == '*') && !name[1])
2793 root = MSI_RecordGetInteger( row, 2 );
2794 key_str = MSI_RecordGetString( row, 3 );
2796 root_key_str = get_root_key( package, root, &hkey_root );
2798 return ERROR_SUCCESS;
2800 deformat_string( package, key_str, &deformated_key );
2801 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2802 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2803 strcpyW( ui_key_str, root_key_str );
2804 strcatW( ui_key_str, deformated_key );
2806 deformat_string( package, name, &deformated_name );
2808 keypath = get_keypath( comp, hkey_root, deformated_key );
2809 msi_free( deformated_key );
2810 if (delete_key) delete_reg_key( hkey_root, keypath );
2811 else delete_reg_value( hkey_root, keypath, deformated_name );
2812 msi_free( keypath );
2814 uirow = MSI_CreateRecord( 2 );
2815 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2816 MSI_RecordSetStringW( uirow, 2, deformated_name );
2817 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2818 msiobj_release( &uirow->hdr );
2820 msi_free( ui_key_str );
2821 msi_free( deformated_name );
2822 return ERROR_SUCCESS;
2825 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2827 MSIPACKAGE *package = param;
2828 LPCWSTR component, name, key_str, root_key_str;
2829 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2832 BOOL delete_key = FALSE;
2837 component = MSI_RecordGetString( row, 5 );
2838 comp = msi_get_loaded_component( package, component );
2840 return ERROR_SUCCESS;
2842 comp->Action = msi_get_component_action( package, comp );
2843 if (comp->Action != INSTALLSTATE_LOCAL)
2845 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2846 return ERROR_SUCCESS;
2849 if ((name = MSI_RecordGetString( row, 4 )))
2851 if (name[0] == '-' && !name[1])
2858 root = MSI_RecordGetInteger( row, 2 );
2859 key_str = MSI_RecordGetString( row, 3 );
2861 root_key_str = get_root_key( package, root, &hkey_root );
2863 return ERROR_SUCCESS;
2865 deformat_string( package, key_str, &deformated_key );
2866 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2867 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2868 strcpyW( ui_key_str, root_key_str );
2869 strcatW( ui_key_str, deformated_key );
2871 deformat_string( package, name, &deformated_name );
2873 keypath = get_keypath( comp, hkey_root, deformated_key );
2874 msi_free( deformated_key );
2875 if (delete_key) delete_reg_key( hkey_root, keypath );
2876 else delete_reg_value( hkey_root, keypath, deformated_name );
2877 msi_free( keypath );
2879 uirow = MSI_CreateRecord( 2 );
2880 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2881 MSI_RecordSetStringW( uirow, 2, deformated_name );
2882 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2883 msiobj_release( &uirow->hdr );
2885 msi_free( ui_key_str );
2886 msi_free( deformated_name );
2887 return ERROR_SUCCESS;
2890 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2892 static const WCHAR registry_query[] = {
2893 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2894 '`','R','e','g','i','s','t','r','y','`',0};
2895 static const WCHAR remove_registry_query[] = {
2896 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2897 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2901 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2902 if (rc == ERROR_SUCCESS)
2904 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2905 msiobj_release( &view->hdr );
2906 if (rc != ERROR_SUCCESS)
2909 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2910 if (rc == ERROR_SUCCESS)
2912 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2913 msiobj_release( &view->hdr );
2914 if (rc != ERROR_SUCCESS)
2917 return ERROR_SUCCESS;
2920 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2922 package->script->CurrentlyScripting = TRUE;
2924 return ERROR_SUCCESS;
2928 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2930 static const WCHAR query[]= {
2931 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2932 '`','R','e','g','i','s','t','r','y','`',0};
2934 DWORD total = 0, count = 0;
2936 MSIFEATURE *feature;
2940 TRACE("InstallValidate\n");
2942 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2943 if (rc == ERROR_SUCCESS)
2945 rc = MSI_IterateRecords( view, &count, NULL, package );
2946 msiobj_release( &view->hdr );
2947 if (rc != ERROR_SUCCESS)
2949 total += count * REG_PROGRESS_VALUE;
2951 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2952 total += COMPONENT_PROGRESS_VALUE;
2954 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2955 total += file->FileSize;
2957 msi_ui_progress( package, 0, total, 0, 0 );
2959 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2961 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2962 debugstr_w(feature->Feature), feature->Installed,
2963 feature->ActionRequest, feature->Action);
2965 return ERROR_SUCCESS;
2968 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2970 MSIPACKAGE* package = param;
2971 LPCWSTR cond = NULL;
2972 LPCWSTR message = NULL;
2975 static const WCHAR title[]=
2976 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2978 cond = MSI_RecordGetString(row,1);
2980 r = MSI_EvaluateConditionW(package,cond);
2981 if (r == MSICONDITION_FALSE)
2983 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2986 message = MSI_RecordGetString(row,2);
2987 deformat_string(package,message,&deformated);
2988 MessageBoxW(NULL,deformated,title,MB_OK);
2989 msi_free(deformated);
2992 return ERROR_INSTALL_FAILURE;
2995 return ERROR_SUCCESS;
2998 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3000 static const WCHAR query[] = {
3001 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3002 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3006 TRACE("Checking launch conditions\n");
3008 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3009 if (rc != ERROR_SUCCESS)
3010 return ERROR_SUCCESS;
3012 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3013 msiobj_release(&view->hdr);
3017 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3021 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3023 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3025 static const WCHAR query[] = {
3026 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3027 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3028 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3029 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3030 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3033 LPWSTR deformated, buffer, deformated_name;
3036 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3040 root = MSI_RecordGetInteger(row,2);
3041 key = MSI_RecordGetString(row, 3);
3042 name = MSI_RecordGetString(row, 4);
3043 deformat_string(package, key , &deformated);
3044 deformat_string(package, name, &deformated_name);
3046 len = strlenW(deformated) + 6;
3047 if (deformated_name)
3048 len+=strlenW(deformated_name);
3050 buffer = msi_alloc( len *sizeof(WCHAR));
3052 if (deformated_name)
3053 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3055 sprintfW(buffer,fmt,root,deformated);
3057 msi_free(deformated);
3058 msi_free(deformated_name);
3059 msiobj_release(&row->hdr);
3063 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3065 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3070 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3073 return strdupW( file->TargetPath );
3078 static HKEY openSharedDLLsKey(void)
3081 static const WCHAR path[] =
3082 {'S','o','f','t','w','a','r','e','\\',
3083 'M','i','c','r','o','s','o','f','t','\\',
3084 'W','i','n','d','o','w','s','\\',
3085 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3086 'S','h','a','r','e','d','D','L','L','s',0};
3088 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3092 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3097 DWORD sz = sizeof(count);
3100 hkey = openSharedDLLsKey();
3101 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3102 if (rc != ERROR_SUCCESS)
3108 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3112 hkey = openSharedDLLsKey();
3114 msi_reg_set_val_dword( hkey, path, count );
3116 RegDeleteValueW(hkey,path);
3121 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3123 MSIFEATURE *feature;
3127 /* only refcount DLLs */
3128 if (comp->KeyPath == NULL ||
3130 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3131 comp->Attributes & msidbComponentAttributesODBCDataSource)
3135 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3136 write = (count > 0);
3138 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3142 /* increment counts */
3143 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3147 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3150 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3152 if ( cl->component == comp )
3157 /* decrement counts */
3158 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3162 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3165 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3167 if ( cl->component == comp )
3172 /* ref count all the files in the component */
3177 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3179 if (file->Component == comp)
3180 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3184 /* add a count for permanent */
3185 if (comp->Attributes & msidbComponentAttributesPermanent)
3188 comp->RefCount = count;
3191 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3194 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3198 const WCHAR prefixW[] = {'<','\\',0};
3199 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3200 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3204 strcpyW( keypath, prefixW );
3205 strcatW( keypath, comp->assembly->display_name );
3209 return resolve_keypath( package, comp );
3212 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3214 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3221 squash_guid(package->ProductCode,squished_pc);
3222 msi_set_sourcedir_props(package, FALSE);
3224 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3227 INSTALLSTATE action;
3229 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3230 if (!comp->ComponentId)
3233 squash_guid( comp->ComponentId, squished_cc );
3234 msi_free( comp->FullKeypath );
3235 comp->FullKeypath = build_full_keypath( package, comp );
3237 ACTION_RefCountComponent( package, comp );
3239 if (package->need_rollback) action = comp->Installed;
3240 else action = comp->ActionRequest;
3242 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3243 debugstr_w(comp->Component), debugstr_w(squished_cc),
3244 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3246 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3248 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3249 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3251 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3253 if (rc != ERROR_SUCCESS)
3256 if (comp->Attributes & msidbComponentAttributesPermanent)
3258 static const WCHAR szPermKey[] =
3259 { '0','0','0','0','0','0','0','0','0','0','0','0',
3260 '0','0','0','0','0','0','0','0','0','0','0','0',
3261 '0','0','0','0','0','0','0','0',0 };
3263 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3265 if (action == INSTALLSTATE_LOCAL)
3266 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3272 WCHAR source[MAX_PATH];
3273 WCHAR base[MAX_PATH];
3276 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3277 static const WCHAR query[] = {
3278 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3279 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3280 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3281 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3282 '`','D','i','s','k','I','d','`',0};
3284 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3287 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3288 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3289 ptr2 = strrchrW(source, '\\') + 1;
3290 msiobj_release(&row->hdr);
3292 lstrcpyW(base, package->PackagePath);
3293 ptr = strrchrW(base, '\\');
3296 sourcepath = msi_resolve_file_source(package, file);
3297 ptr = sourcepath + lstrlenW(base);
3298 lstrcpyW(ptr2, ptr);
3299 msi_free(sourcepath);
3301 msi_reg_set_val_str(hkey, squished_pc, source);
3305 else if (action == INSTALLSTATE_ABSENT)
3307 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3308 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3310 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3314 uirow = MSI_CreateRecord(3);
3315 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3316 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3317 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3318 msi_ui_actiondata( package, szProcessComponents, uirow );
3319 msiobj_release( &uirow->hdr );
3321 return ERROR_SUCCESS;
3332 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3333 LPWSTR lpszName, LONG_PTR lParam)
3336 typelib_struct *tl_struct = (typelib_struct*) lParam;
3337 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3341 if (!IS_INTRESOURCE(lpszName))
3343 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3347 sz = strlenW(tl_struct->source)+4;
3348 sz *= sizeof(WCHAR);
3350 if ((INT_PTR)lpszName == 1)
3351 tl_struct->path = strdupW(tl_struct->source);
3354 tl_struct->path = msi_alloc(sz);
3355 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3358 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3359 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3362 msi_free(tl_struct->path);
3363 tl_struct->path = NULL;
3368 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3369 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3371 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3375 msi_free(tl_struct->path);
3376 tl_struct->path = NULL;
3378 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3379 ITypeLib_Release(tl_struct->ptLib);
3384 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3386 MSIPACKAGE* package = param;
3390 typelib_struct tl_struct;
3395 component = MSI_RecordGetString(row,3);
3396 comp = msi_get_loaded_component(package,component);
3398 return ERROR_SUCCESS;
3400 comp->Action = msi_get_component_action( package, comp );
3401 if (comp->Action != INSTALLSTATE_LOCAL)
3403 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3404 return ERROR_SUCCESS;
3407 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3409 TRACE("component has no key path\n");
3410 return ERROR_SUCCESS;
3412 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3414 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3418 guid = MSI_RecordGetString(row,1);
3419 CLSIDFromString( guid, &tl_struct.clsid);
3420 tl_struct.source = strdupW( file->TargetPath );
3421 tl_struct.path = NULL;
3423 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3424 (LONG_PTR)&tl_struct);
3428 LPCWSTR helpid, help_path = NULL;
3431 helpid = MSI_RecordGetString(row,6);
3433 if (helpid) help_path = msi_get_target_folder( package, helpid );
3434 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3437 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3439 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3441 ITypeLib_Release(tl_struct.ptLib);
3442 msi_free(tl_struct.path);
3444 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3446 FreeLibrary(module);
3447 msi_free(tl_struct.source);
3451 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3454 ERR("Failed to load type library: %08x\n", hr);
3455 return ERROR_INSTALL_FAILURE;
3458 ITypeLib_Release(tlib);
3461 return ERROR_SUCCESS;
3464 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3466 static const WCHAR query[] = {
3467 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3468 '`','T','y','p','e','L','i','b','`',0};
3472 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3473 if (rc != ERROR_SUCCESS)
3474 return ERROR_SUCCESS;
3476 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3477 msiobj_release(&view->hdr);
3481 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3483 MSIPACKAGE *package = param;
3484 LPCWSTR component, guid;
3492 component = MSI_RecordGetString( row, 3 );
3493 comp = msi_get_loaded_component( package, component );
3495 return ERROR_SUCCESS;
3497 comp->Action = msi_get_component_action( package, comp );
3498 if (comp->Action != INSTALLSTATE_ABSENT)
3500 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3501 return ERROR_SUCCESS;
3503 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3505 guid = MSI_RecordGetString( row, 1 );
3506 CLSIDFromString( guid, &libid );
3507 version = MSI_RecordGetInteger( row, 4 );
3508 language = MSI_RecordGetInteger( row, 2 );
3511 syskind = SYS_WIN64;
3513 syskind = SYS_WIN32;
3516 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3519 WARN("Failed to unregister typelib: %08x\n", hr);
3522 return ERROR_SUCCESS;
3525 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3527 static const WCHAR query[] = {
3528 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3529 '`','T','y','p','e','L','i','b','`',0};
3533 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3534 if (rc != ERROR_SUCCESS)
3535 return ERROR_SUCCESS;
3537 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3538 msiobj_release( &view->hdr );
3542 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3544 static const WCHAR szlnk[] = {'.','l','n','k',0};
3545 LPCWSTR directory, extension, link_folder;
3546 LPWSTR link_file, filename;
3548 directory = MSI_RecordGetString( row, 2 );
3549 link_folder = msi_get_target_folder( package, directory );
3552 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3555 /* may be needed because of a bug somewhere else */
3556 msi_create_full_path( link_folder );
3558 filename = msi_dup_record_field( row, 3 );
3559 msi_reduce_to_long_filename( filename );
3561 extension = strchrW( filename, '.' );
3562 if (!extension || strcmpiW( extension, szlnk ))
3564 int len = strlenW( filename );
3565 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3566 memcpy( filename + len, szlnk, sizeof(szlnk) );
3568 link_file = msi_build_directory_name( 2, link_folder, filename );
3569 msi_free( filename );
3574 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3576 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3577 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3578 WCHAR *folder, *dest, *path;
3580 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3581 folder = msi_dup_property( package->db, szWindowsFolder );
3584 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3585 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3586 msi_free( appdata );
3588 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3589 msi_create_full_path( dest );
3590 path = msi_build_directory_name( 2, dest, icon_name );
3596 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3598 MSIPACKAGE *package = param;
3599 LPWSTR link_file, deformated, path;
3600 LPCWSTR component, target;
3602 IShellLinkW *sl = NULL;
3603 IPersistFile *pf = NULL;
3606 component = MSI_RecordGetString(row, 4);
3607 comp = msi_get_loaded_component(package, component);
3609 return ERROR_SUCCESS;
3611 comp->Action = msi_get_component_action( package, comp );
3612 if (comp->Action != INSTALLSTATE_LOCAL)
3614 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3615 return ERROR_SUCCESS;
3617 msi_ui_actiondata( package, szCreateShortcuts, row );
3619 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3620 &IID_IShellLinkW, (LPVOID *) &sl );
3624 ERR("CLSID_ShellLink not available\n");
3628 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3631 ERR("QueryInterface(IID_IPersistFile) failed\n");
3635 target = MSI_RecordGetString(row, 5);
3636 if (strchrW(target, '['))
3638 deformat_string( package, target, &path );
3639 TRACE("target path is %s\n", debugstr_w(path));
3640 IShellLinkW_SetPath( sl, path );
3645 FIXME("poorly handled shortcut format, advertised shortcut\n");
3646 IShellLinkW_SetPath(sl,comp->FullKeypath);
3649 if (!MSI_RecordIsNull(row,6))
3651 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3652 deformat_string(package, arguments, &deformated);
3653 IShellLinkW_SetArguments(sl,deformated);
3654 msi_free(deformated);
3657 if (!MSI_RecordIsNull(row,7))
3659 LPCWSTR description = MSI_RecordGetString(row, 7);
3660 IShellLinkW_SetDescription(sl, description);
3663 if (!MSI_RecordIsNull(row,8))
3664 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3666 if (!MSI_RecordIsNull(row,9))
3669 LPCWSTR icon = MSI_RecordGetString(row, 9);
3671 path = msi_build_icon_path(package, icon);
3672 index = MSI_RecordGetInteger(row,10);
3674 /* no value means 0 */
3675 if (index == MSI_NULL_INTEGER)
3678 IShellLinkW_SetIconLocation(sl, path, index);
3682 if (!MSI_RecordIsNull(row,11))
3683 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3685 if (!MSI_RecordIsNull(row,12))
3687 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3688 full_path = msi_get_target_folder( package, wkdir );
3689 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3691 link_file = get_link_file(package, row);
3693 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3694 IPersistFile_Save(pf, link_file, FALSE);
3695 msi_free(link_file);
3699 IPersistFile_Release( pf );
3701 IShellLinkW_Release( sl );
3703 return ERROR_SUCCESS;
3706 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3708 static const WCHAR query[] = {
3709 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3710 '`','S','h','o','r','t','c','u','t','`',0};
3715 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3716 if (rc != ERROR_SUCCESS)
3717 return ERROR_SUCCESS;
3719 res = CoInitialize( NULL );
3721 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3722 msiobj_release(&view->hdr);
3724 if (SUCCEEDED(res)) CoUninitialize();
3728 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3730 MSIPACKAGE *package = param;
3735 component = MSI_RecordGetString( row, 4 );
3736 comp = msi_get_loaded_component( package, component );
3738 return ERROR_SUCCESS;
3740 comp->Action = msi_get_component_action( package, comp );
3741 if (comp->Action != INSTALLSTATE_ABSENT)
3743 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3744 return ERROR_SUCCESS;
3746 msi_ui_actiondata( package, szRemoveShortcuts, row );
3748 link_file = get_link_file( package, row );
3750 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3751 if (!DeleteFileW( link_file ))
3753 WARN("Failed to remove shortcut file %u\n", GetLastError());
3755 msi_free( link_file );
3757 return ERROR_SUCCESS;
3760 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3762 static const WCHAR query[] = {
3763 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3764 '`','S','h','o','r','t','c','u','t','`',0};
3768 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3769 if (rc != ERROR_SUCCESS)
3770 return ERROR_SUCCESS;
3772 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3773 msiobj_release( &view->hdr );
3777 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3779 MSIPACKAGE* package = param;
3787 FileName = MSI_RecordGetString(row,1);
3790 ERR("Unable to get FileName\n");
3791 return ERROR_SUCCESS;
3794 FilePath = msi_build_icon_path(package, FileName);
3796 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3798 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3799 FILE_ATTRIBUTE_NORMAL, NULL);
3801 if (the_file == INVALID_HANDLE_VALUE)
3803 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3805 return ERROR_SUCCESS;
3812 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3813 if (rc != ERROR_SUCCESS)
3815 ERR("Failed to get stream\n");
3816 CloseHandle(the_file);
3817 DeleteFileW(FilePath);
3820 WriteFile(the_file,buffer,sz,&write,NULL);
3821 } while (sz == 1024);
3824 CloseHandle(the_file);
3826 return ERROR_SUCCESS;
3829 static UINT msi_publish_icons(MSIPACKAGE *package)
3831 static const WCHAR query[]= {
3832 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3833 '`','I','c','o','n','`',0};
3837 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3838 if (r == ERROR_SUCCESS)
3840 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3841 msiobj_release(&view->hdr);
3842 if (r != ERROR_SUCCESS)
3845 return ERROR_SUCCESS;
3848 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3854 MSISOURCELISTINFO *info;
3856 r = RegCreateKeyW(hkey, szSourceList, &source);
3857 if (r != ERROR_SUCCESS)
3860 RegCloseKey(source);
3862 buffer = strrchrW(package->PackagePath, '\\') + 1;
3863 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3864 package->Context, MSICODE_PRODUCT,
3865 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3866 if (r != ERROR_SUCCESS)
3869 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3870 package->Context, MSICODE_PRODUCT,
3871 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3872 if (r != ERROR_SUCCESS)
3875 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3876 package->Context, MSICODE_PRODUCT,
3877 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3878 if (r != ERROR_SUCCESS)
3881 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3883 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3884 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3885 info->options, info->value);
3887 MsiSourceListSetInfoW(package->ProductCode, NULL,
3888 info->context, info->options,
3889 info->property, info->value);
3892 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3894 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3895 disk->context, disk->options,
3896 disk->disk_id, disk->volume_label, disk->disk_prompt);
3899 return ERROR_SUCCESS;
3902 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3904 MSIHANDLE hdb, suminfo;
3905 WCHAR guids[MAX_PATH];
3906 WCHAR packcode[SQUISH_GUID_SIZE];
3913 static const WCHAR szARPProductIcon[] =
3914 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3915 static const WCHAR szAssignment[] =
3916 {'A','s','s','i','g','n','m','e','n','t',0};
3917 static const WCHAR szAdvertiseFlags[] =
3918 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3919 static const WCHAR szClients[] =
3920 {'C','l','i','e','n','t','s',0};
3921 static const WCHAR szColon[] = {':',0};
3923 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3924 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3927 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3928 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3931 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3933 buffer = msi_dup_property(package->db, szARPProductIcon);
3936 LPWSTR path = msi_build_icon_path(package, buffer);
3937 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3942 buffer = msi_dup_property(package->db, szProductVersion);
3945 DWORD verdword = msi_version_str_to_dword(buffer);
3946 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3950 msi_reg_set_val_dword(hkey, szAssignment, 0);
3951 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3952 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3953 msi_reg_set_val_str(hkey, szClients, szColon);
3955 hdb = alloc_msihandle(&package->db->hdr);
3957 return ERROR_NOT_ENOUGH_MEMORY;
3959 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3960 MsiCloseHandle(hdb);
3961 if (r != ERROR_SUCCESS)
3965 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3966 NULL, guids, &size);
3967 if (r != ERROR_SUCCESS)
3970 ptr = strchrW(guids, ';');
3972 squash_guid(guids, packcode);
3973 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3976 MsiCloseHandle(suminfo);
3977 return ERROR_SUCCESS;
3980 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3985 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3987 upgrade = msi_dup_property(package->db, szUpgradeCode);
3989 return ERROR_SUCCESS;
3991 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3992 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3994 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3996 if (r != ERROR_SUCCESS)
3998 WARN("failed to open upgrade code key\n");
4000 return ERROR_SUCCESS;
4002 squash_guid(package->ProductCode, squashed_pc);
4003 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4006 return ERROR_SUCCESS;
4009 static BOOL msi_check_publish(MSIPACKAGE *package)
4011 MSIFEATURE *feature;
4013 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4015 feature->Action = msi_get_feature_action( package, feature );
4016 if (feature->Action == INSTALLSTATE_LOCAL)
4023 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4025 MSIFEATURE *feature;
4027 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4029 feature->Action = msi_get_feature_action( package, feature );
4030 if (feature->Action != INSTALLSTATE_ABSENT)
4037 static UINT msi_publish_patches( MSIPACKAGE *package )
4039 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4040 WCHAR patch_squashed[GUID_SIZE];
4041 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4043 MSIPATCHINFO *patch;
4045 WCHAR *p, *all_patches = NULL;
4048 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4049 if (r != ERROR_SUCCESS)
4050 return ERROR_FUNCTION_FAILED;
4052 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4053 if (res != ERROR_SUCCESS)
4055 r = ERROR_FUNCTION_FAILED;
4059 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4060 if (r != ERROR_SUCCESS)
4063 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4065 squash_guid( patch->patchcode, patch_squashed );
4066 len += strlenW( patch_squashed ) + 1;
4069 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4073 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4077 squash_guid( patch->patchcode, p );
4078 p += strlenW( p ) + 1;
4080 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4081 (const BYTE *)patch->transforms,
4082 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4083 if (res != ERROR_SUCCESS)
4086 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4087 if (r != ERROR_SUCCESS)
4090 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4091 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4092 RegCloseKey( patch_key );
4093 if (res != ERROR_SUCCESS)
4096 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4098 res = GetLastError();
4099 ERR("Unable to copy patch package %d\n", res);
4102 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4103 if (res != ERROR_SUCCESS)
4106 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4107 RegCloseKey( patch_key );
4108 if (res != ERROR_SUCCESS)
4112 all_patches[len] = 0;
4113 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4114 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4115 if (res != ERROR_SUCCESS)
4118 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4119 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4120 if (res != ERROR_SUCCESS)
4121 r = ERROR_FUNCTION_FAILED;
4124 RegCloseKey( product_patches_key );
4125 RegCloseKey( patches_key );
4126 RegCloseKey( product_key );
4127 msi_free( all_patches );
4131 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4134 HKEY hukey = NULL, hudkey = NULL;
4137 if (!list_empty(&package->patches))
4139 rc = msi_publish_patches(package);
4140 if (rc != ERROR_SUCCESS)
4144 /* FIXME: also need to publish if the product is in advertise mode */
4145 if (!msi_check_publish(package))
4146 return ERROR_SUCCESS;
4148 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4150 if (rc != ERROR_SUCCESS)
4153 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4154 NULL, &hudkey, TRUE);
4155 if (rc != ERROR_SUCCESS)
4158 rc = msi_publish_upgrade_code(package);
4159 if (rc != ERROR_SUCCESS)
4162 rc = msi_publish_product_properties(package, hukey);
4163 if (rc != ERROR_SUCCESS)
4166 rc = msi_publish_sourcelist(package, hukey);
4167 if (rc != ERROR_SUCCESS)
4170 rc = msi_publish_icons(package);
4173 uirow = MSI_CreateRecord( 1 );
4174 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4175 msi_ui_actiondata( package, szPublishProduct, uirow );
4176 msiobj_release( &uirow->hdr );
4179 RegCloseKey(hudkey);
4183 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4185 WCHAR *filename, *ptr, *folder, *ret;
4186 const WCHAR *dirprop;
4188 filename = msi_dup_record_field( row, 2 );
4189 if (filename && (ptr = strchrW( filename, '|' )))
4194 dirprop = MSI_RecordGetString( row, 3 );
4197 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4198 if (!folder) folder = msi_dup_property( package->db, dirprop );
4201 folder = msi_dup_property( package->db, szWindowsFolder );
4205 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4206 msi_free( filename );
4210 ret = msi_build_directory_name( 2, folder, ptr );
4212 msi_free( filename );
4217 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4219 MSIPACKAGE *package = param;
4220 LPCWSTR component, section, key, value, identifier;
4221 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4226 component = MSI_RecordGetString(row, 8);
4227 comp = msi_get_loaded_component(package,component);
4229 return ERROR_SUCCESS;
4231 comp->Action = msi_get_component_action( package, comp );
4232 if (comp->Action != INSTALLSTATE_LOCAL)
4234 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4235 return ERROR_SUCCESS;
4238 identifier = MSI_RecordGetString(row,1);
4239 section = MSI_RecordGetString(row,4);
4240 key = MSI_RecordGetString(row,5);
4241 value = MSI_RecordGetString(row,6);
4242 action = MSI_RecordGetInteger(row,7);
4244 deformat_string(package,section,&deformated_section);
4245 deformat_string(package,key,&deformated_key);
4246 deformat_string(package,value,&deformated_value);
4248 fullname = get_ini_file_name(package, row);
4252 TRACE("Adding value %s to section %s in %s\n",
4253 debugstr_w(deformated_key), debugstr_w(deformated_section),
4254 debugstr_w(fullname));
4255 WritePrivateProfileStringW(deformated_section, deformated_key,
4256 deformated_value, fullname);
4258 else if (action == 1)
4261 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4262 returned, 10, fullname);
4263 if (returned[0] == 0)
4265 TRACE("Adding value %s to section %s in %s\n",
4266 debugstr_w(deformated_key), debugstr_w(deformated_section),
4267 debugstr_w(fullname));
4269 WritePrivateProfileStringW(deformated_section, deformated_key,
4270 deformated_value, fullname);
4273 else if (action == 3)
4274 FIXME("Append to existing section not yet implemented\n");
4276 uirow = MSI_CreateRecord(4);
4277 MSI_RecordSetStringW(uirow,1,identifier);
4278 MSI_RecordSetStringW(uirow,2,deformated_section);
4279 MSI_RecordSetStringW(uirow,3,deformated_key);
4280 MSI_RecordSetStringW(uirow,4,deformated_value);
4281 msi_ui_actiondata( package, szWriteIniValues, uirow );
4282 msiobj_release( &uirow->hdr );
4285 msi_free(deformated_key);
4286 msi_free(deformated_value);
4287 msi_free(deformated_section);
4288 return ERROR_SUCCESS;
4291 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4293 static const WCHAR query[] = {
4294 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4295 '`','I','n','i','F','i','l','e','`',0};
4299 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4300 if (rc != ERROR_SUCCESS)
4301 return ERROR_SUCCESS;
4303 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4304 msiobj_release(&view->hdr);
4308 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4310 MSIPACKAGE *package = param;
4311 LPCWSTR component, section, key, value, identifier;
4312 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4317 component = MSI_RecordGetString( row, 8 );
4318 comp = msi_get_loaded_component( package, component );
4320 return ERROR_SUCCESS;
4322 comp->Action = msi_get_component_action( package, comp );
4323 if (comp->Action != INSTALLSTATE_ABSENT)
4325 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4326 return ERROR_SUCCESS;
4329 identifier = MSI_RecordGetString( row, 1 );
4330 section = MSI_RecordGetString( row, 4 );
4331 key = MSI_RecordGetString( row, 5 );
4332 value = MSI_RecordGetString( row, 6 );
4333 action = MSI_RecordGetInteger( row, 7 );
4335 deformat_string( package, section, &deformated_section );
4336 deformat_string( package, key, &deformated_key );
4337 deformat_string( package, value, &deformated_value );
4339 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4341 filename = get_ini_file_name( package, row );
4343 TRACE("Removing key %s from section %s in %s\n",
4344 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4346 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4348 WARN("Unable to remove key %u\n", GetLastError());
4350 msi_free( filename );
4353 FIXME("Unsupported action %d\n", action);
4356 uirow = MSI_CreateRecord( 4 );
4357 MSI_RecordSetStringW( uirow, 1, identifier );
4358 MSI_RecordSetStringW( uirow, 2, deformated_section );
4359 MSI_RecordSetStringW( uirow, 3, deformated_key );
4360 MSI_RecordSetStringW( uirow, 4, deformated_value );
4361 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4362 msiobj_release( &uirow->hdr );
4364 msi_free( deformated_key );
4365 msi_free( deformated_value );
4366 msi_free( deformated_section );
4367 return ERROR_SUCCESS;
4370 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4372 MSIPACKAGE *package = param;
4373 LPCWSTR component, section, key, value, identifier;
4374 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4379 component = MSI_RecordGetString( row, 8 );
4380 comp = msi_get_loaded_component( package, component );
4382 return ERROR_SUCCESS;
4384 comp->Action = msi_get_component_action( package, comp );
4385 if (comp->Action != INSTALLSTATE_LOCAL)
4387 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4388 return ERROR_SUCCESS;
4391 identifier = MSI_RecordGetString( row, 1 );
4392 section = MSI_RecordGetString( row, 4 );
4393 key = MSI_RecordGetString( row, 5 );
4394 value = MSI_RecordGetString( row, 6 );
4395 action = MSI_RecordGetInteger( row, 7 );
4397 deformat_string( package, section, &deformated_section );
4398 deformat_string( package, key, &deformated_key );
4399 deformat_string( package, value, &deformated_value );
4401 if (action == msidbIniFileActionRemoveLine)
4403 filename = get_ini_file_name( package, row );
4405 TRACE("Removing key %s from section %s in %s\n",
4406 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4408 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4410 WARN("Unable to remove key %u\n", GetLastError());
4412 msi_free( filename );
4415 FIXME("Unsupported action %d\n", action);
4417 uirow = MSI_CreateRecord( 4 );
4418 MSI_RecordSetStringW( uirow, 1, identifier );
4419 MSI_RecordSetStringW( uirow, 2, deformated_section );
4420 MSI_RecordSetStringW( uirow, 3, deformated_key );
4421 MSI_RecordSetStringW( uirow, 4, deformated_value );
4422 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4423 msiobj_release( &uirow->hdr );
4425 msi_free( deformated_key );
4426 msi_free( deformated_value );
4427 msi_free( deformated_section );
4428 return ERROR_SUCCESS;
4431 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4433 static const WCHAR query[] = {
4434 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4435 '`','I','n','i','F','i','l','e','`',0};
4436 static const WCHAR remove_query[] = {
4437 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4438 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4442 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4443 if (rc == ERROR_SUCCESS)
4445 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4446 msiobj_release( &view->hdr );
4447 if (rc != ERROR_SUCCESS)
4450 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4451 if (rc == ERROR_SUCCESS)
4453 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4454 msiobj_release( &view->hdr );
4455 if (rc != ERROR_SUCCESS)
4458 return ERROR_SUCCESS;
4461 static void register_dll( const WCHAR *dll, BOOL unregister )
4465 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4468 HRESULT (WINAPI *func_ptr)( void );
4469 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4471 func_ptr = (void *)GetProcAddress( hmod, func );
4474 HRESULT hr = func_ptr();
4476 WARN("failed to register dll 0x%08x\n", hr);
4479 WARN("entry point %s not found\n", func);
4480 FreeLibrary( hmod );
4483 WARN("failed to load library %u\n", GetLastError());
4486 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4488 MSIPACKAGE *package = param;
4493 filename = MSI_RecordGetString( row, 1 );
4494 file = msi_get_loaded_file( package, filename );
4497 WARN("unable to find file %s\n", debugstr_w(filename));
4498 return ERROR_SUCCESS;
4500 file->Component->Action = msi_get_component_action( package, file->Component );
4501 if (file->Component->Action != INSTALLSTATE_LOCAL)
4503 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4504 return ERROR_SUCCESS;
4507 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4508 register_dll( file->TargetPath, FALSE );
4510 uirow = MSI_CreateRecord( 2 );
4511 MSI_RecordSetStringW( uirow, 1, file->File );
4512 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4513 msi_ui_actiondata( package, szSelfRegModules, uirow );
4514 msiobj_release( &uirow->hdr );
4516 return ERROR_SUCCESS;
4519 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4521 static const WCHAR query[] = {
4522 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4523 '`','S','e','l','f','R','e','g','`',0};
4527 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4528 if (rc != ERROR_SUCCESS)
4529 return ERROR_SUCCESS;
4531 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4532 msiobj_release(&view->hdr);
4536 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4538 MSIPACKAGE *package = param;
4543 filename = MSI_RecordGetString( row, 1 );
4544 file = msi_get_loaded_file( package, filename );
4547 WARN("unable to find file %s\n", debugstr_w(filename));
4548 return ERROR_SUCCESS;
4550 file->Component->Action = msi_get_component_action( package, file->Component );
4551 if (file->Component->Action != INSTALLSTATE_ABSENT)
4553 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4554 return ERROR_SUCCESS;
4557 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4558 register_dll( file->TargetPath, TRUE );
4560 uirow = MSI_CreateRecord( 2 );
4561 MSI_RecordSetStringW( uirow, 1, file->File );
4562 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4563 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4564 msiobj_release( &uirow->hdr );
4566 return ERROR_SUCCESS;
4569 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4571 static const WCHAR query[] = {
4572 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4573 '`','S','e','l','f','R','e','g','`',0};
4577 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4578 if (rc != ERROR_SUCCESS)
4579 return ERROR_SUCCESS;
4581 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4582 msiobj_release( &view->hdr );
4586 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4588 MSIFEATURE *feature;
4590 HKEY hkey = NULL, userdata = NULL;
4592 if (!msi_check_publish(package))
4593 return ERROR_SUCCESS;
4595 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4597 if (rc != ERROR_SUCCESS)
4600 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4602 if (rc != ERROR_SUCCESS)
4605 /* here the guids are base 85 encoded */
4606 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4612 BOOL absent = FALSE;
4615 if (feature->Action != INSTALLSTATE_LOCAL &&
4616 feature->Action != INSTALLSTATE_SOURCE &&
4617 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4620 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4624 if (feature->Feature_Parent)
4625 size += strlenW( feature->Feature_Parent )+2;
4627 data = msi_alloc(size * sizeof(WCHAR));
4630 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4632 MSICOMPONENT* component = cl->component;
4636 if (component->ComponentId)
4638 TRACE("From %s\n",debugstr_w(component->ComponentId));
4639 CLSIDFromString(component->ComponentId, &clsid);
4640 encode_base85_guid(&clsid,buf);
4641 TRACE("to %s\n",debugstr_w(buf));
4646 if (feature->Feature_Parent)
4648 static const WCHAR sep[] = {'\2',0};
4650 strcatW(data,feature->Feature_Parent);
4653 msi_reg_set_val_str( userdata, feature->Feature, data );
4657 if (feature->Feature_Parent)
4658 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4661 size += sizeof(WCHAR);
4662 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4663 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4667 size += 2*sizeof(WCHAR);
4668 data = msi_alloc(size);
4671 if (feature->Feature_Parent)
4672 strcpyW( &data[1], feature->Feature_Parent );
4673 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4679 uirow = MSI_CreateRecord( 1 );
4680 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4681 msi_ui_actiondata( package, szPublishFeatures, uirow );
4682 msiobj_release( &uirow->hdr );
4683 /* FIXME: call msi_ui_progress? */
4688 RegCloseKey(userdata);
4692 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4698 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4700 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4702 if (r == ERROR_SUCCESS)
4704 RegDeleteValueW(hkey, feature->Feature);
4708 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4710 if (r == ERROR_SUCCESS)
4712 RegDeleteValueW(hkey, feature->Feature);
4716 uirow = MSI_CreateRecord( 1 );
4717 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4718 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4719 msiobj_release( &uirow->hdr );
4721 return ERROR_SUCCESS;
4724 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4726 MSIFEATURE *feature;
4728 if (!msi_check_unpublish(package))
4729 return ERROR_SUCCESS;
4731 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4733 msi_unpublish_feature(package, feature);
4736 return ERROR_SUCCESS;
4739 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4743 WCHAR date[9], *val, *buffer;
4744 const WCHAR *prop, *key;
4746 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4747 static const WCHAR modpath_fmt[] =
4748 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4749 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4750 static const WCHAR szModifyPath[] =
4751 {'M','o','d','i','f','y','P','a','t','h',0};
4752 static const WCHAR szUninstallString[] =
4753 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4754 static const WCHAR szEstimatedSize[] =
4755 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4756 static const WCHAR szDisplayVersion[] =
4757 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4758 static const WCHAR szInstallSource[] =
4759 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4760 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4761 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4762 static const WCHAR szAuthorizedCDFPrefix[] =
4763 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4764 static const WCHAR szARPCONTACT[] =
4765 {'A','R','P','C','O','N','T','A','C','T',0};
4766 static const WCHAR szContact[] =
4767 {'C','o','n','t','a','c','t',0};
4768 static const WCHAR szARPCOMMENTS[] =
4769 {'A','R','P','C','O','M','M','E','N','T','S',0};
4770 static const WCHAR szComments[] =
4771 {'C','o','m','m','e','n','t','s',0};
4772 static const WCHAR szProductName[] =
4773 {'P','r','o','d','u','c','t','N','a','m','e',0};
4774 static const WCHAR szDisplayName[] =
4775 {'D','i','s','p','l','a','y','N','a','m','e',0};
4776 static const WCHAR szARPHELPLINK[] =
4777 {'A','R','P','H','E','L','P','L','I','N','K',0};
4778 static const WCHAR szHelpLink[] =
4779 {'H','e','l','p','L','i','n','k',0};
4780 static const WCHAR szARPHELPTELEPHONE[] =
4781 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4782 static const WCHAR szHelpTelephone[] =
4783 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4784 static const WCHAR szARPINSTALLLOCATION[] =
4785 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4786 static const WCHAR szInstallLocation[] =
4787 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4788 static const WCHAR szManufacturer[] =
4789 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4790 static const WCHAR szPublisher[] =
4791 {'P','u','b','l','i','s','h','e','r',0};
4792 static const WCHAR szARPREADME[] =
4793 {'A','R','P','R','E','A','D','M','E',0};
4794 static const WCHAR szReadme[] =
4795 {'R','e','a','d','M','e',0};
4796 static const WCHAR szARPSIZE[] =
4797 {'A','R','P','S','I','Z','E',0};
4798 static const WCHAR szSize[] =
4799 {'S','i','z','e',0};
4800 static const WCHAR szARPURLINFOABOUT[] =
4801 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4802 static const WCHAR szURLInfoAbout[] =
4803 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4804 static const WCHAR szARPURLUPDATEINFO[] =
4805 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4806 static const WCHAR szURLUpdateInfo[] =
4807 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4808 static const WCHAR szARPSYSTEMCOMPONENT[] =
4809 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4810 static const WCHAR szSystemComponent[] =
4811 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4813 static const WCHAR *propval[] = {
4814 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4815 szARPCONTACT, szContact,
4816 szARPCOMMENTS, szComments,
4817 szProductName, szDisplayName,
4818 szARPHELPLINK, szHelpLink,
4819 szARPHELPTELEPHONE, szHelpTelephone,
4820 szARPINSTALLLOCATION, szInstallLocation,
4821 szSourceDir, szInstallSource,
4822 szManufacturer, szPublisher,
4823 szARPREADME, szReadme,
4825 szARPURLINFOABOUT, szURLInfoAbout,
4826 szARPURLUPDATEINFO, szURLUpdateInfo,
4829 const WCHAR **p = propval;
4835 val = msi_dup_property(package->db, prop);
4836 msi_reg_set_val_str(hkey, key, val);
4840 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4841 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4843 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4845 size = deformat_string(package, modpath_fmt, &buffer);
4846 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4847 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4850 /* FIXME: Write real Estimated Size when we have it */
4851 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4853 GetLocalTime(&systime);
4854 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4855 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4857 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4858 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4860 buffer = msi_dup_property(package->db, szProductVersion);
4861 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4864 DWORD verdword = msi_version_str_to_dword(buffer);
4866 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4867 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4868 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4872 return ERROR_SUCCESS;
4875 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4877 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4879 LPWSTR upgrade_code;
4880 HKEY hkey, props, upgrade_key;
4883 /* FIXME: also need to publish if the product is in advertise mode */
4884 if (!msi_check_publish(package))
4885 return ERROR_SUCCESS;
4887 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4888 if (rc != ERROR_SUCCESS)
4891 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4892 if (rc != ERROR_SUCCESS)
4895 rc = msi_publish_install_properties(package, hkey);
4896 if (rc != ERROR_SUCCESS)
4899 rc = msi_publish_install_properties(package, props);
4900 if (rc != ERROR_SUCCESS)
4903 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4906 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4907 if (rc == ERROR_SUCCESS)
4909 squash_guid( package->ProductCode, squashed_pc );
4910 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4911 RegCloseKey( upgrade_key );
4913 msi_free( upgrade_code );
4915 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4916 package->delete_on_close = FALSE;
4919 uirow = MSI_CreateRecord( 1 );
4920 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4921 msi_ui_actiondata( package, szRegisterProduct, uirow );
4922 msiobj_release( &uirow->hdr );
4925 return ERROR_SUCCESS;
4928 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4930 return execute_script(package, SCRIPT_INSTALL);
4933 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4935 MSIPACKAGE *package = param;
4936 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4937 WCHAR *p, *icon_path;
4939 if (!icon) return ERROR_SUCCESS;
4940 if ((icon_path = msi_build_icon_path( package, icon )))
4942 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4943 DeleteFileW( icon_path );
4944 if ((p = strrchrW( icon_path, '\\' )))
4947 RemoveDirectoryW( icon_path );
4949 msi_free( icon_path );
4951 return ERROR_SUCCESS;
4954 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4956 static const WCHAR query[]= {
4957 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4961 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4962 if (r == ERROR_SUCCESS)
4964 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4965 msiobj_release( &view->hdr );
4966 if (r != ERROR_SUCCESS)
4969 return ERROR_SUCCESS;
4972 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4974 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4975 WCHAR *upgrade, **features;
4976 BOOL full_uninstall = TRUE;
4977 MSIFEATURE *feature;
4978 MSIPATCHINFO *patch;
4981 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4983 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4985 features = msi_split_string( remove, ',' );
4986 for (i = 0; features && features[i]; i++)
4988 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4992 if (!full_uninstall)
4993 return ERROR_SUCCESS;
4995 MSIREG_DeleteProductKey(package->ProductCode);
4996 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4997 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4999 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5000 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5001 MSIREG_DeleteUserProductKey(package->ProductCode);
5002 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5004 upgrade = msi_dup_property(package->db, szUpgradeCode);
5007 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5008 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5012 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5014 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5015 if (!strcmpW( package->ProductCode, patch->products ))
5017 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5018 patch->delete_on_close = TRUE;
5020 /* FIXME: remove local patch package if this is the last product */
5022 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5023 package->delete_on_close = TRUE;
5025 msi_unpublish_icons( package );
5026 return ERROR_SUCCESS;
5029 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5034 /* turn off scheduling */
5035 package->script->CurrentlyScripting= FALSE;
5037 /* first do the same as an InstallExecute */
5038 rc = ACTION_InstallExecute(package);
5039 if (rc != ERROR_SUCCESS)
5042 /* then handle commit actions */
5043 rc = execute_script(package, SCRIPT_COMMIT);
5044 if (rc != ERROR_SUCCESS)
5047 remove = msi_dup_property(package->db, szRemove);
5048 rc = msi_unpublish_product(package, remove);
5053 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5055 static const WCHAR RunOnce[] = {
5056 'S','o','f','t','w','a','r','e','\\',
5057 'M','i','c','r','o','s','o','f','t','\\',
5058 'W','i','n','d','o','w','s','\\',
5059 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5060 'R','u','n','O','n','c','e',0};
5061 static const WCHAR InstallRunOnce[] = {
5062 'S','o','f','t','w','a','r','e','\\',
5063 'M','i','c','r','o','s','o','f','t','\\',
5064 'W','i','n','d','o','w','s','\\',
5065 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5066 'I','n','s','t','a','l','l','e','r','\\',
5067 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5069 static const WCHAR msiexec_fmt[] = {
5071 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5072 '\"','%','s','\"',0};
5073 static const WCHAR install_fmt[] = {
5074 '/','I',' ','\"','%','s','\"',' ',
5075 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5076 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5077 WCHAR buffer[256], sysdir[MAX_PATH];
5079 WCHAR squished_pc[100];
5081 squash_guid(package->ProductCode,squished_pc);
5083 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5084 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5085 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5088 msi_reg_set_val_str( hkey, squished_pc, buffer );
5091 TRACE("Reboot command %s\n",debugstr_w(buffer));
5093 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5094 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5096 msi_reg_set_val_str( hkey, squished_pc, buffer );
5099 return ERROR_INSTALL_SUSPEND;
5102 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5104 static const WCHAR query[] =
5105 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5106 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5107 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5108 MSIRECORD *rec, *row;
5114 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5116 rec = MSI_CreateRecord( count + 2 );
5117 str = MSI_RecordGetString( row, 1 );
5118 MSI_RecordSetStringW( rec, 0, str );
5119 msiobj_release( &row->hdr );
5120 MSI_RecordSetInteger( rec, 1, error );
5122 va_start( va, count );
5123 for (i = 0; i < count; i++)
5125 str = va_arg( va, const WCHAR *);
5126 MSI_RecordSetStringW( rec, i + 2, str );
5130 MSI_FormatRecordW( package, rec, NULL, &size );
5132 data = msi_alloc( size * sizeof(WCHAR) );
5133 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5135 msiobj_release( &rec->hdr );
5139 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5145 * We are currently doing what should be done here in the top level Install
5146 * however for Administrative and uninstalls this step will be needed
5148 if (!package->PackagePath)
5149 return ERROR_SUCCESS;
5151 msi_set_sourcedir_props(package, TRUE);
5153 attrib = GetFileAttributesW(package->db->path);
5154 if (attrib == INVALID_FILE_ATTRIBUTES)
5159 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5160 package->Context, MSICODE_PRODUCT,
5161 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5162 if (rc == ERROR_MORE_DATA)
5164 prompt = msi_alloc(size * sizeof(WCHAR));
5165 MsiSourceListGetInfoW(package->ProductCode, NULL,
5166 package->Context, MSICODE_PRODUCT,
5167 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5170 prompt = strdupW(package->db->path);
5172 msg = msi_build_error_string(package, 1302, 1, prompt);
5174 while(attrib == INVALID_FILE_ATTRIBUTES)
5176 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5180 return ERROR_INSTALL_USEREXIT;
5182 attrib = GetFileAttributesW(package->db->path);
5188 return ERROR_SUCCESS;
5193 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5196 LPWSTR buffer, productid = NULL;
5197 UINT i, rc = ERROR_SUCCESS;
5200 static const WCHAR szPropKeys[][80] =
5202 {'P','r','o','d','u','c','t','I','D',0},
5203 {'U','S','E','R','N','A','M','E',0},
5204 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5208 static const WCHAR szRegKeys[][80] =
5210 {'P','r','o','d','u','c','t','I','D',0},
5211 {'R','e','g','O','w','n','e','r',0},
5212 {'R','e','g','C','o','m','p','a','n','y',0},
5216 if (msi_check_unpublish(package))
5218 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5222 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5226 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5228 if (rc != ERROR_SUCCESS)
5231 for( i = 0; szPropKeys[i][0]; i++ )
5233 buffer = msi_dup_property( package->db, szPropKeys[i] );
5234 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5239 uirow = MSI_CreateRecord( 1 );
5240 MSI_RecordSetStringW( uirow, 1, productid );
5241 msi_ui_actiondata( package, szRegisterUser, uirow );
5242 msiobj_release( &uirow->hdr );
5244 msi_free(productid);
5250 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5254 package->script->InWhatSequence |= SEQUENCE_EXEC;
5255 rc = ACTION_ProcessExecSequence(package,FALSE);
5259 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5261 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5262 WCHAR productid_85[21], component_85[21], *ret;
5266 /* > is used if there is a component GUID and < if not. */
5268 productid_85[0] = 0;
5269 component_85[0] = 0;
5270 CLSIDFromString( package->ProductCode, &clsid );
5272 encode_base85_guid( &clsid, productid_85 );
5275 CLSIDFromString( component->ComponentId, &clsid );
5276 encode_base85_guid( &clsid, component_85 );
5279 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5280 debugstr_w(component_85));
5282 sz = 20 + strlenW( feature ) + 20 + 3;
5283 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5284 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5288 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5290 MSIPACKAGE *package = param;
5291 LPCWSTR compgroupid, component, feature, qualifier, text;
5292 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5301 feature = MSI_RecordGetString(rec, 5);
5302 feat = msi_get_loaded_feature(package, feature);
5304 return ERROR_SUCCESS;
5306 feat->Action = msi_get_feature_action( package, feat );
5307 if (feat->Action != INSTALLSTATE_LOCAL &&
5308 feat->Action != INSTALLSTATE_SOURCE &&
5309 feat->Action != INSTALLSTATE_ADVERTISED)
5311 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5312 return ERROR_SUCCESS;
5315 component = MSI_RecordGetString(rec, 3);
5316 comp = msi_get_loaded_component(package, component);
5318 return ERROR_SUCCESS;
5320 compgroupid = MSI_RecordGetString(rec,1);
5321 qualifier = MSI_RecordGetString(rec,2);
5323 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5324 if (rc != ERROR_SUCCESS)
5327 advertise = msi_create_component_advertise_string( package, comp, feature );
5328 text = MSI_RecordGetString( rec, 4 );
5331 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5332 strcpyW( p, advertise );
5334 msi_free( advertise );
5337 existing = msi_reg_get_val_str( hkey, qualifier );
5339 sz = strlenW( advertise ) + 1;
5342 for (p = existing; *p; p += len)
5344 len = strlenW( p ) + 1;
5345 if (strcmpW( advertise, p )) sz += len;
5348 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5350 rc = ERROR_OUTOFMEMORY;
5356 for (p = existing; *p; p += len)
5358 len = strlenW( p ) + 1;
5359 if (strcmpW( advertise, p ))
5361 memcpy( q, p, len * sizeof(WCHAR) );
5366 strcpyW( q, advertise );
5367 q[strlenW( q ) + 1] = 0;
5369 msi_reg_set_val_multi_str( hkey, qualifier, output );
5374 msi_free( advertise );
5375 msi_free( existing );
5378 uirow = MSI_CreateRecord( 2 );
5379 MSI_RecordSetStringW( uirow, 1, compgroupid );
5380 MSI_RecordSetStringW( uirow, 2, qualifier);
5381 msi_ui_actiondata( package, szPublishComponents, uirow );
5382 msiobj_release( &uirow->hdr );
5383 /* FIXME: call ui_progress? */
5389 * At present I am ignorning the advertised components part of this and only
5390 * focusing on the qualified component sets
5392 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5394 static const WCHAR query[] = {
5395 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5396 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5400 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5401 if (rc != ERROR_SUCCESS)
5402 return ERROR_SUCCESS;
5404 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5405 msiobj_release(&view->hdr);
5409 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5411 static const WCHAR szInstallerComponents[] = {
5412 'S','o','f','t','w','a','r','e','\\',
5413 'M','i','c','r','o','s','o','f','t','\\',
5414 'I','n','s','t','a','l','l','e','r','\\',
5415 'C','o','m','p','o','n','e','n','t','s','\\',0};
5417 MSIPACKAGE *package = param;
5418 LPCWSTR compgroupid, component, feature, qualifier;
5422 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5425 feature = MSI_RecordGetString( rec, 5 );
5426 feat = msi_get_loaded_feature( package, feature );
5428 return ERROR_SUCCESS;
5430 feat->Action = msi_get_feature_action( package, feat );
5431 if (feat->Action != INSTALLSTATE_ABSENT)
5433 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5434 return ERROR_SUCCESS;
5437 component = MSI_RecordGetString( rec, 3 );
5438 comp = msi_get_loaded_component( package, component );
5440 return ERROR_SUCCESS;
5442 compgroupid = MSI_RecordGetString( rec, 1 );
5443 qualifier = MSI_RecordGetString( rec, 2 );
5445 squash_guid( compgroupid, squashed );
5446 strcpyW( keypath, szInstallerComponents );
5447 strcatW( keypath, squashed );
5449 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5450 if (res != ERROR_SUCCESS)
5452 WARN("Unable to delete component key %d\n", res);
5455 uirow = MSI_CreateRecord( 2 );
5456 MSI_RecordSetStringW( uirow, 1, compgroupid );
5457 MSI_RecordSetStringW( uirow, 2, qualifier );
5458 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5459 msiobj_release( &uirow->hdr );
5461 return ERROR_SUCCESS;
5464 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5466 static const WCHAR query[] = {
5467 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5468 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5472 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5473 if (rc != ERROR_SUCCESS)
5474 return ERROR_SUCCESS;
5476 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5477 msiobj_release( &view->hdr );
5481 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5483 static const WCHAR query[] =
5484 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5485 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5486 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5487 MSIPACKAGE *package = param;
5488 MSICOMPONENT *component;
5491 SC_HANDLE hscm = NULL, service = NULL;
5493 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5494 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5495 DWORD serv_type, start_type, err_control;
5496 SERVICE_DESCRIPTIONW sd = {NULL};
5498 comp = MSI_RecordGetString( rec, 12 );
5499 component = msi_get_loaded_component( package, comp );
5502 WARN("service component not found\n");
5505 component->Action = msi_get_component_action( package, component );
5506 if (component->Action != INSTALLSTATE_LOCAL)
5508 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5511 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5514 ERR("Failed to open the SC Manager!\n");
5518 start_type = MSI_RecordGetInteger(rec, 5);
5519 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5522 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5523 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5524 serv_type = MSI_RecordGetInteger(rec, 4);
5525 err_control = MSI_RecordGetInteger(rec, 6);
5526 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5527 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5528 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5529 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5530 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5531 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5533 /* fetch the service path */
5534 row = MSI_QueryGetRecord(package->db, query, comp);
5537 ERR("Query failed\n");
5540 key = MSI_RecordGetString(row, 6);
5541 file = msi_get_loaded_file(package, key);
5542 msiobj_release(&row->hdr);
5545 ERR("Failed to load the service file\n");
5549 if (!args || !args[0]) image_path = file->TargetPath;
5552 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5553 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5554 return ERROR_OUTOFMEMORY;
5556 strcpyW(image_path, file->TargetPath);
5557 strcatW(image_path, szSpace);
5558 strcatW(image_path, args);
5560 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5561 start_type, err_control, image_path, load_order,
5562 NULL, depends, serv_name, pass);
5566 if (GetLastError() != ERROR_SERVICE_EXISTS)
5567 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5569 else if (sd.lpDescription)
5571 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5572 WARN("failed to set service description %u\n", GetLastError());
5575 if (image_path != file->TargetPath) msi_free(image_path);
5577 CloseServiceHandle(service);
5578 CloseServiceHandle(hscm);
5581 msi_free(sd.lpDescription);
5582 msi_free(load_order);
5583 msi_free(serv_name);
5588 return ERROR_SUCCESS;
5591 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5593 static const WCHAR query[] = {
5594 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5595 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5599 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5600 if (rc != ERROR_SUCCESS)
5601 return ERROR_SUCCESS;
5603 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5604 msiobj_release(&view->hdr);
5608 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5609 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5611 LPCWSTR *vector, *temp_vector;
5615 static const WCHAR separator[] = {'[','~',']',0};
5618 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5623 vector = msi_alloc(sizeof(LPWSTR));
5631 vector[*numargs - 1] = p;
5633 if ((q = strstrW(p, separator)))
5637 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5643 vector = temp_vector;
5652 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5654 MSIPACKAGE *package = param;
5657 SC_HANDLE scm = NULL, service = NULL;
5658 LPCWSTR component, *vector = NULL;
5659 LPWSTR name, args, display_name = NULL;
5660 DWORD event, numargs, len, wait, dummy;
5661 UINT r = ERROR_FUNCTION_FAILED;
5662 SERVICE_STATUS_PROCESS status;
5663 ULONGLONG start_time;
5665 component = MSI_RecordGetString(rec, 6);
5666 comp = msi_get_loaded_component(package, component);
5668 return ERROR_SUCCESS;
5670 comp->Action = msi_get_component_action( package, comp );
5671 if (comp->Action != INSTALLSTATE_LOCAL)
5673 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5674 return ERROR_SUCCESS;
5677 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5678 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5679 event = MSI_RecordGetInteger(rec, 3);
5680 wait = MSI_RecordGetInteger(rec, 5);
5682 if (!(event & msidbServiceControlEventStart))
5688 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5691 ERR("Failed to open the service control manager\n");
5696 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5697 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5699 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5700 GetServiceDisplayNameW( scm, name, display_name, &len );
5703 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5706 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5710 vector = msi_service_args_to_vector(args, &numargs);
5712 if (!StartServiceW(service, numargs, vector) &&
5713 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5715 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5722 /* wait for at most 30 seconds for the service to be up and running */
5723 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5724 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5726 TRACE("failed to query service status (%u)\n", GetLastError());
5729 start_time = GetTickCount64();
5730 while (status.dwCurrentState == SERVICE_START_PENDING)
5732 if (GetTickCount64() - start_time > 30000) break;
5734 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5735 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5737 TRACE("failed to query service status (%u)\n", GetLastError());
5741 if (status.dwCurrentState != SERVICE_RUNNING)
5743 WARN("service failed to start %u\n", status.dwCurrentState);
5744 r = ERROR_FUNCTION_FAILED;
5749 uirow = MSI_CreateRecord( 2 );
5750 MSI_RecordSetStringW( uirow, 1, display_name );
5751 MSI_RecordSetStringW( uirow, 2, name );
5752 msi_ui_actiondata( package, szStartServices, uirow );
5753 msiobj_release( &uirow->hdr );
5755 CloseServiceHandle(service);
5756 CloseServiceHandle(scm);
5761 msi_free(display_name);
5765 static UINT ACTION_StartServices( MSIPACKAGE *package )
5767 static const WCHAR query[] = {
5768 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5769 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5773 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5774 if (rc != ERROR_SUCCESS)
5775 return ERROR_SUCCESS;
5777 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5778 msiobj_release(&view->hdr);
5782 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5784 DWORD i, needed, count;
5785 ENUM_SERVICE_STATUSW *dependencies;
5789 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5790 0, &needed, &count))
5793 if (GetLastError() != ERROR_MORE_DATA)
5796 dependencies = msi_alloc(needed);
5800 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5801 needed, &needed, &count))
5804 for (i = 0; i < count; i++)
5806 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5807 SERVICE_STOP | SERVICE_QUERY_STATUS);
5811 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5818 msi_free(dependencies);
5822 static UINT stop_service( LPCWSTR name )
5824 SC_HANDLE scm = NULL, service = NULL;
5825 SERVICE_STATUS status;
5826 SERVICE_STATUS_PROCESS ssp;
5829 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5832 WARN("Failed to open the SCM: %d\n", GetLastError());
5836 service = OpenServiceW(scm, name,
5838 SERVICE_QUERY_STATUS |
5839 SERVICE_ENUMERATE_DEPENDENTS);
5842 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5846 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5847 sizeof(SERVICE_STATUS_PROCESS), &needed))
5849 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5853 if (ssp.dwCurrentState == SERVICE_STOPPED)
5856 stop_service_dependents(scm, service);
5858 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5859 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5862 CloseServiceHandle(service);
5863 CloseServiceHandle(scm);
5865 return ERROR_SUCCESS;
5868 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5870 MSIPACKAGE *package = param;
5874 LPWSTR name = NULL, display_name = NULL;
5878 event = MSI_RecordGetInteger( rec, 3 );
5879 if (!(event & msidbServiceControlEventStop))
5880 return ERROR_SUCCESS;
5882 component = MSI_RecordGetString( rec, 6 );
5883 comp = msi_get_loaded_component( package, component );
5885 return ERROR_SUCCESS;
5887 comp->Action = msi_get_component_action( package, comp );
5888 if (comp->Action != INSTALLSTATE_ABSENT)
5890 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5891 return ERROR_SUCCESS;
5894 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5897 ERR("Failed to open the service control manager\n");
5902 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5903 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5905 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5906 GetServiceDisplayNameW( scm, name, display_name, &len );
5908 CloseServiceHandle( scm );
5910 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5911 stop_service( name );
5914 uirow = MSI_CreateRecord( 2 );
5915 MSI_RecordSetStringW( uirow, 1, display_name );
5916 MSI_RecordSetStringW( uirow, 2, name );
5917 msi_ui_actiondata( package, szStopServices, uirow );
5918 msiobj_release( &uirow->hdr );
5921 msi_free( display_name );
5922 return ERROR_SUCCESS;
5925 static UINT ACTION_StopServices( MSIPACKAGE *package )
5927 static const WCHAR query[] = {
5928 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5929 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5933 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5934 if (rc != ERROR_SUCCESS)
5935 return ERROR_SUCCESS;
5937 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5938 msiobj_release(&view->hdr);
5942 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5944 MSIPACKAGE *package = param;
5947 LPWSTR name = NULL, display_name = NULL;
5949 SC_HANDLE scm = NULL, service = NULL;
5951 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5953 return ERROR_SUCCESS;
5955 event = MSI_RecordGetInteger( rec, 3 );
5956 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5958 comp->Action = msi_get_component_action( package, comp );
5959 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5960 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5962 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5964 return ERROR_SUCCESS;
5966 stop_service( name );
5968 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5971 WARN("Failed to open the SCM: %d\n", GetLastError());
5976 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5977 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5979 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5980 GetServiceDisplayNameW( scm, name, display_name, &len );
5983 service = OpenServiceW( scm, name, DELETE );
5986 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5990 if (!DeleteService( service ))
5991 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5994 uirow = MSI_CreateRecord( 2 );
5995 MSI_RecordSetStringW( uirow, 1, display_name );
5996 MSI_RecordSetStringW( uirow, 2, name );
5997 msi_ui_actiondata( package, szDeleteServices, uirow );
5998 msiobj_release( &uirow->hdr );
6000 CloseServiceHandle( service );
6001 CloseServiceHandle( scm );
6003 msi_free( display_name );
6005 return ERROR_SUCCESS;
6008 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6010 static const WCHAR query[] = {
6011 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6012 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6016 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6017 if (rc != ERROR_SUCCESS)
6018 return ERROR_SUCCESS;
6020 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6021 msiobj_release( &view->hdr );
6025 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6027 MSIPACKAGE *package = param;
6028 LPWSTR driver, driver_path, ptr;
6029 WCHAR outpath[MAX_PATH];
6030 MSIFILE *driver_file = NULL, *setup_file = NULL;
6033 LPCWSTR desc, file_key, component;
6035 UINT r = ERROR_SUCCESS;
6037 static const WCHAR driver_fmt[] = {
6038 'D','r','i','v','e','r','=','%','s',0};
6039 static const WCHAR setup_fmt[] = {
6040 'S','e','t','u','p','=','%','s',0};
6041 static const WCHAR usage_fmt[] = {
6042 'F','i','l','e','U','s','a','g','e','=','1',0};
6044 component = MSI_RecordGetString( rec, 2 );
6045 comp = msi_get_loaded_component( package, component );
6047 return ERROR_SUCCESS;
6049 comp->Action = msi_get_component_action( package, comp );
6050 if (comp->Action != INSTALLSTATE_LOCAL)
6052 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6053 return ERROR_SUCCESS;
6055 desc = MSI_RecordGetString(rec, 3);
6057 file_key = MSI_RecordGetString( rec, 4 );
6058 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6060 file_key = MSI_RecordGetString( rec, 5 );
6061 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6065 ERR("ODBC Driver entry not found!\n");
6066 return ERROR_FUNCTION_FAILED;
6069 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6071 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6072 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6074 driver = msi_alloc(len * sizeof(WCHAR));
6076 return ERROR_OUTOFMEMORY;
6079 lstrcpyW(ptr, desc);
6080 ptr += lstrlenW(ptr) + 1;
6082 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6087 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6091 lstrcpyW(ptr, usage_fmt);
6092 ptr += lstrlenW(ptr) + 1;
6095 if (!driver_file->TargetPath)
6097 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6098 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6100 driver_path = strdupW(driver_file->TargetPath);
6101 ptr = strrchrW(driver_path, '\\');
6102 if (ptr) *ptr = '\0';
6104 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6105 NULL, ODBC_INSTALL_COMPLETE, &usage))
6107 ERR("Failed to install SQL driver!\n");
6108 r = ERROR_FUNCTION_FAILED;
6111 uirow = MSI_CreateRecord( 5 );
6112 MSI_RecordSetStringW( uirow, 1, desc );
6113 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6114 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6115 msi_ui_actiondata( package, szInstallODBC, uirow );
6116 msiobj_release( &uirow->hdr );
6119 msi_free(driver_path);
6124 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6126 MSIPACKAGE *package = param;
6127 LPWSTR translator, translator_path, ptr;
6128 WCHAR outpath[MAX_PATH];
6129 MSIFILE *translator_file = NULL, *setup_file = NULL;
6132 LPCWSTR desc, file_key, component;
6134 UINT r = ERROR_SUCCESS;
6136 static const WCHAR translator_fmt[] = {
6137 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6138 static const WCHAR setup_fmt[] = {
6139 'S','e','t','u','p','=','%','s',0};
6141 component = MSI_RecordGetString( rec, 2 );
6142 comp = msi_get_loaded_component( package, component );
6144 return ERROR_SUCCESS;
6146 comp->Action = msi_get_component_action( package, comp );
6147 if (comp->Action != INSTALLSTATE_LOCAL)
6149 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6150 return ERROR_SUCCESS;
6152 desc = MSI_RecordGetString(rec, 3);
6154 file_key = MSI_RecordGetString( rec, 4 );
6155 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6157 file_key = MSI_RecordGetString( rec, 5 );
6158 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6160 if (!translator_file)
6162 ERR("ODBC Translator entry not found!\n");
6163 return ERROR_FUNCTION_FAILED;
6166 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6168 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6170 translator = msi_alloc(len * sizeof(WCHAR));
6172 return ERROR_OUTOFMEMORY;
6175 lstrcpyW(ptr, desc);
6176 ptr += lstrlenW(ptr) + 1;
6178 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6183 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6188 translator_path = strdupW(translator_file->TargetPath);
6189 ptr = strrchrW(translator_path, '\\');
6190 if (ptr) *ptr = '\0';
6192 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6193 NULL, ODBC_INSTALL_COMPLETE, &usage))
6195 ERR("Failed to install SQL translator!\n");
6196 r = ERROR_FUNCTION_FAILED;
6199 uirow = MSI_CreateRecord( 5 );
6200 MSI_RecordSetStringW( uirow, 1, desc );
6201 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6202 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6203 msi_ui_actiondata( package, szInstallODBC, uirow );
6204 msiobj_release( &uirow->hdr );
6206 msi_free(translator);
6207 msi_free(translator_path);
6212 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6214 MSIPACKAGE *package = param;
6217 LPCWSTR desc, driver, component;
6218 WORD request = ODBC_ADD_SYS_DSN;
6221 UINT r = ERROR_SUCCESS;
6224 static const WCHAR attrs_fmt[] = {
6225 'D','S','N','=','%','s',0 };
6227 component = MSI_RecordGetString( rec, 2 );
6228 comp = msi_get_loaded_component( package, component );
6230 return ERROR_SUCCESS;
6232 comp->Action = msi_get_component_action( package, comp );
6233 if (comp->Action != INSTALLSTATE_LOCAL)
6235 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6236 return ERROR_SUCCESS;
6239 desc = MSI_RecordGetString(rec, 3);
6240 driver = MSI_RecordGetString(rec, 4);
6241 registration = MSI_RecordGetInteger(rec, 5);
6243 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6244 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6246 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6247 attrs = msi_alloc(len * sizeof(WCHAR));
6249 return ERROR_OUTOFMEMORY;
6251 len = sprintfW(attrs, attrs_fmt, desc);
6254 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6256 ERR("Failed to install SQL data source!\n");
6257 r = ERROR_FUNCTION_FAILED;
6260 uirow = MSI_CreateRecord( 5 );
6261 MSI_RecordSetStringW( uirow, 1, desc );
6262 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6263 MSI_RecordSetInteger( uirow, 3, request );
6264 msi_ui_actiondata( package, szInstallODBC, uirow );
6265 msiobj_release( &uirow->hdr );
6272 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6274 static const WCHAR driver_query[] = {
6275 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6276 'O','D','B','C','D','r','i','v','e','r',0};
6277 static const WCHAR translator_query[] = {
6278 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6279 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6280 static const WCHAR source_query[] = {
6281 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6282 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6286 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6287 if (rc == ERROR_SUCCESS)
6289 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6290 msiobj_release(&view->hdr);
6291 if (rc != ERROR_SUCCESS)
6294 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6295 if (rc == ERROR_SUCCESS)
6297 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6298 msiobj_release(&view->hdr);
6299 if (rc != ERROR_SUCCESS)
6302 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6303 if (rc == ERROR_SUCCESS)
6305 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6306 msiobj_release(&view->hdr);
6307 if (rc != ERROR_SUCCESS)
6310 return ERROR_SUCCESS;
6313 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6315 MSIPACKAGE *package = param;
6319 LPCWSTR desc, component;
6321 component = MSI_RecordGetString( rec, 2 );
6322 comp = msi_get_loaded_component( package, component );
6324 return ERROR_SUCCESS;
6326 comp->Action = msi_get_component_action( package, comp );
6327 if (comp->Action != INSTALLSTATE_ABSENT)
6329 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6330 return ERROR_SUCCESS;
6333 desc = MSI_RecordGetString( rec, 3 );
6334 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6336 WARN("Failed to remove ODBC driver\n");
6340 FIXME("Usage count reached 0\n");
6343 uirow = MSI_CreateRecord( 2 );
6344 MSI_RecordSetStringW( uirow, 1, desc );
6345 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6346 msi_ui_actiondata( package, szRemoveODBC, uirow );
6347 msiobj_release( &uirow->hdr );
6349 return ERROR_SUCCESS;
6352 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6354 MSIPACKAGE *package = param;
6358 LPCWSTR desc, component;
6360 component = MSI_RecordGetString( rec, 2 );
6361 comp = msi_get_loaded_component( package, component );
6363 return ERROR_SUCCESS;
6365 comp->Action = msi_get_component_action( package, comp );
6366 if (comp->Action != INSTALLSTATE_ABSENT)
6368 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6369 return ERROR_SUCCESS;
6372 desc = MSI_RecordGetString( rec, 3 );
6373 if (!SQLRemoveTranslatorW( desc, &usage ))
6375 WARN("Failed to remove ODBC translator\n");
6379 FIXME("Usage count reached 0\n");
6382 uirow = MSI_CreateRecord( 2 );
6383 MSI_RecordSetStringW( uirow, 1, desc );
6384 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6385 msi_ui_actiondata( package, szRemoveODBC, uirow );
6386 msiobj_release( &uirow->hdr );
6388 return ERROR_SUCCESS;
6391 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6393 MSIPACKAGE *package = param;
6397 LPCWSTR desc, driver, component;
6398 WORD request = ODBC_REMOVE_SYS_DSN;
6402 static const WCHAR attrs_fmt[] = {
6403 'D','S','N','=','%','s',0 };
6405 component = MSI_RecordGetString( rec, 2 );
6406 comp = msi_get_loaded_component( package, component );
6408 return ERROR_SUCCESS;
6410 comp->Action = msi_get_component_action( package, comp );
6411 if (comp->Action != INSTALLSTATE_ABSENT)
6413 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6414 return ERROR_SUCCESS;
6417 desc = MSI_RecordGetString( rec, 3 );
6418 driver = MSI_RecordGetString( rec, 4 );
6419 registration = MSI_RecordGetInteger( rec, 5 );
6421 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6422 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6424 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6425 attrs = msi_alloc( len * sizeof(WCHAR) );
6427 return ERROR_OUTOFMEMORY;
6429 FIXME("Use ODBCSourceAttribute table\n");
6431 len = sprintfW( attrs, attrs_fmt, desc );
6434 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6436 WARN("Failed to remove ODBC data source\n");
6440 uirow = MSI_CreateRecord( 3 );
6441 MSI_RecordSetStringW( uirow, 1, desc );
6442 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6443 MSI_RecordSetInteger( uirow, 3, request );
6444 msi_ui_actiondata( package, szRemoveODBC, uirow );
6445 msiobj_release( &uirow->hdr );
6447 return ERROR_SUCCESS;
6450 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6452 static const WCHAR driver_query[] = {
6453 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6454 'O','D','B','C','D','r','i','v','e','r',0};
6455 static const WCHAR translator_query[] = {
6456 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6457 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6458 static const WCHAR source_query[] = {
6459 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6460 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6464 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6465 if (rc == ERROR_SUCCESS)
6467 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6468 msiobj_release( &view->hdr );
6469 if (rc != ERROR_SUCCESS)
6472 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6473 if (rc == ERROR_SUCCESS)
6475 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6476 msiobj_release( &view->hdr );
6477 if (rc != ERROR_SUCCESS)
6480 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6481 if (rc == ERROR_SUCCESS)
6483 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6484 msiobj_release( &view->hdr );
6485 if (rc != ERROR_SUCCESS)
6488 return ERROR_SUCCESS;
6491 #define ENV_ACT_SETALWAYS 0x1
6492 #define ENV_ACT_SETABSENT 0x2
6493 #define ENV_ACT_REMOVE 0x4
6494 #define ENV_ACT_REMOVEMATCH 0x8
6496 #define ENV_MOD_MACHINE 0x20000000
6497 #define ENV_MOD_APPEND 0x40000000
6498 #define ENV_MOD_PREFIX 0x80000000
6499 #define ENV_MOD_MASK 0xC0000000
6501 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6503 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6505 LPCWSTR cptr = *name;
6507 static const WCHAR prefix[] = {'[','~',']',0};
6508 static const int prefix_len = 3;
6514 *flags |= ENV_ACT_SETALWAYS;
6515 else if (*cptr == '+')
6516 *flags |= ENV_ACT_SETABSENT;
6517 else if (*cptr == '-')
6518 *flags |= ENV_ACT_REMOVE;
6519 else if (*cptr == '!')
6520 *flags |= ENV_ACT_REMOVEMATCH;
6521 else if (*cptr == '*')
6522 *flags |= ENV_MOD_MACHINE;
6532 ERR("Missing environment variable\n");
6533 return ERROR_FUNCTION_FAILED;
6538 LPCWSTR ptr = *value;
6539 if (!strncmpW(ptr, prefix, prefix_len))
6541 if (ptr[prefix_len] == szSemiColon[0])
6543 *flags |= ENV_MOD_APPEND;
6544 *value += lstrlenW(prefix);
6551 else if (lstrlenW(*value) >= prefix_len)
6553 ptr += lstrlenW(ptr) - prefix_len;
6554 if (!strcmpW( ptr, prefix ))
6556 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6558 *flags |= ENV_MOD_PREFIX;
6559 /* the "[~]" will be removed by deformat_string */;
6569 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6570 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6571 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6572 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6574 ERR("Invalid flags: %08x\n", *flags);
6575 return ERROR_FUNCTION_FAILED;
6579 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6581 return ERROR_SUCCESS;
6584 static UINT open_env_key( DWORD flags, HKEY *key )
6586 static const WCHAR user_env[] =
6587 {'E','n','v','i','r','o','n','m','e','n','t',0};
6588 static const WCHAR machine_env[] =
6589 {'S','y','s','t','e','m','\\',
6590 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6591 'C','o','n','t','r','o','l','\\',
6592 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6593 'E','n','v','i','r','o','n','m','e','n','t',0};
6598 if (flags & ENV_MOD_MACHINE)
6601 root = HKEY_LOCAL_MACHINE;
6606 root = HKEY_CURRENT_USER;
6609 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6610 if (res != ERROR_SUCCESS)
6612 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6613 return ERROR_FUNCTION_FAILED;
6616 return ERROR_SUCCESS;
6619 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6621 MSIPACKAGE *package = param;
6622 LPCWSTR name, value, component;
6623 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6624 DWORD flags, type, size;
6631 component = MSI_RecordGetString(rec, 4);
6632 comp = msi_get_loaded_component(package, component);
6634 return ERROR_SUCCESS;
6636 comp->Action = msi_get_component_action( package, comp );
6637 if (comp->Action != INSTALLSTATE_LOCAL)
6639 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6640 return ERROR_SUCCESS;
6642 name = MSI_RecordGetString(rec, 2);
6643 value = MSI_RecordGetString(rec, 3);
6645 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6647 res = env_parse_flags(&name, &value, &flags);
6648 if (res != ERROR_SUCCESS || !value)
6651 if (value && !deformat_string(package, value, &deformatted))
6653 res = ERROR_OUTOFMEMORY;
6657 value = deformatted;
6659 res = open_env_key( flags, &env );
6660 if (res != ERROR_SUCCESS)
6663 if (flags & ENV_MOD_MACHINE)
6664 action |= 0x20000000;
6668 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6669 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6670 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6673 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6677 /* Nothing to do. */
6680 res = ERROR_SUCCESS;
6684 /* If we are appending but the string was empty, strip ; */
6685 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6687 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6688 newval = strdupW(value);
6691 res = ERROR_OUTOFMEMORY;
6699 /* Contrary to MSDN, +-variable to [~];path works */
6700 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6702 res = ERROR_SUCCESS;
6706 data = msi_alloc(size);
6710 return ERROR_OUTOFMEMORY;
6713 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6714 if (res != ERROR_SUCCESS)
6717 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6720 res = RegDeleteValueW(env, name);
6721 if (res != ERROR_SUCCESS)
6722 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6726 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6727 if (flags & ENV_MOD_MASK)
6731 if (flags & ENV_MOD_APPEND) multiplier++;
6732 if (flags & ENV_MOD_PREFIX) multiplier++;
6733 mod_size = lstrlenW(value) * multiplier;
6734 size += mod_size * sizeof(WCHAR);
6737 newval = msi_alloc(size);
6741 res = ERROR_OUTOFMEMORY;
6745 if (flags & ENV_MOD_PREFIX)
6747 lstrcpyW(newval, value);
6748 ptr = newval + lstrlenW(value);
6749 action |= 0x80000000;
6752 lstrcpyW(ptr, data);
6754 if (flags & ENV_MOD_APPEND)
6756 lstrcatW(newval, value);
6757 action |= 0x40000000;
6760 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6761 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6764 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6768 uirow = MSI_CreateRecord( 3 );
6769 MSI_RecordSetStringW( uirow, 1, name );
6770 MSI_RecordSetStringW( uirow, 2, newval );
6771 MSI_RecordSetInteger( uirow, 3, action );
6772 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6773 msiobj_release( &uirow->hdr );
6775 if (env) RegCloseKey(env);
6776 msi_free(deformatted);
6782 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6784 static const WCHAR query[] = {
6785 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6786 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6790 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6791 if (rc != ERROR_SUCCESS)
6792 return ERROR_SUCCESS;
6794 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6795 msiobj_release(&view->hdr);
6799 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6801 MSIPACKAGE *package = param;
6802 LPCWSTR name, value, component;
6803 LPWSTR deformatted = NULL;
6812 component = MSI_RecordGetString( rec, 4 );
6813 comp = msi_get_loaded_component( package, component );
6815 return ERROR_SUCCESS;
6817 comp->Action = msi_get_component_action( package, comp );
6818 if (comp->Action != INSTALLSTATE_ABSENT)
6820 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6821 return ERROR_SUCCESS;
6823 name = MSI_RecordGetString( rec, 2 );
6824 value = MSI_RecordGetString( rec, 3 );
6826 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6828 r = env_parse_flags( &name, &value, &flags );
6829 if (r != ERROR_SUCCESS)
6832 if (!(flags & ENV_ACT_REMOVE))
6834 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6835 return ERROR_SUCCESS;
6838 if (value && !deformat_string( package, value, &deformatted ))
6839 return ERROR_OUTOFMEMORY;
6841 value = deformatted;
6843 r = open_env_key( flags, &env );
6844 if (r != ERROR_SUCCESS)
6850 if (flags & ENV_MOD_MACHINE)
6851 action |= 0x20000000;
6853 TRACE("Removing %s\n", debugstr_w(name));
6855 res = RegDeleteValueW( env, name );
6856 if (res != ERROR_SUCCESS)
6858 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6863 uirow = MSI_CreateRecord( 3 );
6864 MSI_RecordSetStringW( uirow, 1, name );
6865 MSI_RecordSetStringW( uirow, 2, value );
6866 MSI_RecordSetInteger( uirow, 3, action );
6867 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6868 msiobj_release( &uirow->hdr );
6870 if (env) RegCloseKey( env );
6871 msi_free( deformatted );
6875 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6877 static const WCHAR query[] = {
6878 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6879 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6883 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6884 if (rc != ERROR_SUCCESS)
6885 return ERROR_SUCCESS;
6887 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6888 msiobj_release( &view->hdr );
6892 UINT msi_validate_product_id( MSIPACKAGE *package )
6894 LPWSTR key, template, id;
6895 UINT r = ERROR_SUCCESS;
6897 id = msi_dup_property( package->db, szProductID );
6901 return ERROR_SUCCESS;
6903 template = msi_dup_property( package->db, szPIDTemplate );
6904 key = msi_dup_property( package->db, szPIDKEY );
6905 if (key && template)
6907 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6908 r = msi_set_property( package->db, szProductID, key );
6910 msi_free( template );
6915 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6917 return msi_validate_product_id( package );
6920 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6923 package->need_reboot_at_end = 1;
6924 return ERROR_SUCCESS;
6927 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6929 static const WCHAR szAvailableFreeReg[] =
6930 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6932 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6934 TRACE("%p %d kilobytes\n", package, space);
6936 uirow = MSI_CreateRecord( 1 );
6937 MSI_RecordSetInteger( uirow, 1, space );
6938 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6939 msiobj_release( &uirow->hdr );
6941 return ERROR_SUCCESS;
6944 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6946 TRACE("%p\n", package);
6948 msi_set_property( package->db, szRollbackDisabled, szOne );
6949 return ERROR_SUCCESS;
6952 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6954 FIXME("%p\n", package);
6955 return ERROR_SUCCESS;
6958 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6960 static const WCHAR driver_query[] = {
6961 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6962 'O','D','B','C','D','r','i','v','e','r',0};
6963 static const WCHAR translator_query[] = {
6964 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6965 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6969 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6970 if (r == ERROR_SUCCESS)
6973 r = MSI_IterateRecords( view, &count, NULL, package );
6974 msiobj_release( &view->hdr );
6975 if (r != ERROR_SUCCESS)
6977 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6979 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6980 if (r == ERROR_SUCCESS)
6983 r = MSI_IterateRecords( view, &count, NULL, package );
6984 msiobj_release( &view->hdr );
6985 if (r != ERROR_SUCCESS)
6987 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6989 return ERROR_SUCCESS;
6992 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6994 MSIPACKAGE *package = param;
6995 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6998 if ((value = msi_dup_property( package->db, property )))
7000 FIXME("remove %s\n", debugstr_w(value));
7003 return ERROR_SUCCESS;
7006 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7008 static const WCHAR query[] = {
7009 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7010 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7014 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7015 if (r == ERROR_SUCCESS)
7017 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7018 msiobj_release( &view->hdr );
7019 if (r != ERROR_SUCCESS)
7022 return ERROR_SUCCESS;
7025 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7027 MSIPACKAGE *package = param;
7028 int attributes = MSI_RecordGetInteger( rec, 5 );
7030 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7032 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7033 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7034 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7035 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7039 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7041 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7042 if (r != ERROR_SUCCESS)
7043 return ERROR_SUCCESS;
7047 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7048 if (r != ERROR_SUCCESS)
7049 return ERROR_SUCCESS;
7051 RegCloseKey( hkey );
7053 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7054 debugstr_w(upgrade_code), debugstr_w(version_min),
7055 debugstr_w(version_max), debugstr_w(language));
7057 return ERROR_SUCCESS;
7060 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7062 static const WCHAR query[] = {
7063 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7064 'U','p','g','r','a','d','e',0};
7068 if (msi_get_property_int( package->db, szInstalled, 0 ))
7070 TRACE("product is installed, skipping action\n");
7071 return ERROR_SUCCESS;
7073 if (msi_get_property_int( package->db, szPreselected, 0 ))
7075 TRACE("Preselected property is set, not migrating feature states\n");
7076 return ERROR_SUCCESS;
7078 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7079 if (r == ERROR_SUCCESS)
7081 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7082 msiobj_release( &view->hdr );
7083 if (r != ERROR_SUCCESS)
7086 return ERROR_SUCCESS;
7089 static void bind_image( const char *filename, const char *path )
7091 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7093 WARN("failed to bind image %u\n", GetLastError());
7097 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7101 MSIPACKAGE *package = param;
7102 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7103 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7104 char *filenameA, *pathA;
7105 WCHAR *pathW, **path_list;
7107 if (!(file = msi_get_loaded_file( package, key )))
7109 WARN("file %s not found\n", debugstr_w(key));
7110 return ERROR_SUCCESS;
7112 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7113 path_list = msi_split_string( paths, ';' );
7114 if (!path_list) bind_image( filenameA, NULL );
7117 for (i = 0; path_list[i] && path_list[i][0]; i++)
7119 deformat_string( package, path_list[i], &pathW );
7120 if ((pathA = strdupWtoA( pathW )))
7122 bind_image( filenameA, pathA );
7128 msi_free( path_list );
7129 msi_free( filenameA );
7130 return ERROR_SUCCESS;
7133 static UINT ACTION_BindImage( MSIPACKAGE *package )
7135 static const WCHAR query[] = {
7136 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7137 'B','i','n','d','I','m','a','g','e',0};
7141 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7142 if (r == ERROR_SUCCESS)
7144 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7145 msiobj_release( &view->hdr );
7146 if (r != ERROR_SUCCESS)
7149 return ERROR_SUCCESS;
7152 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7154 static const WCHAR query[] = {
7155 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7160 r = MSI_OpenQuery( package->db, &view, query, table );
7161 if (r == ERROR_SUCCESS)
7163 r = MSI_IterateRecords(view, &count, NULL, package);
7164 msiobj_release(&view->hdr);
7165 if (r != ERROR_SUCCESS)
7168 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7169 return ERROR_SUCCESS;
7172 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7174 static const WCHAR table[] = {
7175 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7176 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7179 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7181 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7182 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7185 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7187 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7188 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7191 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7193 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7194 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7197 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7199 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7200 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7205 const WCHAR *action;
7206 UINT (*handler)(MSIPACKAGE *);
7207 const WCHAR *action_rollback;
7211 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7212 { szAppSearch, ACTION_AppSearch, NULL },
7213 { szBindImage, ACTION_BindImage, NULL },
7214 { szCCPSearch, ACTION_CCPSearch, NULL },
7215 { szCostFinalize, ACTION_CostFinalize, NULL },
7216 { szCostInitialize, ACTION_CostInitialize, NULL },
7217 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7218 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7219 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7220 { szDisableRollback, ACTION_DisableRollback, NULL },
7221 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7222 { szExecuteAction, ACTION_ExecuteAction, NULL },
7223 { szFileCost, ACTION_FileCost, NULL },
7224 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7225 { szForceReboot, ACTION_ForceReboot, NULL },
7226 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7227 { szInstallExecute, ACTION_InstallExecute, NULL },
7228 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7229 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7230 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7231 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7232 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7233 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7234 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7235 { szInstallValidate, ACTION_InstallValidate, NULL },
7236 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7237 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7238 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7239 { szMoveFiles, ACTION_MoveFiles, NULL },
7240 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7241 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7242 { szPatchFiles, ACTION_PatchFiles, NULL },
7243 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7244 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7245 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7246 { szPublishProduct, ACTION_PublishProduct, NULL },
7247 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7248 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7249 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7250 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7251 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7252 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7253 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7254 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7255 { szRegisterUser, ACTION_RegisterUser, NULL },
7256 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7257 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7258 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7259 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7260 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7261 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7262 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7263 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7264 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7265 { szResolveSource, ACTION_ResolveSource, NULL },
7266 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7267 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7268 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7269 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7270 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7271 { szStartServices, ACTION_StartServices, szStopServices },
7272 { szStopServices, ACTION_StopServices, szStartServices },
7273 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7274 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7275 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7276 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7277 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7278 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7279 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7280 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7281 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7282 { szValidateProductID, ACTION_ValidateProductID, NULL },
7283 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7284 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7285 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7286 { NULL, NULL, NULL }
7289 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7295 while (StandardActions[i].action != NULL)
7297 if (!strcmpW( StandardActions[i].action, action ))
7299 ui_actionstart( package, action );
7300 if (StandardActions[i].handler)
7302 ui_actioninfo( package, action, TRUE, 0 );
7303 *rc = StandardActions[i].handler( package );
7304 ui_actioninfo( package, action, FALSE, *rc );
7306 if (StandardActions[i].action_rollback && !package->need_rollback)
7308 TRACE("scheduling rollback action\n");
7309 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7314 FIXME("unhandled standard action %s\n", debugstr_w(action));
7315 *rc = ERROR_SUCCESS;
7325 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7327 UINT rc = ERROR_SUCCESS;
7330 TRACE("Performing action (%s)\n", debugstr_w(action));
7332 handled = ACTION_HandleStandardAction(package, action, &rc);
7335 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7339 WARN("unhandled msi action %s\n", debugstr_w(action));
7340 rc = ERROR_FUNCTION_NOT_CALLED;
7346 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7348 UINT rc = ERROR_SUCCESS;
7349 BOOL handled = FALSE;
7351 TRACE("Performing action (%s)\n", debugstr_w(action));
7353 package->action_progress_increment = 0;
7354 handled = ACTION_HandleStandardAction(package, action, &rc);
7357 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7359 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7364 WARN("unhandled msi action %s\n", debugstr_w(action));
7365 rc = ERROR_FUNCTION_NOT_CALLED;
7371 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7373 UINT rc = ERROR_SUCCESS;
7376 static const WCHAR query[] =
7377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7378 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7379 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7380 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7381 static const WCHAR ui_query[] =
7382 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7383 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7384 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7385 ' ', '=',' ','%','i',0};
7387 if (needs_ui_sequence(package))
7388 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7390 row = MSI_QueryGetRecord(package->db, query, seq);
7394 LPCWSTR action, cond;
7396 TRACE("Running the actions\n");
7398 /* check conditions */
7399 cond = MSI_RecordGetString(row, 2);
7401 /* this is a hack to skip errors in the condition code */
7402 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7404 msiobj_release(&row->hdr);
7405 return ERROR_SUCCESS;
7408 action = MSI_RecordGetString(row, 1);
7411 ERR("failed to fetch action\n");
7412 msiobj_release(&row->hdr);
7413 return ERROR_FUNCTION_FAILED;
7416 if (needs_ui_sequence(package))
7417 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7419 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7421 msiobj_release(&row->hdr);
7427 /****************************************************
7428 * TOP level entry points
7429 *****************************************************/
7431 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7432 LPCWSTR szCommandLine )
7434 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7435 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7436 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7437 WCHAR *reinstall = NULL;
7441 msi_set_property( package->db, szAction, szInstall );
7443 package->script->InWhatSequence = SEQUENCE_INSTALL;
7450 dir = strdupW(szPackagePath);
7451 p = strrchrW(dir, '\\');
7455 file = szPackagePath + (p - dir);
7460 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7461 GetCurrentDirectoryW(MAX_PATH, dir);
7462 lstrcatW(dir, szBackSlash);
7463 file = szPackagePath;
7466 msi_free( package->PackagePath );
7467 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7468 if (!package->PackagePath)
7471 return ERROR_OUTOFMEMORY;
7474 lstrcpyW(package->PackagePath, dir);
7475 lstrcatW(package->PackagePath, file);
7478 msi_set_sourcedir_props(package, FALSE);
7481 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7482 if (rc != ERROR_SUCCESS)
7485 msi_apply_transforms( package );
7486 msi_apply_patches( package );
7488 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7490 TRACE("setting reinstall property\n");
7491 msi_set_property( package->db, szReinstall, szAll );
7494 /* properties may have been added by a transform */
7495 msi_clone_properties( package );
7497 msi_parse_command_line( package, szCommandLine, FALSE );
7498 msi_adjust_privilege_properties( package );
7499 msi_set_context( package );
7501 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7503 TRACE("disabling rollback\n");
7504 msi_set_property( package->db, szRollbackDisabled, szOne );
7507 if (needs_ui_sequence( package))
7509 package->script->InWhatSequence |= SEQUENCE_UI;
7510 rc = ACTION_ProcessUISequence(package);
7511 ui_exists = ui_sequence_exists(package);
7512 if (rc == ERROR_SUCCESS || !ui_exists)
7514 package->script->InWhatSequence |= SEQUENCE_EXEC;
7515 rc = ACTION_ProcessExecSequence(package, ui_exists);
7519 rc = ACTION_ProcessExecSequence(package, FALSE);
7521 package->script->CurrentlyScripting = FALSE;
7523 /* process the ending type action */
7524 if (rc == ERROR_SUCCESS)
7525 ACTION_PerformActionSequence(package, -1);
7526 else if (rc == ERROR_INSTALL_USEREXIT)
7527 ACTION_PerformActionSequence(package, -2);
7528 else if (rc == ERROR_INSTALL_SUSPEND)
7529 ACTION_PerformActionSequence(package, -4);
7532 ACTION_PerformActionSequence(package, -3);
7533 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7535 package->need_rollback = TRUE;
7539 /* finish up running custom actions */
7540 ACTION_FinishCustomActions(package);
7542 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7544 WARN("installation failed, running rollback script\n");
7545 execute_script( package, SCRIPT_ROLLBACK );
7547 msi_free( reinstall );
7549 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7550 return ERROR_SUCCESS_REBOOT_REQUIRED;