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 (gUILevel & 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);
542 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
544 static const WCHAR query[] = {
545 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
546 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
547 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
548 '`','S','e','q','u','e','n','c','e','`',0};
552 TRACE("%p %s\n", package, debugstr_w(table));
554 r = MSI_OpenQuery( package->db, &view, query, table );
555 if (r == ERROR_SUCCESS)
557 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
558 msiobj_release(&view->hdr);
563 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
565 static const WCHAR query[] = {
566 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
567 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
568 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
569 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
570 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
571 static const WCHAR query_validate[] = {
572 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
573 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
574 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
575 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
576 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
581 if (package->script->ExecuteSequenceRun)
583 TRACE("Execute Sequence already Run\n");
584 return ERROR_SUCCESS;
587 package->script->ExecuteSequenceRun = TRUE;
589 /* get the sequence number */
592 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
593 if (!row) return ERROR_FUNCTION_FAILED;
594 seq = MSI_RecordGetInteger(row,1);
595 msiobj_release(&row->hdr);
597 rc = MSI_OpenQuery(package->db, &view, query, seq);
598 if (rc == ERROR_SUCCESS)
600 TRACE("Running the actions\n");
602 msi_set_property(package->db, szSourceDir, NULL);
603 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
604 msiobj_release(&view->hdr);
609 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
611 static const WCHAR query[] = {
612 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
613 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
614 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
615 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
619 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
620 if (rc == ERROR_SUCCESS)
622 TRACE("Running the actions\n");
623 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
624 msiobj_release(&view->hdr);
629 /********************************************************
630 * ACTION helper functions and functions that perform the actions
631 *******************************************************/
632 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
633 UINT* rc, UINT script, BOOL force )
638 arc = ACTION_CustomAction(package, action, script, force);
640 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
648 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
652 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
654 if (!strcmpW( Component, comp->Component )) return comp;
659 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
663 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
665 if (!strcmpW( Feature, feature->Feature )) return feature;
670 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
674 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
676 if (!strcmpW( key, file->File )) return file;
681 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
685 /* FIXME: There might be more than one patch */
686 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
688 if (!strcmpW( key, patch->File->File )) return patch;
693 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
697 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
699 if (!strcmpW( dir, folder->Directory )) return folder;
705 * Recursively create all directories in the path.
706 * shamelessly stolen from setupapi/queue.c
708 BOOL msi_create_full_path( const WCHAR *path )
714 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
715 strcpyW( new_path, path );
717 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
718 new_path[len - 1] = 0;
720 while (!CreateDirectoryW( new_path, NULL ))
723 DWORD last_error = GetLastError();
724 if (last_error == ERROR_ALREADY_EXISTS) break;
725 if (last_error != ERROR_PATH_NOT_FOUND)
730 if (!(slash = strrchrW( new_path, '\\' )))
735 len = slash - new_path;
737 if (!msi_create_full_path( new_path ))
742 new_path[len] = '\\';
744 msi_free( new_path );
748 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
752 row = MSI_CreateRecord( 4 );
753 MSI_RecordSetInteger( row, 1, a );
754 MSI_RecordSetInteger( row, 2, b );
755 MSI_RecordSetInteger( row, 3, c );
756 MSI_RecordSetInteger( row, 4, d );
757 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
758 msiobj_release( &row->hdr );
760 msi_dialog_check_messages( NULL );
763 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
765 static const WCHAR query[] =
766 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
767 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
768 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
773 if (!package->LastAction || strcmpW( package->LastAction, action ))
775 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
777 if (MSI_RecordIsNull( row, 3 ))
779 msiobj_release( &row->hdr );
782 /* update the cached action format */
783 msi_free( package->ActionFormat );
784 package->ActionFormat = msi_dup_record_field( row, 3 );
785 msi_free( package->LastAction );
786 package->LastAction = strdupW( action );
787 msiobj_release( &row->hdr );
790 MSI_RecordSetStringW( record, 0, package->ActionFormat );
791 MSI_FormatRecordW( package, record, message, &size );
792 row = MSI_CreateRecord( 1 );
793 MSI_RecordSetStringW( row, 1, message );
794 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
795 msiobj_release( &row->hdr );
798 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
802 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
803 return INSTALLSTATE_UNKNOWN;
805 if (package->need_rollback) return comp->Installed;
806 return comp->ActionRequest;
809 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
811 if (package->need_rollback) return feature->Installed;
812 return feature->ActionRequest;
815 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
817 MSIPACKAGE *package = param;
818 LPCWSTR dir, component, full_path;
823 component = MSI_RecordGetString(row, 2);
825 return ERROR_SUCCESS;
827 comp = msi_get_loaded_component(package, component);
829 return ERROR_SUCCESS;
831 comp->Action = msi_get_component_action( package, comp );
832 if (comp->Action != INSTALLSTATE_LOCAL)
834 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
835 return ERROR_SUCCESS;
838 dir = MSI_RecordGetString(row,1);
841 ERR("Unable to get folder id\n");
842 return ERROR_SUCCESS;
845 uirow = MSI_CreateRecord(1);
846 MSI_RecordSetStringW(uirow, 1, dir);
847 msi_ui_actiondata(package, szCreateFolders, uirow);
848 msiobj_release(&uirow->hdr);
850 full_path = msi_get_target_folder( package, dir );
853 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
854 return ERROR_SUCCESS;
856 TRACE("folder is %s\n", debugstr_w(full_path));
858 folder = msi_get_loaded_folder( package, dir );
859 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
860 folder->State = FOLDER_STATE_CREATED;
861 return ERROR_SUCCESS;
864 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
866 static const WCHAR query[] = {
867 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
868 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
872 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
873 if (rc != ERROR_SUCCESS)
874 return ERROR_SUCCESS;
876 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
877 msiobj_release(&view->hdr);
881 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
883 MSIPACKAGE *package = param;
884 LPCWSTR dir, component, full_path;
889 component = MSI_RecordGetString(row, 2);
891 return ERROR_SUCCESS;
893 comp = msi_get_loaded_component(package, component);
895 return ERROR_SUCCESS;
897 comp->Action = msi_get_component_action( package, comp );
898 if (comp->Action != INSTALLSTATE_ABSENT)
900 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
901 return ERROR_SUCCESS;
904 dir = MSI_RecordGetString( row, 1 );
907 ERR("Unable to get folder id\n");
908 return ERROR_SUCCESS;
911 full_path = msi_get_target_folder( package, dir );
914 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
915 return ERROR_SUCCESS;
917 TRACE("folder is %s\n", debugstr_w(full_path));
919 uirow = MSI_CreateRecord( 1 );
920 MSI_RecordSetStringW( uirow, 1, dir );
921 msi_ui_actiondata( package, szRemoveFolders, uirow );
922 msiobj_release( &uirow->hdr );
924 RemoveDirectoryW( full_path );
925 folder = msi_get_loaded_folder( package, dir );
926 folder->State = FOLDER_STATE_REMOVED;
927 return ERROR_SUCCESS;
930 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
932 static const WCHAR query[] = {
933 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
934 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
938 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
939 if (rc != ERROR_SUCCESS)
940 return ERROR_SUCCESS;
942 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
943 msiobj_release( &view->hdr );
947 static UINT load_component( MSIRECORD *row, LPVOID param )
949 MSIPACKAGE *package = param;
952 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
954 return ERROR_FUNCTION_FAILED;
956 list_add_tail( &package->components, &comp->entry );
958 /* fill in the data */
959 comp->Component = msi_dup_record_field( row, 1 );
961 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
963 comp->ComponentId = msi_dup_record_field( row, 2 );
964 comp->Directory = msi_dup_record_field( row, 3 );
965 comp->Attributes = MSI_RecordGetInteger(row,4);
966 comp->Condition = msi_dup_record_field( row, 5 );
967 comp->KeyPath = msi_dup_record_field( row, 6 );
969 comp->Installed = INSTALLSTATE_UNKNOWN;
970 comp->Action = INSTALLSTATE_UNKNOWN;
971 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
973 comp->assembly = msi_load_assembly( package, comp );
974 return ERROR_SUCCESS;
977 UINT msi_load_all_components( MSIPACKAGE *package )
979 static const WCHAR query[] = {
980 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
981 '`','C','o','m','p','o','n','e','n','t','`',0};
985 if (!list_empty(&package->components))
986 return ERROR_SUCCESS;
988 r = MSI_DatabaseOpenViewW( package->db, query, &view );
989 if (r != ERROR_SUCCESS)
992 if (!msi_init_assembly_caches( package ))
994 ERR("can't initialize assembly caches\n");
995 msiobj_release( &view->hdr );
996 return ERROR_FUNCTION_FAILED;
999 r = MSI_IterateRecords(view, NULL, load_component, package);
1000 msiobj_release(&view->hdr);
1001 msi_destroy_assembly_caches( package );
1006 MSIPACKAGE *package;
1007 MSIFEATURE *feature;
1010 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1014 cl = msi_alloc( sizeof (*cl) );
1016 return ERROR_NOT_ENOUGH_MEMORY;
1017 cl->component = comp;
1018 list_add_tail( &feature->Components, &cl->entry );
1020 return ERROR_SUCCESS;
1023 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1027 fl = msi_alloc( sizeof(*fl) );
1029 return ERROR_NOT_ENOUGH_MEMORY;
1030 fl->feature = child;
1031 list_add_tail( &parent->Children, &fl->entry );
1033 return ERROR_SUCCESS;
1036 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1038 _ilfs* ilfs = param;
1042 component = MSI_RecordGetString(row,1);
1044 /* check to see if the component is already loaded */
1045 comp = msi_get_loaded_component( ilfs->package, component );
1048 WARN("ignoring unknown component %s\n", debugstr_w(component));
1049 return ERROR_SUCCESS;
1051 add_feature_component( ilfs->feature, comp );
1052 comp->Enabled = TRUE;
1054 return ERROR_SUCCESS;
1057 static UINT load_feature(MSIRECORD * row, LPVOID param)
1059 static const WCHAR query[] = {
1060 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1061 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1062 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1063 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1064 MSIPACKAGE *package = param;
1065 MSIFEATURE *feature;
1070 /* fill in the data */
1072 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1074 return ERROR_NOT_ENOUGH_MEMORY;
1076 list_init( &feature->Children );
1077 list_init( &feature->Components );
1079 feature->Feature = msi_dup_record_field( row, 1 );
1081 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1083 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1084 feature->Title = msi_dup_record_field( row, 3 );
1085 feature->Description = msi_dup_record_field( row, 4 );
1087 if (!MSI_RecordIsNull(row,5))
1088 feature->Display = MSI_RecordGetInteger(row,5);
1090 feature->Level= MSI_RecordGetInteger(row,6);
1091 feature->Directory = msi_dup_record_field( row, 7 );
1092 feature->Attributes = MSI_RecordGetInteger(row,8);
1094 feature->Installed = INSTALLSTATE_UNKNOWN;
1095 feature->Action = INSTALLSTATE_UNKNOWN;
1096 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1098 list_add_tail( &package->features, &feature->entry );
1100 /* load feature components */
1102 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1103 if (rc != ERROR_SUCCESS)
1104 return ERROR_SUCCESS;
1106 ilfs.package = package;
1107 ilfs.feature = feature;
1109 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1110 msiobj_release(&view->hdr);
1114 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1116 MSIPACKAGE *package = param;
1117 MSIFEATURE *parent, *child;
1119 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1121 return ERROR_FUNCTION_FAILED;
1123 if (!child->Feature_Parent)
1124 return ERROR_SUCCESS;
1126 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1128 return ERROR_FUNCTION_FAILED;
1130 add_feature_child( parent, child );
1131 return ERROR_SUCCESS;
1134 UINT msi_load_all_features( MSIPACKAGE *package )
1136 static const WCHAR query[] = {
1137 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1138 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1139 '`','D','i','s','p','l','a','y','`',0};
1143 if (!list_empty(&package->features))
1144 return ERROR_SUCCESS;
1146 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1147 if (r != ERROR_SUCCESS)
1150 r = MSI_IterateRecords( view, NULL, load_feature, package );
1151 if (r != ERROR_SUCCESS)
1153 msiobj_release( &view->hdr );
1156 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1157 msiobj_release( &view->hdr );
1161 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1172 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1174 static const WCHAR query[] = {
1175 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1176 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1177 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1178 MSIQUERY *view = NULL;
1179 MSIRECORD *row = NULL;
1182 TRACE("%s\n", debugstr_w(file->File));
1184 r = MSI_OpenQuery(package->db, &view, query, file->File);
1185 if (r != ERROR_SUCCESS)
1188 r = MSI_ViewExecute(view, NULL);
1189 if (r != ERROR_SUCCESS)
1192 r = MSI_ViewFetch(view, &row);
1193 if (r != ERROR_SUCCESS)
1196 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1197 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1198 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1199 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1200 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1203 if (view) msiobj_release(&view->hdr);
1204 if (row) msiobj_release(&row->hdr);
1208 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1211 static const WCHAR query[] = {
1212 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1213 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1214 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1216 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1219 WARN("query failed\n");
1220 return ERROR_FUNCTION_FAILED;
1223 file->disk_id = MSI_RecordGetInteger( row, 1 );
1224 msiobj_release( &row->hdr );
1225 return ERROR_SUCCESS;
1228 static UINT load_file(MSIRECORD *row, LPVOID param)
1230 MSIPACKAGE* package = param;
1234 /* fill in the data */
1236 file = msi_alloc_zero( sizeof (MSIFILE) );
1238 return ERROR_NOT_ENOUGH_MEMORY;
1240 file->File = msi_dup_record_field( row, 1 );
1242 component = MSI_RecordGetString( row, 2 );
1243 file->Component = msi_get_loaded_component( package, component );
1245 if (!file->Component)
1247 WARN("Component not found: %s\n", debugstr_w(component));
1248 msi_free(file->File);
1250 return ERROR_SUCCESS;
1253 file->FileName = msi_dup_record_field( row, 3 );
1254 msi_reduce_to_long_filename( file->FileName );
1256 file->ShortName = msi_dup_record_field( row, 3 );
1257 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1259 file->FileSize = MSI_RecordGetInteger( row, 4 );
1260 file->Version = msi_dup_record_field( row, 5 );
1261 file->Language = msi_dup_record_field( row, 6 );
1262 file->Attributes = MSI_RecordGetInteger( row, 7 );
1263 file->Sequence = MSI_RecordGetInteger( row, 8 );
1265 file->state = msifs_invalid;
1267 /* if the compressed bits are not set in the file attributes,
1268 * then read the information from the package word count property
1270 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1272 file->IsCompressed = FALSE;
1274 else if (file->Attributes &
1275 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1277 file->IsCompressed = TRUE;
1279 else if (file->Attributes & msidbFileAttributesNoncompressed)
1281 file->IsCompressed = FALSE;
1285 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1288 load_file_hash(package, file);
1289 load_file_disk_id(package, file);
1291 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1293 list_add_tail( &package->files, &file->entry );
1295 return ERROR_SUCCESS;
1298 static UINT load_all_files(MSIPACKAGE *package)
1300 static const WCHAR query[] = {
1301 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1302 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1303 '`','S','e','q','u','e','n','c','e','`', 0};
1307 if (!list_empty(&package->files))
1308 return ERROR_SUCCESS;
1310 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1311 if (rc != ERROR_SUCCESS)
1312 return ERROR_SUCCESS;
1314 rc = MSI_IterateRecords(view, NULL, load_file, package);
1315 msiobj_release(&view->hdr);
1319 static UINT load_media( MSIRECORD *row, LPVOID param )
1321 MSIPACKAGE *package = param;
1322 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1323 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1325 /* FIXME: load external cabinets and directory sources too */
1326 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1327 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1328 return ERROR_SUCCESS;
1331 static UINT load_all_media( MSIPACKAGE *package )
1333 static const WCHAR query[] = {
1334 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1335 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1336 '`','D','i','s','k','I','d','`',0};
1340 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1341 if (r != ERROR_SUCCESS)
1342 return ERROR_SUCCESS;
1344 r = MSI_IterateRecords( view, NULL, load_media, package );
1345 msiobj_release( &view->hdr );
1349 static UINT load_patch(MSIRECORD *row, LPVOID param)
1351 MSIPACKAGE *package = param;
1352 MSIFILEPATCH *patch;
1355 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1357 return ERROR_NOT_ENOUGH_MEMORY;
1359 file_key = msi_dup_record_field( row, 1 );
1360 patch->File = msi_get_loaded_file( package, file_key );
1365 ERR("Failed to find target for patch in File table\n");
1367 return ERROR_FUNCTION_FAILED;
1370 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1372 /* FIXME: The database should be properly transformed */
1373 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1375 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1376 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1377 patch->IsApplied = FALSE;
1380 * Header field - for patch validation.
1381 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1384 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1386 list_add_tail( &package->filepatches, &patch->entry );
1388 return ERROR_SUCCESS;
1391 static UINT load_all_patches(MSIPACKAGE *package)
1393 static const WCHAR query[] = {
1394 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1395 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1396 '`','S','e','q','u','e','n','c','e','`',0};
1400 if (!list_empty(&package->filepatches))
1401 return ERROR_SUCCESS;
1403 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1404 if (rc != ERROR_SUCCESS)
1405 return ERROR_SUCCESS;
1407 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1408 msiobj_release(&view->hdr);
1412 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1414 static const WCHAR query[] = {
1415 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1416 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1417 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1420 folder->persistent = FALSE;
1421 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1423 if (!MSI_ViewExecute( view, NULL ))
1426 if (!MSI_ViewFetch( view, &rec ))
1428 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1429 folder->persistent = TRUE;
1430 msiobj_release( &rec->hdr );
1433 msiobj_release( &view->hdr );
1435 return ERROR_SUCCESS;
1438 static UINT load_folder( MSIRECORD *row, LPVOID param )
1440 MSIPACKAGE *package = param;
1441 static WCHAR szEmpty[] = { 0 };
1442 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1445 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1446 list_init( &folder->children );
1447 folder->Directory = msi_dup_record_field( row, 1 );
1448 folder->Parent = msi_dup_record_field( row, 2 );
1449 p = msi_dup_record_field(row, 3);
1451 TRACE("%s\n", debugstr_w(folder->Directory));
1453 /* split src and target dir */
1455 src_short = folder_split_path( p, ':' );
1457 /* split the long and short paths */
1458 tgt_long = folder_split_path( tgt_short, '|' );
1459 src_long = folder_split_path( src_short, '|' );
1461 /* check for no-op dirs */
1462 if (tgt_short && !strcmpW( szDot, tgt_short ))
1463 tgt_short = szEmpty;
1464 if (src_short && !strcmpW( szDot, src_short ))
1465 src_short = szEmpty;
1468 tgt_long = tgt_short;
1471 src_short = tgt_short;
1472 src_long = tgt_long;
1476 src_long = src_short;
1478 /* FIXME: use the target short path too */
1479 folder->TargetDefault = strdupW(tgt_long);
1480 folder->SourceShortPath = strdupW(src_short);
1481 folder->SourceLongPath = strdupW(src_long);
1484 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1485 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1486 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1488 load_folder_persistence( package, folder );
1490 list_add_tail( &package->folders, &folder->entry );
1491 return ERROR_SUCCESS;
1494 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1498 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1500 list_add_tail( &parent->children, &fl->entry );
1501 return ERROR_SUCCESS;
1504 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1506 MSIPACKAGE *package = param;
1507 MSIFOLDER *parent, *child;
1509 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1510 return ERROR_FUNCTION_FAILED;
1512 if (!child->Parent) return ERROR_SUCCESS;
1514 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1515 return ERROR_FUNCTION_FAILED;
1517 return add_folder_child( parent, child );
1520 static UINT load_all_folders( MSIPACKAGE *package )
1522 static const WCHAR query[] = {
1523 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1524 '`','D','i','r','e','c','t','o','r','y','`',0};
1528 if (!list_empty(&package->folders))
1529 return ERROR_SUCCESS;
1531 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1532 if (r != ERROR_SUCCESS)
1535 r = MSI_IterateRecords( view, NULL, load_folder, package );
1536 if (r != ERROR_SUCCESS)
1538 msiobj_release( &view->hdr );
1541 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1542 msiobj_release( &view->hdr );
1546 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1548 msi_set_property( package->db, szCostingComplete, szZero );
1549 msi_set_property( package->db, szRootDrive, szCRoot );
1551 load_all_folders( package );
1552 msi_load_all_components( package );
1553 msi_load_all_features( package );
1554 load_all_files( package );
1555 load_all_patches( package );
1556 load_all_media( package );
1558 return ERROR_SUCCESS;
1561 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1563 const WCHAR *action = package->script->Actions[script][index];
1564 ui_actionstart( package, action );
1565 TRACE("executing %s\n", debugstr_w(action));
1566 return ACTION_PerformAction( package, action, script );
1569 static UINT execute_script( MSIPACKAGE *package, UINT script )
1571 UINT i, rc = ERROR_SUCCESS;
1573 TRACE("executing script %u\n", script);
1575 if (!package->script)
1577 ERR("no script!\n");
1578 return ERROR_FUNCTION_FAILED;
1580 if (script == SCRIPT_ROLLBACK)
1582 for (i = package->script->ActionCount[script]; i > 0; i--)
1584 rc = execute_script_action( package, script, i - 1 );
1585 if (rc != ERROR_SUCCESS) break;
1590 for (i = 0; i < package->script->ActionCount[script]; i++)
1592 rc = execute_script_action( package, script, i );
1593 if (rc != ERROR_SUCCESS) break;
1596 msi_free_action_script(package, script);
1600 static UINT ACTION_FileCost(MSIPACKAGE *package)
1602 return ERROR_SUCCESS;
1605 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1610 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1612 if (!comp->ComponentId) continue;
1614 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1615 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1617 if (r != ERROR_SUCCESS)
1618 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1619 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1621 if (r != ERROR_SUCCESS)
1622 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1623 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1625 if (r != ERROR_SUCCESS)
1626 comp->Installed = INSTALLSTATE_ABSENT;
1630 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1632 MSIFEATURE *feature;
1634 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1636 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1638 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1639 feature->Installed = INSTALLSTATE_ABSENT;
1641 feature->Installed = state;
1645 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1647 return (feature->Level > 0 && feature->Level <= level);
1650 static BOOL process_state_property(MSIPACKAGE* package, int level,
1651 LPCWSTR property, INSTALLSTATE state)
1654 MSIFEATURE *feature;
1656 override = msi_dup_property( package->db, property );
1660 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1662 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1665 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1667 if (!strcmpiW( override, szAll ))
1669 if (feature->Installed != state)
1671 feature->Action = state;
1672 feature->ActionRequest = state;
1677 LPWSTR ptr = override;
1678 LPWSTR ptr2 = strchrW(override,',');
1682 int len = ptr2 - ptr;
1684 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1685 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1687 if (feature->Installed != state)
1689 feature->Action = state;
1690 feature->ActionRequest = state;
1697 ptr2 = strchrW(ptr,',');
1708 static BOOL process_overrides( MSIPACKAGE *package, int level )
1710 static const WCHAR szAddLocal[] =
1711 {'A','D','D','L','O','C','A','L',0};
1712 static const WCHAR szAddSource[] =
1713 {'A','D','D','S','O','U','R','C','E',0};
1714 static const WCHAR szAdvertise[] =
1715 {'A','D','V','E','R','T','I','S','E',0};
1718 /* all these activation/deactivation things happen in order and things
1719 * later on the list override things earlier on the list.
1721 * 0 INSTALLLEVEL processing
1734 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1735 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1736 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1737 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1738 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1741 msi_set_property( package->db, szPreselected, szOne );
1746 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1749 MSICOMPONENT* component;
1750 MSIFEATURE *feature;
1752 TRACE("Checking Install Level\n");
1754 level = msi_get_property_int(package->db, szInstallLevel, 1);
1756 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1758 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1760 if (!is_feature_selected( feature, level )) continue;
1762 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1764 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1766 feature->Action = INSTALLSTATE_SOURCE;
1767 feature->ActionRequest = INSTALLSTATE_SOURCE;
1769 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1771 feature->Action = INSTALLSTATE_ADVERTISED;
1772 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1776 feature->Action = INSTALLSTATE_LOCAL;
1777 feature->ActionRequest = INSTALLSTATE_LOCAL;
1781 /* disable child features of unselected parent or follow parent */
1782 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1786 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1788 if (!is_feature_selected( feature, level ))
1790 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1791 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1793 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1795 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1796 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1797 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1798 fl->feature->Action = feature->Action;
1799 fl->feature->ActionRequest = feature->ActionRequest;
1804 else /* preselected */
1806 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1808 if (!is_feature_selected( feature, level )) continue;
1810 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1812 if (feature->Installed == INSTALLSTATE_ABSENT)
1814 feature->Action = INSTALLSTATE_UNKNOWN;
1815 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1819 feature->Action = feature->Installed;
1820 feature->ActionRequest = feature->Installed;
1824 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1828 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1830 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1831 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1833 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1834 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1835 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1836 fl->feature->Action = feature->Action;
1837 fl->feature->ActionRequest = feature->ActionRequest;
1843 /* now we want to set component state based based on feature state */
1844 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1848 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1849 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1850 feature->ActionRequest, feature->Action);
1852 if (!is_feature_selected( feature, level )) continue;
1854 /* features with components that have compressed files are made local */
1855 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1857 if (cl->component->ForceLocalState &&
1858 feature->ActionRequest == INSTALLSTATE_SOURCE)
1860 feature->Action = INSTALLSTATE_LOCAL;
1861 feature->ActionRequest = INSTALLSTATE_LOCAL;
1866 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1868 component = cl->component;
1870 switch (feature->ActionRequest)
1872 case INSTALLSTATE_ABSENT:
1873 component->anyAbsent = 1;
1875 case INSTALLSTATE_ADVERTISED:
1876 component->hasAdvertiseFeature = 1;
1878 case INSTALLSTATE_SOURCE:
1879 component->hasSourceFeature = 1;
1881 case INSTALLSTATE_LOCAL:
1882 component->hasLocalFeature = 1;
1884 case INSTALLSTATE_DEFAULT:
1885 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1886 component->hasAdvertiseFeature = 1;
1887 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1888 component->hasSourceFeature = 1;
1890 component->hasLocalFeature = 1;
1898 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1900 /* check if it's local or source */
1901 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1902 (component->hasLocalFeature || component->hasSourceFeature))
1904 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1905 !component->ForceLocalState)
1907 component->Action = INSTALLSTATE_SOURCE;
1908 component->ActionRequest = INSTALLSTATE_SOURCE;
1912 component->Action = INSTALLSTATE_LOCAL;
1913 component->ActionRequest = INSTALLSTATE_LOCAL;
1918 /* if any feature is local, the component must be local too */
1919 if (component->hasLocalFeature)
1921 component->Action = INSTALLSTATE_LOCAL;
1922 component->ActionRequest = INSTALLSTATE_LOCAL;
1925 if (component->hasSourceFeature)
1927 component->Action = INSTALLSTATE_SOURCE;
1928 component->ActionRequest = INSTALLSTATE_SOURCE;
1931 if (component->hasAdvertiseFeature)
1933 component->Action = INSTALLSTATE_ADVERTISED;
1934 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1937 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1938 if (component->anyAbsent &&
1939 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1941 component->Action = INSTALLSTATE_ABSENT;
1942 component->ActionRequest = INSTALLSTATE_ABSENT;
1946 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1948 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1950 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1951 component->Action = INSTALLSTATE_LOCAL;
1952 component->ActionRequest = INSTALLSTATE_LOCAL;
1955 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1956 component->Installed == INSTALLSTATE_SOURCE &&
1957 component->hasSourceFeature)
1959 component->Action = INSTALLSTATE_UNKNOWN;
1960 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1963 TRACE("component %s (installed %d request %d action %d)\n",
1964 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1967 return ERROR_SUCCESS;
1970 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1972 MSIPACKAGE *package = param;
1974 MSIFEATURE *feature;
1976 name = MSI_RecordGetString( row, 1 );
1978 feature = msi_get_loaded_feature( package, name );
1980 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1984 Condition = MSI_RecordGetString(row,3);
1986 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1988 int level = MSI_RecordGetInteger(row,2);
1989 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1990 feature->Level = level;
1993 return ERROR_SUCCESS;
1996 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1998 static const WCHAR name[] = {'\\',0};
1999 VS_FIXEDFILEINFO *ptr, *ret;
2001 DWORD versize, handle;
2004 versize = GetFileVersionInfoSizeW( filename, &handle );
2008 version = msi_alloc( versize );
2012 GetFileVersionInfoW( filename, 0, versize, version );
2014 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2016 msi_free( version );
2020 ret = msi_alloc( sz );
2021 memcpy( ret, ptr, sz );
2023 msi_free( version );
2027 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2031 msi_parse_version_string( version, &ms, &ls );
2033 if (fi->dwFileVersionMS > ms) return 1;
2034 else if (fi->dwFileVersionMS < ms) return -1;
2035 else if (fi->dwFileVersionLS > ls) return 1;
2036 else if (fi->dwFileVersionLS < ls) return -1;
2040 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2044 msi_parse_version_string( ver1, &ms1, NULL );
2045 msi_parse_version_string( ver2, &ms2, NULL );
2047 if (ms1 > ms2) return 1;
2048 else if (ms1 < ms2) return -1;
2052 DWORD msi_get_disk_file_size( LPCWSTR filename )
2057 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2058 if (file == INVALID_HANDLE_VALUE)
2059 return INVALID_FILE_SIZE;
2061 size = GetFileSize( file, NULL );
2062 TRACE("size is %u\n", size);
2063 CloseHandle( file );
2067 BOOL msi_file_hash_matches( MSIFILE *file )
2070 MSIFILEHASHINFO hash;
2072 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2073 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2074 if (r != ERROR_SUCCESS)
2077 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2080 static WCHAR *get_temp_dir( void )
2083 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2085 GetTempPathW( MAX_PATH, tmp );
2088 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2089 if (CreateDirectoryW( dir, NULL )) break;
2091 return strdupW( dir );
2095 * msi_build_directory_name()
2097 * This function is to save messing round with directory names
2098 * It handles adding backslashes between path segments,
2099 * and can add \ at the end of the directory name if told to.
2101 * It takes a variable number of arguments.
2102 * It always allocates a new string for the result, so make sure
2103 * to free the return value when finished with it.
2105 * The first arg is the number of path segments that follow.
2106 * The arguments following count are a list of path segments.
2107 * A path segment may be NULL.
2109 * Path segments will be added with a \ separating them.
2110 * A \ will not be added after the last segment, however if the
2111 * last segment is NULL, then the last character will be a \
2113 WCHAR *msi_build_directory_name( DWORD count, ... )
2119 va_start( va, count );
2120 for (i = 0; i < count; i++)
2122 const WCHAR *str = va_arg( va, const WCHAR * );
2123 if (str) sz += strlenW( str ) + 1;
2127 dir = msi_alloc( sz * sizeof(WCHAR) );
2130 va_start( va, count );
2131 for (i = 0; i < count; i++)
2133 const WCHAR *str = va_arg( va, const WCHAR * );
2135 strcatW( dir, str );
2136 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2142 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2144 MSIASSEMBLY *assembly = file->Component->assembly;
2146 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2148 msi_free( file->TargetPath );
2149 if (assembly && !assembly->application)
2151 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2152 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2153 msi_track_tempfile( package, file->TargetPath );
2157 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2158 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2161 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2164 static UINT calculate_file_cost( MSIPACKAGE *package )
2166 VS_FIXEDFILEINFO *file_version;
2167 WCHAR *font_version;
2170 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2172 MSICOMPONENT *comp = file->Component;
2175 if (!comp->Enabled) continue;
2177 if (file->IsCompressed)
2178 comp->ForceLocalState = TRUE;
2180 set_target_path( package, file );
2182 if ((comp->assembly && !comp->assembly->installed) ||
2183 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2185 comp->Cost += file->FileSize;
2188 file_size = msi_get_disk_file_size( file->TargetPath );
2192 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2194 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2196 comp->Cost += file->FileSize - file_size;
2198 msi_free( file_version );
2201 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2203 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2205 comp->Cost += file->FileSize - file_size;
2207 msi_free( font_version );
2211 if (file_size != file->FileSize)
2213 comp->Cost += file->FileSize - file_size;
2216 return ERROR_SUCCESS;
2219 WCHAR *msi_normalize_path( const WCHAR *in )
2221 const WCHAR *p = in;
2223 int n, len = strlenW( in ) + 2;
2225 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2230 /* copy until the end of the string or a space */
2231 while (*p != ' ' && (*q = *p))
2234 /* reduce many backslashes to one */
2235 if (*p != '\\' || *q != '\\')
2239 /* quit at the end of the string */
2243 /* count the number of spaces */
2248 /* if it's leading or trailing space, skip it */
2249 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2251 else /* copy n spaces */
2252 while (n && (*q++ = *p++)) n--;
2254 while (q - ret > 0 && q[-1] == ' ') q--;
2255 if (q - ret > 0 && q[-1] != '\\')
2263 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2266 MSIFOLDER *folder, *parent, *child;
2267 WCHAR *path, *normalized_path;
2269 TRACE("resolving %s\n", debugstr_w(name));
2271 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2273 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2275 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2277 path = msi_dup_property( package->db, szRootDrive );
2280 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2282 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2284 parent = msi_get_loaded_folder( package, folder->Parent );
2285 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2288 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2290 normalized_path = msi_normalize_path( path );
2292 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2294 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2295 msi_free( normalized_path );
2298 msi_set_property( package->db, folder->Directory, normalized_path );
2299 msi_free( folder->ResolvedTarget );
2300 folder->ResolvedTarget = normalized_path;
2302 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2305 msi_resolve_target_folder( package, child->Directory, load_prop );
2307 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2310 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2312 static const WCHAR query[] = {
2313 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2314 '`','C','o','n','d','i','t','i','o','n','`',0};
2315 static const WCHAR szOutOfDiskSpace[] = {
2316 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2322 TRACE("Building directory properties\n");
2323 msi_resolve_target_folder( package, szTargetDir, TRUE );
2325 TRACE("Evaluating component conditions\n");
2326 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2328 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2330 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2331 comp->Enabled = FALSE;
2334 comp->Enabled = TRUE;
2337 /* read components states from the registry */
2338 ACTION_GetComponentInstallStates(package);
2339 ACTION_GetFeatureInstallStates(package);
2341 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2343 TRACE("Evaluating feature conditions\n");
2345 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2346 if (rc == ERROR_SUCCESS)
2348 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2349 msiobj_release( &view->hdr );
2350 if (rc != ERROR_SUCCESS)
2355 TRACE("Calculating file cost\n");
2356 calculate_file_cost( package );
2358 msi_set_property( package->db, szCostingComplete, szOne );
2359 /* set default run level if not set */
2360 level = msi_dup_property( package->db, szInstallLevel );
2362 msi_set_property( package->db, szInstallLevel, szOne );
2365 /* FIXME: check volume disk space */
2366 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2368 return MSI_SetFeatureStates(package);
2371 /* OK this value is "interpreted" and then formatted based on the
2372 first few characters */
2373 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2378 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2384 LPWSTR deformated = NULL;
2387 deformat_string(package, &value[2], &deformated);
2389 /* binary value type */
2393 *size = (strlenW(ptr)/2)+1;
2395 *size = strlenW(ptr)/2;
2397 data = msi_alloc(*size);
2403 /* if uneven pad with a zero in front */
2409 data[count] = (BYTE)strtol(byte,NULL,0);
2411 TRACE("Uneven byte count\n");
2419 data[count] = (BYTE)strtol(byte,NULL,0);
2422 msi_free(deformated);
2424 TRACE("Data %i bytes(%i)\n",*size,count);
2431 deformat_string(package, &value[1], &deformated);
2434 *size = sizeof(DWORD);
2435 data = msi_alloc(*size);
2441 if ( (*p < '0') || (*p > '9') )
2447 if (deformated[0] == '-')
2450 TRACE("DWORD %i\n",*(LPDWORD)data);
2452 msi_free(deformated);
2457 static const WCHAR szMulti[] = {'[','~',']',0};
2466 *type=REG_EXPAND_SZ;
2474 if (strstrW(value, szMulti))
2475 *type = REG_MULTI_SZ;
2477 /* remove initial delimiter */
2478 if (!strncmpW(value, szMulti, 3))
2481 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2483 /* add double NULL terminator */
2484 if (*type == REG_MULTI_SZ)
2486 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2487 data = msi_realloc_zero(data, *size);
2493 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2500 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2502 *root_key = HKEY_LOCAL_MACHINE;
2507 *root_key = HKEY_CURRENT_USER;
2512 *root_key = HKEY_CLASSES_ROOT;
2516 *root_key = HKEY_CURRENT_USER;
2520 *root_key = HKEY_LOCAL_MACHINE;
2524 *root_key = HKEY_USERS;
2528 ERR("Unknown root %i\n", root);
2535 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2537 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2538 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2540 if (is_64bit && package->platform == PLATFORM_INTEL &&
2541 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2546 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2547 if (!(path_32node = msi_alloc( size ))) return NULL;
2549 memcpy( path_32node, path, len * sizeof(WCHAR) );
2550 strcpyW( path_32node + len, szWow6432Node );
2551 strcatW( path_32node, szBackSlash );
2552 strcatW( path_32node, path + len );
2556 return strdupW( path );
2559 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2561 MSIPACKAGE *package = param;
2562 LPSTR value_data = NULL;
2563 HKEY root_key, hkey;
2565 LPWSTR deformated, uikey, keypath;
2566 LPCWSTR szRoot, component, name, key, value;
2570 BOOL check_first = FALSE;
2573 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2575 component = MSI_RecordGetString(row, 6);
2576 comp = msi_get_loaded_component(package,component);
2578 return ERROR_SUCCESS;
2580 comp->Action = msi_get_component_action( package, comp );
2581 if (comp->Action != INSTALLSTATE_LOCAL)
2583 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2584 return ERROR_SUCCESS;
2587 name = MSI_RecordGetString(row, 4);
2588 if( MSI_RecordIsNull(row,5) && name )
2590 /* null values can have special meanings */
2591 if (name[0]=='-' && name[1] == 0)
2592 return ERROR_SUCCESS;
2593 else if ((name[0]=='+' && name[1] == 0) ||
2594 (name[0] == '*' && name[1] == 0))
2599 root = MSI_RecordGetInteger(row,2);
2600 key = MSI_RecordGetString(row, 3);
2602 szRoot = get_root_key( package, root, &root_key );
2604 return ERROR_SUCCESS;
2606 deformat_string(package, key , &deformated);
2607 size = strlenW(deformated) + strlenW(szRoot) + 1;
2608 uikey = msi_alloc(size*sizeof(WCHAR));
2609 strcpyW(uikey,szRoot);
2610 strcatW(uikey,deformated);
2612 keypath = get_keypath( package, root_key, deformated );
2613 msi_free( deformated );
2614 if (RegCreateKeyW( root_key, keypath, &hkey ))
2616 ERR("Could not create key %s\n", debugstr_w(keypath));
2619 return ERROR_SUCCESS;
2622 value = MSI_RecordGetString(row,5);
2624 value_data = parse_value(package, value, &type, &size);
2627 value_data = (LPSTR)strdupW(szEmpty);
2628 size = sizeof(szEmpty);
2632 deformat_string(package, name, &deformated);
2636 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2638 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2643 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2644 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2646 TRACE("value %s of %s checked already exists\n",
2647 debugstr_w(deformated), debugstr_w(uikey));
2651 TRACE("Checked and setting value %s of %s\n",
2652 debugstr_w(deformated), debugstr_w(uikey));
2653 if (deformated || size)
2654 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2659 uirow = MSI_CreateRecord(3);
2660 MSI_RecordSetStringW(uirow,2,deformated);
2661 MSI_RecordSetStringW(uirow,1,uikey);
2662 if (type == REG_SZ || type == REG_EXPAND_SZ)
2663 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2664 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2665 msiobj_release( &uirow->hdr );
2667 msi_free(value_data);
2668 msi_free(deformated);
2672 return ERROR_SUCCESS;
2675 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2677 static const WCHAR query[] = {
2678 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2679 '`','R','e','g','i','s','t','r','y','`',0};
2683 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2684 if (rc != ERROR_SUCCESS)
2685 return ERROR_SUCCESS;
2687 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2688 msiobj_release(&view->hdr);
2692 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2696 DWORD num_subkeys, num_values;
2698 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2700 if ((res = RegDeleteValueW( hkey, value )))
2702 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2704 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2705 NULL, NULL, NULL, NULL );
2706 RegCloseKey( hkey );
2707 if (!res && !num_subkeys && !num_values)
2709 TRACE("removing empty key %s\n", debugstr_w(keypath));
2710 RegDeleteKeyW( root, keypath );
2714 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2717 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2719 LONG res = RegDeleteTreeW( root, keypath );
2720 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2723 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2725 MSIPACKAGE *package = param;
2726 LPCWSTR component, name, key_str, root_key_str;
2727 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2730 BOOL delete_key = FALSE;
2735 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2737 component = MSI_RecordGetString( row, 6 );
2738 comp = msi_get_loaded_component( package, component );
2740 return ERROR_SUCCESS;
2742 comp->Action = msi_get_component_action( package, comp );
2743 if (comp->Action != INSTALLSTATE_ABSENT)
2745 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2746 return ERROR_SUCCESS;
2749 name = MSI_RecordGetString( row, 4 );
2750 if (MSI_RecordIsNull( row, 5 ) && name )
2752 if (name[0] == '+' && !name[1])
2753 return ERROR_SUCCESS;
2754 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2761 root = MSI_RecordGetInteger( row, 2 );
2762 key_str = MSI_RecordGetString( row, 3 );
2764 root_key_str = get_root_key( package, root, &hkey_root );
2766 return ERROR_SUCCESS;
2768 deformat_string( package, key_str, &deformated_key );
2769 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2770 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2771 strcpyW( ui_key_str, root_key_str );
2772 strcatW( ui_key_str, deformated_key );
2774 deformat_string( package, name, &deformated_name );
2776 keypath = get_keypath( package, hkey_root, deformated_key );
2777 msi_free( deformated_key );
2778 if (delete_key) delete_reg_key( hkey_root, keypath );
2779 else delete_reg_value( hkey_root, keypath, deformated_name );
2780 msi_free( keypath );
2782 uirow = MSI_CreateRecord( 2 );
2783 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2784 MSI_RecordSetStringW( uirow, 2, deformated_name );
2785 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2786 msiobj_release( &uirow->hdr );
2788 msi_free( ui_key_str );
2789 msi_free( deformated_name );
2790 return ERROR_SUCCESS;
2793 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2795 MSIPACKAGE *package = param;
2796 LPCWSTR component, name, key_str, root_key_str;
2797 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2800 BOOL delete_key = FALSE;
2805 component = MSI_RecordGetString( row, 5 );
2806 comp = msi_get_loaded_component( package, component );
2808 return ERROR_SUCCESS;
2810 comp->Action = msi_get_component_action( package, comp );
2811 if (comp->Action != INSTALLSTATE_LOCAL)
2813 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2814 return ERROR_SUCCESS;
2817 if ((name = MSI_RecordGetString( row, 4 )))
2819 if (name[0] == '-' && !name[1])
2826 root = MSI_RecordGetInteger( row, 2 );
2827 key_str = MSI_RecordGetString( row, 3 );
2829 root_key_str = get_root_key( package, root, &hkey_root );
2831 return ERROR_SUCCESS;
2833 deformat_string( package, key_str, &deformated_key );
2834 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2835 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2836 strcpyW( ui_key_str, root_key_str );
2837 strcatW( ui_key_str, deformated_key );
2839 deformat_string( package, name, &deformated_name );
2841 keypath = get_keypath( package, hkey_root, deformated_key );
2842 msi_free( deformated_key );
2843 if (delete_key) delete_reg_key( hkey_root, keypath );
2844 else delete_reg_value( hkey_root, keypath, deformated_name );
2845 msi_free( keypath );
2847 uirow = MSI_CreateRecord( 2 );
2848 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2849 MSI_RecordSetStringW( uirow, 2, deformated_name );
2850 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2851 msiobj_release( &uirow->hdr );
2853 msi_free( ui_key_str );
2854 msi_free( deformated_name );
2855 return ERROR_SUCCESS;
2858 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2860 static const WCHAR registry_query[] = {
2861 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2862 '`','R','e','g','i','s','t','r','y','`',0};
2863 static const WCHAR remove_registry_query[] = {
2864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2865 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2869 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2870 if (rc == ERROR_SUCCESS)
2872 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2873 msiobj_release( &view->hdr );
2874 if (rc != ERROR_SUCCESS)
2877 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2878 if (rc == ERROR_SUCCESS)
2880 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2881 msiobj_release( &view->hdr );
2882 if (rc != ERROR_SUCCESS)
2885 return ERROR_SUCCESS;
2888 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2890 package->script->CurrentlyScripting = TRUE;
2892 return ERROR_SUCCESS;
2896 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2898 static const WCHAR query[]= {
2899 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2900 '`','R','e','g','i','s','t','r','y','`',0};
2902 DWORD total = 0, count = 0;
2904 MSIFEATURE *feature;
2908 TRACE("InstallValidate\n");
2910 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2911 if (rc == ERROR_SUCCESS)
2913 rc = MSI_IterateRecords( view, &count, NULL, package );
2914 msiobj_release( &view->hdr );
2915 if (rc != ERROR_SUCCESS)
2917 total += count * REG_PROGRESS_VALUE;
2919 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2920 total += COMPONENT_PROGRESS_VALUE;
2922 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2923 total += file->FileSize;
2925 msi_ui_progress( package, 0, total, 0, 0 );
2927 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2929 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2930 debugstr_w(feature->Feature), feature->Installed,
2931 feature->ActionRequest, feature->Action);
2933 return ERROR_SUCCESS;
2936 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2938 MSIPACKAGE* package = param;
2939 LPCWSTR cond = NULL;
2940 LPCWSTR message = NULL;
2943 static const WCHAR title[]=
2944 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2946 cond = MSI_RecordGetString(row,1);
2948 r = MSI_EvaluateConditionW(package,cond);
2949 if (r == MSICONDITION_FALSE)
2951 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2954 message = MSI_RecordGetString(row,2);
2955 deformat_string(package,message,&deformated);
2956 MessageBoxW(NULL,deformated,title,MB_OK);
2957 msi_free(deformated);
2960 return ERROR_INSTALL_FAILURE;
2963 return ERROR_SUCCESS;
2966 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2968 static const WCHAR query[] = {
2969 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2970 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2974 TRACE("Checking launch conditions\n");
2976 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2977 if (rc != ERROR_SUCCESS)
2978 return ERROR_SUCCESS;
2980 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2981 msiobj_release(&view->hdr);
2985 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2989 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2991 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2993 static const WCHAR query[] = {
2994 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2995 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
2996 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
2997 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
2998 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3001 LPWSTR deformated, buffer, deformated_name;
3004 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3008 root = MSI_RecordGetInteger(row,2);
3009 key = MSI_RecordGetString(row, 3);
3010 name = MSI_RecordGetString(row, 4);
3011 deformat_string(package, key , &deformated);
3012 deformat_string(package, name, &deformated_name);
3014 len = strlenW(deformated) + 6;
3015 if (deformated_name)
3016 len+=strlenW(deformated_name);
3018 buffer = msi_alloc( len *sizeof(WCHAR));
3020 if (deformated_name)
3021 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3023 sprintfW(buffer,fmt,root,deformated);
3025 msi_free(deformated);
3026 msi_free(deformated_name);
3027 msiobj_release(&row->hdr);
3031 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3033 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3038 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3041 return strdupW( file->TargetPath );
3046 static HKEY openSharedDLLsKey(void)
3049 static const WCHAR path[] =
3050 {'S','o','f','t','w','a','r','e','\\',
3051 'M','i','c','r','o','s','o','f','t','\\',
3052 'W','i','n','d','o','w','s','\\',
3053 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3054 'S','h','a','r','e','d','D','L','L','s',0};
3056 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3060 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3065 DWORD sz = sizeof(count);
3068 hkey = openSharedDLLsKey();
3069 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3070 if (rc != ERROR_SUCCESS)
3076 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3080 hkey = openSharedDLLsKey();
3082 msi_reg_set_val_dword( hkey, path, count );
3084 RegDeleteValueW(hkey,path);
3089 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3091 MSIFEATURE *feature;
3095 /* only refcount DLLs */
3096 if (comp->KeyPath == NULL ||
3098 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3099 comp->Attributes & msidbComponentAttributesODBCDataSource)
3103 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3104 write = (count > 0);
3106 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3110 /* increment counts */
3111 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3115 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3118 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3120 if ( cl->component == comp )
3125 /* decrement counts */
3126 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3130 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3133 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3135 if ( cl->component == comp )
3140 /* ref count all the files in the component */
3145 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3147 if (file->Component == comp)
3148 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3152 /* add a count for permanent */
3153 if (comp->Attributes & msidbComponentAttributesPermanent)
3156 comp->RefCount = count;
3159 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3162 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3166 const WCHAR prefixW[] = {'<','\\',0};
3167 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3168 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3172 strcpyW( keypath, prefixW );
3173 strcatW( keypath, comp->assembly->display_name );
3177 return resolve_keypath( package, comp );
3180 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3182 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3189 squash_guid(package->ProductCode,squished_pc);
3190 msi_set_sourcedir_props(package, FALSE);
3192 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3195 INSTALLSTATE action;
3197 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3198 if (!comp->ComponentId)
3201 squash_guid( comp->ComponentId, squished_cc );
3202 msi_free( comp->FullKeypath );
3203 comp->FullKeypath = build_full_keypath( package, comp );
3205 ACTION_RefCountComponent( package, comp );
3207 if (package->need_rollback) action = comp->Installed;
3208 else action = comp->ActionRequest;
3210 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3211 debugstr_w(comp->Component), debugstr_w(squished_cc),
3212 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3214 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3216 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3217 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3219 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3221 if (rc != ERROR_SUCCESS)
3224 if (comp->Attributes & msidbComponentAttributesPermanent)
3226 static const WCHAR szPermKey[] =
3227 { '0','0','0','0','0','0','0','0','0','0','0','0',
3228 '0','0','0','0','0','0','0','0','0','0','0','0',
3229 '0','0','0','0','0','0','0','0',0 };
3231 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3233 if (action == INSTALLSTATE_LOCAL)
3234 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3240 WCHAR source[MAX_PATH];
3241 WCHAR base[MAX_PATH];
3244 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3245 static const WCHAR query[] = {
3246 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3247 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3248 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3249 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3250 '`','D','i','s','k','I','d','`',0};
3252 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3255 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3256 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3257 ptr2 = strrchrW(source, '\\') + 1;
3258 msiobj_release(&row->hdr);
3260 lstrcpyW(base, package->PackagePath);
3261 ptr = strrchrW(base, '\\');
3264 sourcepath = msi_resolve_file_source(package, file);
3265 ptr = sourcepath + lstrlenW(base);
3266 lstrcpyW(ptr2, ptr);
3267 msi_free(sourcepath);
3269 msi_reg_set_val_str(hkey, squished_pc, source);
3273 else if (action == INSTALLSTATE_ABSENT)
3275 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3276 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3278 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3282 uirow = MSI_CreateRecord(3);
3283 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3284 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3285 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3286 msi_ui_actiondata( package, szProcessComponents, uirow );
3287 msiobj_release( &uirow->hdr );
3289 return ERROR_SUCCESS;
3300 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3301 LPWSTR lpszName, LONG_PTR lParam)
3304 typelib_struct *tl_struct = (typelib_struct*) lParam;
3305 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3309 if (!IS_INTRESOURCE(lpszName))
3311 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3315 sz = strlenW(tl_struct->source)+4;
3316 sz *= sizeof(WCHAR);
3318 if ((INT_PTR)lpszName == 1)
3319 tl_struct->path = strdupW(tl_struct->source);
3322 tl_struct->path = msi_alloc(sz);
3323 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3326 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3327 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3330 msi_free(tl_struct->path);
3331 tl_struct->path = NULL;
3336 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3337 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3339 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3343 msi_free(tl_struct->path);
3344 tl_struct->path = NULL;
3346 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3347 ITypeLib_Release(tl_struct->ptLib);
3352 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3354 MSIPACKAGE* package = param;
3358 typelib_struct tl_struct;
3363 component = MSI_RecordGetString(row,3);
3364 comp = msi_get_loaded_component(package,component);
3366 return ERROR_SUCCESS;
3368 comp->Action = msi_get_component_action( package, comp );
3369 if (comp->Action != INSTALLSTATE_LOCAL)
3371 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3372 return ERROR_SUCCESS;
3375 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3377 TRACE("component has no key path\n");
3378 return ERROR_SUCCESS;
3380 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3382 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3386 guid = MSI_RecordGetString(row,1);
3387 CLSIDFromString( guid, &tl_struct.clsid);
3388 tl_struct.source = strdupW( file->TargetPath );
3389 tl_struct.path = NULL;
3391 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3392 (LONG_PTR)&tl_struct);
3396 LPCWSTR helpid, help_path = NULL;
3399 helpid = MSI_RecordGetString(row,6);
3401 if (helpid) help_path = msi_get_target_folder( package, helpid );
3402 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3405 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3407 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3409 ITypeLib_Release(tl_struct.ptLib);
3410 msi_free(tl_struct.path);
3412 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3414 FreeLibrary(module);
3415 msi_free(tl_struct.source);
3419 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3422 ERR("Failed to load type library: %08x\n", hr);
3423 return ERROR_INSTALL_FAILURE;
3426 ITypeLib_Release(tlib);
3429 return ERROR_SUCCESS;
3432 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3434 static const WCHAR query[] = {
3435 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3436 '`','T','y','p','e','L','i','b','`',0};
3440 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3441 if (rc != ERROR_SUCCESS)
3442 return ERROR_SUCCESS;
3444 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3445 msiobj_release(&view->hdr);
3449 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3451 MSIPACKAGE *package = param;
3452 LPCWSTR component, guid;
3460 component = MSI_RecordGetString( row, 3 );
3461 comp = msi_get_loaded_component( package, component );
3463 return ERROR_SUCCESS;
3465 comp->Action = msi_get_component_action( package, comp );
3466 if (comp->Action != INSTALLSTATE_ABSENT)
3468 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3469 return ERROR_SUCCESS;
3471 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3473 guid = MSI_RecordGetString( row, 1 );
3474 CLSIDFromString( guid, &libid );
3475 version = MSI_RecordGetInteger( row, 4 );
3476 language = MSI_RecordGetInteger( row, 2 );
3479 syskind = SYS_WIN64;
3481 syskind = SYS_WIN32;
3484 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3487 WARN("Failed to unregister typelib: %08x\n", hr);
3490 return ERROR_SUCCESS;
3493 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3495 static const WCHAR query[] = {
3496 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3497 '`','T','y','p','e','L','i','b','`',0};
3501 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3502 if (rc != ERROR_SUCCESS)
3503 return ERROR_SUCCESS;
3505 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3506 msiobj_release( &view->hdr );
3510 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3512 static const WCHAR szlnk[] = {'.','l','n','k',0};
3513 LPCWSTR directory, extension, link_folder;
3514 LPWSTR link_file, filename;
3516 directory = MSI_RecordGetString( row, 2 );
3517 link_folder = msi_get_target_folder( package, directory );
3520 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3523 /* may be needed because of a bug somewhere else */
3524 msi_create_full_path( link_folder );
3526 filename = msi_dup_record_field( row, 3 );
3527 msi_reduce_to_long_filename( filename );
3529 extension = strchrW( filename, '.' );
3530 if (!extension || strcmpiW( extension, szlnk ))
3532 int len = strlenW( filename );
3533 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3534 memcpy( filename + len, szlnk, sizeof(szlnk) );
3536 link_file = msi_build_directory_name( 2, link_folder, filename );
3537 msi_free( filename );
3542 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3544 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3545 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3546 WCHAR *folder, *dest, *path;
3548 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3549 folder = msi_dup_property( package->db, szWindowsFolder );
3552 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3553 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3554 msi_free( appdata );
3556 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3557 msi_create_full_path( dest );
3558 path = msi_build_directory_name( 2, dest, icon_name );
3564 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3566 MSIPACKAGE *package = param;
3567 LPWSTR link_file, deformated, path;
3568 LPCWSTR component, target;
3570 IShellLinkW *sl = NULL;
3571 IPersistFile *pf = NULL;
3574 component = MSI_RecordGetString(row, 4);
3575 comp = msi_get_loaded_component(package, component);
3577 return ERROR_SUCCESS;
3579 comp->Action = msi_get_component_action( package, comp );
3580 if (comp->Action != INSTALLSTATE_LOCAL)
3582 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3583 return ERROR_SUCCESS;
3585 msi_ui_actiondata( package, szCreateShortcuts, row );
3587 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3588 &IID_IShellLinkW, (LPVOID *) &sl );
3592 ERR("CLSID_ShellLink not available\n");
3596 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3599 ERR("QueryInterface(IID_IPersistFile) failed\n");
3603 target = MSI_RecordGetString(row, 5);
3604 if (strchrW(target, '['))
3606 deformat_string( package, target, &path );
3607 TRACE("target path is %s\n", debugstr_w(path));
3608 IShellLinkW_SetPath( sl, path );
3613 FIXME("poorly handled shortcut format, advertised shortcut\n");
3614 IShellLinkW_SetPath(sl,comp->FullKeypath);
3617 if (!MSI_RecordIsNull(row,6))
3619 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3620 deformat_string(package, arguments, &deformated);
3621 IShellLinkW_SetArguments(sl,deformated);
3622 msi_free(deformated);
3625 if (!MSI_RecordIsNull(row,7))
3627 LPCWSTR description = MSI_RecordGetString(row, 7);
3628 IShellLinkW_SetDescription(sl, description);
3631 if (!MSI_RecordIsNull(row,8))
3632 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3634 if (!MSI_RecordIsNull(row,9))
3637 LPCWSTR icon = MSI_RecordGetString(row, 9);
3639 path = msi_build_icon_path(package, icon);
3640 index = MSI_RecordGetInteger(row,10);
3642 /* no value means 0 */
3643 if (index == MSI_NULL_INTEGER)
3646 IShellLinkW_SetIconLocation(sl, path, index);
3650 if (!MSI_RecordIsNull(row,11))
3651 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3653 if (!MSI_RecordIsNull(row,12))
3655 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3656 full_path = msi_get_target_folder( package, wkdir );
3657 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3659 link_file = get_link_file(package, row);
3661 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3662 IPersistFile_Save(pf, link_file, FALSE);
3663 msi_free(link_file);
3667 IPersistFile_Release( pf );
3669 IShellLinkW_Release( sl );
3671 return ERROR_SUCCESS;
3674 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3676 static const WCHAR query[] = {
3677 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3678 '`','S','h','o','r','t','c','u','t','`',0};
3683 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3684 if (rc != ERROR_SUCCESS)
3685 return ERROR_SUCCESS;
3687 res = CoInitialize( NULL );
3689 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3690 msiobj_release(&view->hdr);
3692 if (SUCCEEDED(res)) CoUninitialize();
3696 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3698 MSIPACKAGE *package = param;
3703 component = MSI_RecordGetString( row, 4 );
3704 comp = msi_get_loaded_component( package, component );
3706 return ERROR_SUCCESS;
3708 comp->Action = msi_get_component_action( package, comp );
3709 if (comp->Action != INSTALLSTATE_ABSENT)
3711 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3712 return ERROR_SUCCESS;
3714 msi_ui_actiondata( package, szRemoveShortcuts, row );
3716 link_file = get_link_file( package, row );
3718 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3719 if (!DeleteFileW( link_file ))
3721 WARN("Failed to remove shortcut file %u\n", GetLastError());
3723 msi_free( link_file );
3725 return ERROR_SUCCESS;
3728 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3730 static const WCHAR query[] = {
3731 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3732 '`','S','h','o','r','t','c','u','t','`',0};
3736 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3737 if (rc != ERROR_SUCCESS)
3738 return ERROR_SUCCESS;
3740 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3741 msiobj_release( &view->hdr );
3745 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3747 MSIPACKAGE* package = param;
3755 FileName = MSI_RecordGetString(row,1);
3758 ERR("Unable to get FileName\n");
3759 return ERROR_SUCCESS;
3762 FilePath = msi_build_icon_path(package, FileName);
3764 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3766 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3767 FILE_ATTRIBUTE_NORMAL, NULL);
3769 if (the_file == INVALID_HANDLE_VALUE)
3771 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3773 return ERROR_SUCCESS;
3780 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3781 if (rc != ERROR_SUCCESS)
3783 ERR("Failed to get stream\n");
3784 CloseHandle(the_file);
3785 DeleteFileW(FilePath);
3788 WriteFile(the_file,buffer,sz,&write,NULL);
3789 } while (sz == 1024);
3792 CloseHandle(the_file);
3794 return ERROR_SUCCESS;
3797 static UINT msi_publish_icons(MSIPACKAGE *package)
3799 static const WCHAR query[]= {
3800 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3801 '`','I','c','o','n','`',0};
3805 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3806 if (r == ERROR_SUCCESS)
3808 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3809 msiobj_release(&view->hdr);
3810 if (r != ERROR_SUCCESS)
3813 return ERROR_SUCCESS;
3816 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3822 MSISOURCELISTINFO *info;
3824 r = RegCreateKeyW(hkey, szSourceList, &source);
3825 if (r != ERROR_SUCCESS)
3828 RegCloseKey(source);
3830 buffer = strrchrW(package->PackagePath, '\\') + 1;
3831 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3832 package->Context, MSICODE_PRODUCT,
3833 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3834 if (r != ERROR_SUCCESS)
3837 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3838 package->Context, MSICODE_PRODUCT,
3839 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3840 if (r != ERROR_SUCCESS)
3843 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3844 package->Context, MSICODE_PRODUCT,
3845 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3846 if (r != ERROR_SUCCESS)
3849 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3851 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3852 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3853 info->options, info->value);
3855 MsiSourceListSetInfoW(package->ProductCode, NULL,
3856 info->context, info->options,
3857 info->property, info->value);
3860 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3862 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3863 disk->context, disk->options,
3864 disk->disk_id, disk->volume_label, disk->disk_prompt);
3867 return ERROR_SUCCESS;
3870 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3872 MSIHANDLE hdb, suminfo;
3873 WCHAR guids[MAX_PATH];
3874 WCHAR packcode[SQUISH_GUID_SIZE];
3881 static const WCHAR szARPProductIcon[] =
3882 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3883 static const WCHAR szAssignment[] =
3884 {'A','s','s','i','g','n','m','e','n','t',0};
3885 static const WCHAR szAdvertiseFlags[] =
3886 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3887 static const WCHAR szClients[] =
3888 {'C','l','i','e','n','t','s',0};
3889 static const WCHAR szColon[] = {':',0};
3891 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3892 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3895 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3896 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3899 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3901 buffer = msi_dup_property(package->db, szARPProductIcon);
3904 LPWSTR path = msi_build_icon_path(package, buffer);
3905 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3910 buffer = msi_dup_property(package->db, szProductVersion);
3913 DWORD verdword = msi_version_str_to_dword(buffer);
3914 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3918 msi_reg_set_val_dword(hkey, szAssignment, 0);
3919 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3921 msi_reg_set_val_str(hkey, szClients, szColon);
3923 hdb = alloc_msihandle(&package->db->hdr);
3925 return ERROR_NOT_ENOUGH_MEMORY;
3927 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3928 MsiCloseHandle(hdb);
3929 if (r != ERROR_SUCCESS)
3933 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3934 NULL, guids, &size);
3935 if (r != ERROR_SUCCESS)
3938 ptr = strchrW(guids, ';');
3940 squash_guid(guids, packcode);
3941 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3944 MsiCloseHandle(suminfo);
3945 return ERROR_SUCCESS;
3948 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3953 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3955 upgrade = msi_dup_property(package->db, szUpgradeCode);
3957 return ERROR_SUCCESS;
3959 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3960 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3962 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3964 if (r != ERROR_SUCCESS)
3966 WARN("failed to open upgrade code key\n");
3968 return ERROR_SUCCESS;
3970 squash_guid(package->ProductCode, squashed_pc);
3971 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3974 return ERROR_SUCCESS;
3977 static BOOL msi_check_publish(MSIPACKAGE *package)
3979 MSIFEATURE *feature;
3981 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3983 feature->Action = msi_get_feature_action( package, feature );
3984 if (feature->Action == INSTALLSTATE_LOCAL)
3991 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3993 MSIFEATURE *feature;
3995 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3997 feature->Action = msi_get_feature_action( package, feature );
3998 if (feature->Action != INSTALLSTATE_ABSENT)
4005 static UINT msi_publish_patches( MSIPACKAGE *package )
4007 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4008 WCHAR patch_squashed[GUID_SIZE];
4009 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4011 MSIPATCHINFO *patch;
4013 WCHAR *p, *all_patches = NULL;
4016 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4017 if (r != ERROR_SUCCESS)
4018 return ERROR_FUNCTION_FAILED;
4020 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4021 if (res != ERROR_SUCCESS)
4023 r = ERROR_FUNCTION_FAILED;
4027 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4028 if (r != ERROR_SUCCESS)
4031 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4033 squash_guid( patch->patchcode, patch_squashed );
4034 len += strlenW( patch_squashed ) + 1;
4037 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4041 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4045 squash_guid( patch->patchcode, p );
4046 p += strlenW( p ) + 1;
4048 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4049 (const BYTE *)patch->transforms,
4050 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4051 if (res != ERROR_SUCCESS)
4054 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4055 if (r != ERROR_SUCCESS)
4058 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4059 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4060 RegCloseKey( patch_key );
4061 if (res != ERROR_SUCCESS)
4064 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4066 res = GetLastError();
4067 ERR("Unable to copy patch package %d\n", res);
4070 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4071 if (res != ERROR_SUCCESS)
4074 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4075 RegCloseKey( patch_key );
4076 if (res != ERROR_SUCCESS)
4080 all_patches[len] = 0;
4081 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4082 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4083 if (res != ERROR_SUCCESS)
4086 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4087 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4088 if (res != ERROR_SUCCESS)
4089 r = ERROR_FUNCTION_FAILED;
4092 RegCloseKey( product_patches_key );
4093 RegCloseKey( patches_key );
4094 RegCloseKey( product_key );
4095 msi_free( all_patches );
4099 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4102 HKEY hukey = NULL, hudkey = NULL;
4105 if (!list_empty(&package->patches))
4107 rc = msi_publish_patches(package);
4108 if (rc != ERROR_SUCCESS)
4112 /* FIXME: also need to publish if the product is in advertise mode */
4113 if (!msi_check_publish(package))
4114 return ERROR_SUCCESS;
4116 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4118 if (rc != ERROR_SUCCESS)
4121 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4122 NULL, &hudkey, TRUE);
4123 if (rc != ERROR_SUCCESS)
4126 rc = msi_publish_upgrade_code(package);
4127 if (rc != ERROR_SUCCESS)
4130 rc = msi_publish_product_properties(package, hukey);
4131 if (rc != ERROR_SUCCESS)
4134 rc = msi_publish_sourcelist(package, hukey);
4135 if (rc != ERROR_SUCCESS)
4138 rc = msi_publish_icons(package);
4141 uirow = MSI_CreateRecord( 1 );
4142 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4143 msi_ui_actiondata( package, szPublishProduct, uirow );
4144 msiobj_release( &uirow->hdr );
4147 RegCloseKey(hudkey);
4151 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4153 WCHAR *filename, *ptr, *folder, *ret;
4154 const WCHAR *dirprop;
4156 filename = msi_dup_record_field( row, 2 );
4157 if (filename && (ptr = strchrW( filename, '|' )))
4162 dirprop = MSI_RecordGetString( row, 3 );
4165 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4166 if (!folder) folder = msi_dup_property( package->db, dirprop );
4169 folder = msi_dup_property( package->db, szWindowsFolder );
4173 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4174 msi_free( filename );
4178 ret = msi_build_directory_name( 2, folder, ptr );
4180 msi_free( filename );
4185 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4187 MSIPACKAGE *package = param;
4188 LPCWSTR component, section, key, value, identifier;
4189 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4194 component = MSI_RecordGetString(row, 8);
4195 comp = msi_get_loaded_component(package,component);
4197 return ERROR_SUCCESS;
4199 comp->Action = msi_get_component_action( package, comp );
4200 if (comp->Action != INSTALLSTATE_LOCAL)
4202 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4203 return ERROR_SUCCESS;
4206 identifier = MSI_RecordGetString(row,1);
4207 section = MSI_RecordGetString(row,4);
4208 key = MSI_RecordGetString(row,5);
4209 value = MSI_RecordGetString(row,6);
4210 action = MSI_RecordGetInteger(row,7);
4212 deformat_string(package,section,&deformated_section);
4213 deformat_string(package,key,&deformated_key);
4214 deformat_string(package,value,&deformated_value);
4216 fullname = get_ini_file_name(package, row);
4220 TRACE("Adding value %s to section %s in %s\n",
4221 debugstr_w(deformated_key), debugstr_w(deformated_section),
4222 debugstr_w(fullname));
4223 WritePrivateProfileStringW(deformated_section, deformated_key,
4224 deformated_value, fullname);
4226 else if (action == 1)
4229 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4230 returned, 10, fullname);
4231 if (returned[0] == 0)
4233 TRACE("Adding value %s to section %s in %s\n",
4234 debugstr_w(deformated_key), debugstr_w(deformated_section),
4235 debugstr_w(fullname));
4237 WritePrivateProfileStringW(deformated_section, deformated_key,
4238 deformated_value, fullname);
4241 else if (action == 3)
4242 FIXME("Append to existing section not yet implemented\n");
4244 uirow = MSI_CreateRecord(4);
4245 MSI_RecordSetStringW(uirow,1,identifier);
4246 MSI_RecordSetStringW(uirow,2,deformated_section);
4247 MSI_RecordSetStringW(uirow,3,deformated_key);
4248 MSI_RecordSetStringW(uirow,4,deformated_value);
4249 msi_ui_actiondata( package, szWriteIniValues, uirow );
4250 msiobj_release( &uirow->hdr );
4253 msi_free(deformated_key);
4254 msi_free(deformated_value);
4255 msi_free(deformated_section);
4256 return ERROR_SUCCESS;
4259 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4261 static const WCHAR query[] = {
4262 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4263 '`','I','n','i','F','i','l','e','`',0};
4267 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4268 if (rc != ERROR_SUCCESS)
4269 return ERROR_SUCCESS;
4271 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4272 msiobj_release(&view->hdr);
4276 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4278 MSIPACKAGE *package = param;
4279 LPCWSTR component, section, key, value, identifier;
4280 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4285 component = MSI_RecordGetString( row, 8 );
4286 comp = msi_get_loaded_component( package, component );
4288 return ERROR_SUCCESS;
4290 comp->Action = msi_get_component_action( package, comp );
4291 if (comp->Action != INSTALLSTATE_ABSENT)
4293 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4294 return ERROR_SUCCESS;
4297 identifier = MSI_RecordGetString( row, 1 );
4298 section = MSI_RecordGetString( row, 4 );
4299 key = MSI_RecordGetString( row, 5 );
4300 value = MSI_RecordGetString( row, 6 );
4301 action = MSI_RecordGetInteger( row, 7 );
4303 deformat_string( package, section, &deformated_section );
4304 deformat_string( package, key, &deformated_key );
4305 deformat_string( package, value, &deformated_value );
4307 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4309 filename = get_ini_file_name( package, row );
4311 TRACE("Removing key %s from section %s in %s\n",
4312 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4314 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4316 WARN("Unable to remove key %u\n", GetLastError());
4318 msi_free( filename );
4321 FIXME("Unsupported action %d\n", action);
4324 uirow = MSI_CreateRecord( 4 );
4325 MSI_RecordSetStringW( uirow, 1, identifier );
4326 MSI_RecordSetStringW( uirow, 2, deformated_section );
4327 MSI_RecordSetStringW( uirow, 3, deformated_key );
4328 MSI_RecordSetStringW( uirow, 4, deformated_value );
4329 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4330 msiobj_release( &uirow->hdr );
4332 msi_free( deformated_key );
4333 msi_free( deformated_value );
4334 msi_free( deformated_section );
4335 return ERROR_SUCCESS;
4338 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4340 MSIPACKAGE *package = param;
4341 LPCWSTR component, section, key, value, identifier;
4342 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4347 component = MSI_RecordGetString( row, 8 );
4348 comp = msi_get_loaded_component( package, component );
4350 return ERROR_SUCCESS;
4352 comp->Action = msi_get_component_action( package, comp );
4353 if (comp->Action != INSTALLSTATE_LOCAL)
4355 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4356 return ERROR_SUCCESS;
4359 identifier = MSI_RecordGetString( row, 1 );
4360 section = MSI_RecordGetString( row, 4 );
4361 key = MSI_RecordGetString( row, 5 );
4362 value = MSI_RecordGetString( row, 6 );
4363 action = MSI_RecordGetInteger( row, 7 );
4365 deformat_string( package, section, &deformated_section );
4366 deformat_string( package, key, &deformated_key );
4367 deformat_string( package, value, &deformated_value );
4369 if (action == msidbIniFileActionRemoveLine)
4371 filename = get_ini_file_name( package, row );
4373 TRACE("Removing key %s from section %s in %s\n",
4374 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4376 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4378 WARN("Unable to remove key %u\n", GetLastError());
4380 msi_free( filename );
4383 FIXME("Unsupported action %d\n", action);
4385 uirow = MSI_CreateRecord( 4 );
4386 MSI_RecordSetStringW( uirow, 1, identifier );
4387 MSI_RecordSetStringW( uirow, 2, deformated_section );
4388 MSI_RecordSetStringW( uirow, 3, deformated_key );
4389 MSI_RecordSetStringW( uirow, 4, deformated_value );
4390 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4391 msiobj_release( &uirow->hdr );
4393 msi_free( deformated_key );
4394 msi_free( deformated_value );
4395 msi_free( deformated_section );
4396 return ERROR_SUCCESS;
4399 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4401 static const WCHAR query[] = {
4402 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4403 '`','I','n','i','F','i','l','e','`',0};
4404 static const WCHAR remove_query[] = {
4405 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4406 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4410 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4411 if (rc == ERROR_SUCCESS)
4413 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4414 msiobj_release( &view->hdr );
4415 if (rc != ERROR_SUCCESS)
4418 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4419 if (rc == ERROR_SUCCESS)
4421 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4422 msiobj_release( &view->hdr );
4423 if (rc != ERROR_SUCCESS)
4426 return ERROR_SUCCESS;
4429 static void register_dll( const WCHAR *dll, BOOL unregister )
4433 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4436 HRESULT (WINAPI *func_ptr)( void );
4437 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4439 func_ptr = (void *)GetProcAddress( hmod, func );
4442 HRESULT hr = func_ptr();
4444 WARN("failed to register dll 0x%08x\n", hr);
4447 WARN("entry point %s not found\n", func);
4448 FreeLibrary( hmod );
4451 WARN("failed to load library %u\n", GetLastError());
4454 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4456 MSIPACKAGE *package = param;
4461 filename = MSI_RecordGetString( row, 1 );
4462 file = msi_get_loaded_file( package, filename );
4465 WARN("unable to find file %s\n", debugstr_w(filename));
4466 return ERROR_SUCCESS;
4468 file->Component->Action = msi_get_component_action( package, file->Component );
4469 if (file->Component->Action != INSTALLSTATE_LOCAL)
4471 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4472 return ERROR_SUCCESS;
4475 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4476 register_dll( file->TargetPath, FALSE );
4478 uirow = MSI_CreateRecord( 2 );
4479 MSI_RecordSetStringW( uirow, 1, file->File );
4480 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4481 msi_ui_actiondata( package, szSelfRegModules, uirow );
4482 msiobj_release( &uirow->hdr );
4484 return ERROR_SUCCESS;
4487 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4489 static const WCHAR query[] = {
4490 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4491 '`','S','e','l','f','R','e','g','`',0};
4495 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4496 if (rc != ERROR_SUCCESS)
4497 return ERROR_SUCCESS;
4499 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4500 msiobj_release(&view->hdr);
4504 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4506 MSIPACKAGE *package = param;
4511 filename = MSI_RecordGetString( row, 1 );
4512 file = msi_get_loaded_file( package, filename );
4515 WARN("unable to find file %s\n", debugstr_w(filename));
4516 return ERROR_SUCCESS;
4518 file->Component->Action = msi_get_component_action( package, file->Component );
4519 if (file->Component->Action != INSTALLSTATE_ABSENT)
4521 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4522 return ERROR_SUCCESS;
4525 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4526 register_dll( file->TargetPath, TRUE );
4528 uirow = MSI_CreateRecord( 2 );
4529 MSI_RecordSetStringW( uirow, 1, file->File );
4530 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4531 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4532 msiobj_release( &uirow->hdr );
4534 return ERROR_SUCCESS;
4537 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4539 static const WCHAR query[] = {
4540 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4541 '`','S','e','l','f','R','e','g','`',0};
4545 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4546 if (rc != ERROR_SUCCESS)
4547 return ERROR_SUCCESS;
4549 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4550 msiobj_release( &view->hdr );
4554 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4556 MSIFEATURE *feature;
4558 HKEY hkey = NULL, userdata = NULL;
4560 if (!msi_check_publish(package))
4561 return ERROR_SUCCESS;
4563 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4565 if (rc != ERROR_SUCCESS)
4568 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4570 if (rc != ERROR_SUCCESS)
4573 /* here the guids are base 85 encoded */
4574 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4580 BOOL absent = FALSE;
4583 if (feature->Action != INSTALLSTATE_LOCAL &&
4584 feature->Action != INSTALLSTATE_SOURCE &&
4585 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4588 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4592 if (feature->Feature_Parent)
4593 size += strlenW( feature->Feature_Parent )+2;
4595 data = msi_alloc(size * sizeof(WCHAR));
4598 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4600 MSICOMPONENT* component = cl->component;
4604 if (component->ComponentId)
4606 TRACE("From %s\n",debugstr_w(component->ComponentId));
4607 CLSIDFromString(component->ComponentId, &clsid);
4608 encode_base85_guid(&clsid,buf);
4609 TRACE("to %s\n",debugstr_w(buf));
4614 if (feature->Feature_Parent)
4616 static const WCHAR sep[] = {'\2',0};
4618 strcatW(data,feature->Feature_Parent);
4621 msi_reg_set_val_str( userdata, feature->Feature, data );
4625 if (feature->Feature_Parent)
4626 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4629 size += sizeof(WCHAR);
4630 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4631 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4635 size += 2*sizeof(WCHAR);
4636 data = msi_alloc(size);
4639 if (feature->Feature_Parent)
4640 strcpyW( &data[1], feature->Feature_Parent );
4641 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4647 uirow = MSI_CreateRecord( 1 );
4648 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4649 msi_ui_actiondata( package, szPublishFeatures, uirow );
4650 msiobj_release( &uirow->hdr );
4651 /* FIXME: call msi_ui_progress? */
4656 RegCloseKey(userdata);
4660 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4666 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4668 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4670 if (r == ERROR_SUCCESS)
4672 RegDeleteValueW(hkey, feature->Feature);
4676 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4678 if (r == ERROR_SUCCESS)
4680 RegDeleteValueW(hkey, feature->Feature);
4684 uirow = MSI_CreateRecord( 1 );
4685 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4686 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4687 msiobj_release( &uirow->hdr );
4689 return ERROR_SUCCESS;
4692 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4694 MSIFEATURE *feature;
4696 if (!msi_check_unpublish(package))
4697 return ERROR_SUCCESS;
4699 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4701 msi_unpublish_feature(package, feature);
4704 return ERROR_SUCCESS;
4707 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4711 WCHAR date[9], *val, *buffer;
4712 const WCHAR *prop, *key;
4714 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4715 static const WCHAR modpath_fmt[] =
4716 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4717 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4718 static const WCHAR szModifyPath[] =
4719 {'M','o','d','i','f','y','P','a','t','h',0};
4720 static const WCHAR szUninstallString[] =
4721 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4722 static const WCHAR szEstimatedSize[] =
4723 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4724 static const WCHAR szDisplayVersion[] =
4725 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4726 static const WCHAR szInstallSource[] =
4727 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4728 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4729 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4730 static const WCHAR szAuthorizedCDFPrefix[] =
4731 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4732 static const WCHAR szARPCONTACT[] =
4733 {'A','R','P','C','O','N','T','A','C','T',0};
4734 static const WCHAR szContact[] =
4735 {'C','o','n','t','a','c','t',0};
4736 static const WCHAR szARPCOMMENTS[] =
4737 {'A','R','P','C','O','M','M','E','N','T','S',0};
4738 static const WCHAR szComments[] =
4739 {'C','o','m','m','e','n','t','s',0};
4740 static const WCHAR szProductName[] =
4741 {'P','r','o','d','u','c','t','N','a','m','e',0};
4742 static const WCHAR szDisplayName[] =
4743 {'D','i','s','p','l','a','y','N','a','m','e',0};
4744 static const WCHAR szARPHELPLINK[] =
4745 {'A','R','P','H','E','L','P','L','I','N','K',0};
4746 static const WCHAR szHelpLink[] =
4747 {'H','e','l','p','L','i','n','k',0};
4748 static const WCHAR szARPHELPTELEPHONE[] =
4749 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4750 static const WCHAR szHelpTelephone[] =
4751 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4752 static const WCHAR szARPINSTALLLOCATION[] =
4753 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4754 static const WCHAR szInstallLocation[] =
4755 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4756 static const WCHAR szManufacturer[] =
4757 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4758 static const WCHAR szPublisher[] =
4759 {'P','u','b','l','i','s','h','e','r',0};
4760 static const WCHAR szARPREADME[] =
4761 {'A','R','P','R','E','A','D','M','E',0};
4762 static const WCHAR szReadme[] =
4763 {'R','e','a','d','M','e',0};
4764 static const WCHAR szARPSIZE[] =
4765 {'A','R','P','S','I','Z','E',0};
4766 static const WCHAR szSize[] =
4767 {'S','i','z','e',0};
4768 static const WCHAR szARPURLINFOABOUT[] =
4769 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4770 static const WCHAR szURLInfoAbout[] =
4771 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4772 static const WCHAR szARPURLUPDATEINFO[] =
4773 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4774 static const WCHAR szURLUpdateInfo[] =
4775 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4776 static const WCHAR szARPSYSTEMCOMPONENT[] =
4777 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4778 static const WCHAR szSystemComponent[] =
4779 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4781 static const WCHAR *propval[] = {
4782 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4783 szARPCONTACT, szContact,
4784 szARPCOMMENTS, szComments,
4785 szProductName, szDisplayName,
4786 szARPHELPLINK, szHelpLink,
4787 szARPHELPTELEPHONE, szHelpTelephone,
4788 szARPINSTALLLOCATION, szInstallLocation,
4789 szSourceDir, szInstallSource,
4790 szManufacturer, szPublisher,
4791 szARPREADME, szReadme,
4793 szARPURLINFOABOUT, szURLInfoAbout,
4794 szARPURLUPDATEINFO, szURLUpdateInfo,
4797 const WCHAR **p = propval;
4803 val = msi_dup_property(package->db, prop);
4804 msi_reg_set_val_str(hkey, key, val);
4808 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4809 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4811 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4813 size = deformat_string(package, modpath_fmt, &buffer);
4814 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4815 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4818 /* FIXME: Write real Estimated Size when we have it */
4819 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4821 GetLocalTime(&systime);
4822 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4823 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4825 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4826 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4828 buffer = msi_dup_property(package->db, szProductVersion);
4829 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4832 DWORD verdword = msi_version_str_to_dword(buffer);
4834 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4835 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4836 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4840 return ERROR_SUCCESS;
4843 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4845 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4847 LPWSTR upgrade_code;
4848 HKEY hkey, props, upgrade_key;
4851 /* FIXME: also need to publish if the product is in advertise mode */
4852 if (!msi_check_publish(package))
4853 return ERROR_SUCCESS;
4855 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4856 if (rc != ERROR_SUCCESS)
4859 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4860 if (rc != ERROR_SUCCESS)
4863 rc = msi_publish_install_properties(package, hkey);
4864 if (rc != ERROR_SUCCESS)
4867 rc = msi_publish_install_properties(package, props);
4868 if (rc != ERROR_SUCCESS)
4871 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4874 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4875 if (rc == ERROR_SUCCESS)
4877 squash_guid( package->ProductCode, squashed_pc );
4878 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4879 RegCloseKey( upgrade_key );
4881 msi_free( upgrade_code );
4883 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4884 package->delete_on_close = FALSE;
4887 uirow = MSI_CreateRecord( 1 );
4888 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4889 msi_ui_actiondata( package, szRegisterProduct, uirow );
4890 msiobj_release( &uirow->hdr );
4893 return ERROR_SUCCESS;
4896 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4898 return execute_script(package, SCRIPT_INSTALL);
4901 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4903 MSIPACKAGE *package = param;
4904 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4905 WCHAR *p, *icon_path;
4907 if (!icon) return ERROR_SUCCESS;
4908 if ((icon_path = msi_build_icon_path( package, icon )))
4910 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4911 DeleteFileW( icon_path );
4912 if ((p = strrchrW( icon_path, '\\' )))
4915 RemoveDirectoryW( icon_path );
4917 msi_free( icon_path );
4919 return ERROR_SUCCESS;
4922 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4924 static const WCHAR query[]= {
4925 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4929 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4930 if (r == ERROR_SUCCESS)
4932 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4933 msiobj_release( &view->hdr );
4934 if (r != ERROR_SUCCESS)
4937 return ERROR_SUCCESS;
4940 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4942 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4943 WCHAR *upgrade, **features;
4944 BOOL full_uninstall = TRUE;
4945 MSIFEATURE *feature;
4946 MSIPATCHINFO *patch;
4949 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4951 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4953 features = msi_split_string( remove, ',' );
4954 for (i = 0; features && features[i]; i++)
4956 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4960 if (!full_uninstall)
4961 return ERROR_SUCCESS;
4963 MSIREG_DeleteProductKey(package->ProductCode);
4964 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4965 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4967 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4968 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4969 MSIREG_DeleteUserProductKey(package->ProductCode);
4970 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4972 upgrade = msi_dup_property(package->db, szUpgradeCode);
4975 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4976 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4980 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4982 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4983 if (!strcmpW( package->ProductCode, patch->products ))
4985 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
4986 patch->delete_on_close = TRUE;
4988 /* FIXME: remove local patch package if this is the last product */
4990 TRACE("removing local package %s\n", debugstr_w(package->localfile));
4991 package->delete_on_close = TRUE;
4993 msi_unpublish_icons( package );
4994 return ERROR_SUCCESS;
4997 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5002 /* turn off scheduling */
5003 package->script->CurrentlyScripting= FALSE;
5005 /* first do the same as an InstallExecute */
5006 rc = ACTION_InstallExecute(package);
5007 if (rc != ERROR_SUCCESS)
5010 /* then handle commit actions */
5011 rc = execute_script(package, SCRIPT_COMMIT);
5012 if (rc != ERROR_SUCCESS)
5015 remove = msi_dup_property(package->db, szRemove);
5016 rc = msi_unpublish_product(package, remove);
5021 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5023 static const WCHAR RunOnce[] = {
5024 'S','o','f','t','w','a','r','e','\\',
5025 'M','i','c','r','o','s','o','f','t','\\',
5026 'W','i','n','d','o','w','s','\\',
5027 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5028 'R','u','n','O','n','c','e',0};
5029 static const WCHAR InstallRunOnce[] = {
5030 'S','o','f','t','w','a','r','e','\\',
5031 'M','i','c','r','o','s','o','f','t','\\',
5032 'W','i','n','d','o','w','s','\\',
5033 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5034 'I','n','s','t','a','l','l','e','r','\\',
5035 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5037 static const WCHAR msiexec_fmt[] = {
5039 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5040 '\"','%','s','\"',0};
5041 static const WCHAR install_fmt[] = {
5042 '/','I',' ','\"','%','s','\"',' ',
5043 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5044 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5045 WCHAR buffer[256], sysdir[MAX_PATH];
5047 WCHAR squished_pc[100];
5049 squash_guid(package->ProductCode,squished_pc);
5051 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5052 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5053 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5056 msi_reg_set_val_str( hkey, squished_pc, buffer );
5059 TRACE("Reboot command %s\n",debugstr_w(buffer));
5061 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5062 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5064 msi_reg_set_val_str( hkey, squished_pc, buffer );
5067 return ERROR_INSTALL_SUSPEND;
5070 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5072 static const WCHAR query[] =
5073 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5074 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5075 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5076 MSIRECORD *rec, *row;
5082 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5084 rec = MSI_CreateRecord( count + 2 );
5085 str = MSI_RecordGetString( row, 1 );
5086 MSI_RecordSetStringW( rec, 0, str );
5087 msiobj_release( &row->hdr );
5088 MSI_RecordSetInteger( rec, 1, error );
5090 va_start( va, count );
5091 for (i = 0; i < count; i++)
5093 str = va_arg( va, const WCHAR *);
5094 MSI_RecordSetStringW( rec, i + 2, str );
5098 MSI_FormatRecordW( package, rec, NULL, &size );
5100 data = msi_alloc( size * sizeof(WCHAR) );
5101 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5103 msiobj_release( &rec->hdr );
5107 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5113 * We are currently doing what should be done here in the top level Install
5114 * however for Administrative and uninstalls this step will be needed
5116 if (!package->PackagePath)
5117 return ERROR_SUCCESS;
5119 msi_set_sourcedir_props(package, TRUE);
5121 attrib = GetFileAttributesW(package->db->path);
5122 if (attrib == INVALID_FILE_ATTRIBUTES)
5127 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5128 package->Context, MSICODE_PRODUCT,
5129 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5130 if (rc == ERROR_MORE_DATA)
5132 prompt = msi_alloc(size * sizeof(WCHAR));
5133 MsiSourceListGetInfoW(package->ProductCode, NULL,
5134 package->Context, MSICODE_PRODUCT,
5135 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5138 prompt = strdupW(package->db->path);
5140 msg = msi_build_error_string(package, 1302, 1, prompt);
5142 while(attrib == INVALID_FILE_ATTRIBUTES)
5144 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5148 return ERROR_INSTALL_USEREXIT;
5150 attrib = GetFileAttributesW(package->db->path);
5156 return ERROR_SUCCESS;
5161 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5164 LPWSTR buffer, productid = NULL;
5165 UINT i, rc = ERROR_SUCCESS;
5168 static const WCHAR szPropKeys[][80] =
5170 {'P','r','o','d','u','c','t','I','D',0},
5171 {'U','S','E','R','N','A','M','E',0},
5172 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5176 static const WCHAR szRegKeys[][80] =
5178 {'P','r','o','d','u','c','t','I','D',0},
5179 {'R','e','g','O','w','n','e','r',0},
5180 {'R','e','g','C','o','m','p','a','n','y',0},
5184 if (msi_check_unpublish(package))
5186 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5190 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5194 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5196 if (rc != ERROR_SUCCESS)
5199 for( i = 0; szPropKeys[i][0]; i++ )
5201 buffer = msi_dup_property( package->db, szPropKeys[i] );
5202 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5207 uirow = MSI_CreateRecord( 1 );
5208 MSI_RecordSetStringW( uirow, 1, productid );
5209 msi_ui_actiondata( package, szRegisterUser, uirow );
5210 msiobj_release( &uirow->hdr );
5212 msi_free(productid);
5218 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5222 package->script->InWhatSequence |= SEQUENCE_EXEC;
5223 rc = ACTION_ProcessExecSequence(package,FALSE);
5227 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5229 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5230 WCHAR productid_85[21], component_85[21], *ret;
5234 /* > is used if there is a component GUID and < if not. */
5236 productid_85[0] = 0;
5237 component_85[0] = 0;
5238 CLSIDFromString( package->ProductCode, &clsid );
5240 encode_base85_guid( &clsid, productid_85 );
5243 CLSIDFromString( component->ComponentId, &clsid );
5244 encode_base85_guid( &clsid, component_85 );
5247 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5248 debugstr_w(component_85));
5250 sz = 20 + strlenW( feature ) + 20 + 3;
5251 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5252 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5256 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5258 MSIPACKAGE *package = param;
5259 LPCWSTR compgroupid, component, feature, qualifier, text;
5260 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5269 feature = MSI_RecordGetString(rec, 5);
5270 feat = msi_get_loaded_feature(package, feature);
5272 return ERROR_SUCCESS;
5274 feat->Action = msi_get_feature_action( package, feat );
5275 if (feat->Action != INSTALLSTATE_LOCAL &&
5276 feat->Action != INSTALLSTATE_SOURCE &&
5277 feat->Action != INSTALLSTATE_ADVERTISED)
5279 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5280 return ERROR_SUCCESS;
5283 component = MSI_RecordGetString(rec, 3);
5284 comp = msi_get_loaded_component(package, component);
5286 return ERROR_SUCCESS;
5288 compgroupid = MSI_RecordGetString(rec,1);
5289 qualifier = MSI_RecordGetString(rec,2);
5291 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5292 if (rc != ERROR_SUCCESS)
5295 advertise = msi_create_component_advertise_string( package, comp, feature );
5296 text = MSI_RecordGetString( rec, 4 );
5299 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5300 strcpyW( p, advertise );
5302 msi_free( advertise );
5305 existing = msi_reg_get_val_str( hkey, qualifier );
5307 sz = strlenW( advertise ) + 1;
5310 for (p = existing; *p; p += len)
5312 len = strlenW( p ) + 1;
5313 if (strcmpW( advertise, p )) sz += len;
5316 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5318 rc = ERROR_OUTOFMEMORY;
5324 for (p = existing; *p; p += len)
5326 len = strlenW( p ) + 1;
5327 if (strcmpW( advertise, p ))
5329 memcpy( q, p, len * sizeof(WCHAR) );
5334 strcpyW( q, advertise );
5335 q[strlenW( q ) + 1] = 0;
5337 msi_reg_set_val_multi_str( hkey, qualifier, output );
5342 msi_free( advertise );
5343 msi_free( existing );
5346 uirow = MSI_CreateRecord( 2 );
5347 MSI_RecordSetStringW( uirow, 1, compgroupid );
5348 MSI_RecordSetStringW( uirow, 2, qualifier);
5349 msi_ui_actiondata( package, szPublishComponents, uirow );
5350 msiobj_release( &uirow->hdr );
5351 /* FIXME: call ui_progress? */
5357 * At present I am ignorning the advertised components part of this and only
5358 * focusing on the qualified component sets
5360 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5362 static const WCHAR query[] = {
5363 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5364 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5368 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5369 if (rc != ERROR_SUCCESS)
5370 return ERROR_SUCCESS;
5372 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5373 msiobj_release(&view->hdr);
5377 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5379 static const WCHAR szInstallerComponents[] = {
5380 'S','o','f','t','w','a','r','e','\\',
5381 'M','i','c','r','o','s','o','f','t','\\',
5382 'I','n','s','t','a','l','l','e','r','\\',
5383 'C','o','m','p','o','n','e','n','t','s','\\',0};
5385 MSIPACKAGE *package = param;
5386 LPCWSTR compgroupid, component, feature, qualifier;
5390 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5393 feature = MSI_RecordGetString( rec, 5 );
5394 feat = msi_get_loaded_feature( package, feature );
5396 return ERROR_SUCCESS;
5398 feat->Action = msi_get_feature_action( package, feat );
5399 if (feat->Action != INSTALLSTATE_ABSENT)
5401 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5402 return ERROR_SUCCESS;
5405 component = MSI_RecordGetString( rec, 3 );
5406 comp = msi_get_loaded_component( package, component );
5408 return ERROR_SUCCESS;
5410 compgroupid = MSI_RecordGetString( rec, 1 );
5411 qualifier = MSI_RecordGetString( rec, 2 );
5413 squash_guid( compgroupid, squashed );
5414 strcpyW( keypath, szInstallerComponents );
5415 strcatW( keypath, squashed );
5417 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5418 if (res != ERROR_SUCCESS)
5420 WARN("Unable to delete component key %d\n", res);
5423 uirow = MSI_CreateRecord( 2 );
5424 MSI_RecordSetStringW( uirow, 1, compgroupid );
5425 MSI_RecordSetStringW( uirow, 2, qualifier );
5426 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5427 msiobj_release( &uirow->hdr );
5429 return ERROR_SUCCESS;
5432 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5434 static const WCHAR query[] = {
5435 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5436 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5440 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5441 if (rc != ERROR_SUCCESS)
5442 return ERROR_SUCCESS;
5444 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5445 msiobj_release( &view->hdr );
5449 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5451 static const WCHAR query[] =
5452 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5453 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5454 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5455 MSIPACKAGE *package = param;
5456 MSICOMPONENT *component;
5459 SC_HANDLE hscm = NULL, service = NULL;
5461 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5462 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5463 DWORD serv_type, start_type, err_control;
5464 SERVICE_DESCRIPTIONW sd = {NULL};
5466 comp = MSI_RecordGetString( rec, 12 );
5467 component = msi_get_loaded_component( package, comp );
5470 WARN("service component not found\n");
5473 component->Action = msi_get_component_action( package, component );
5474 if (component->Action != INSTALLSTATE_LOCAL)
5476 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5479 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5482 ERR("Failed to open the SC Manager!\n");
5486 start_type = MSI_RecordGetInteger(rec, 5);
5487 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5490 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5491 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5492 serv_type = MSI_RecordGetInteger(rec, 4);
5493 err_control = MSI_RecordGetInteger(rec, 6);
5494 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5495 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5496 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5497 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5498 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5499 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5501 /* fetch the service path */
5502 row = MSI_QueryGetRecord(package->db, query, comp);
5505 ERR("Query failed\n");
5508 key = MSI_RecordGetString(row, 6);
5509 file = msi_get_loaded_file(package, key);
5510 msiobj_release(&row->hdr);
5513 ERR("Failed to load the service file\n");
5517 if (!args || !args[0]) image_path = file->TargetPath;
5520 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5521 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5522 return ERROR_OUTOFMEMORY;
5524 strcpyW(image_path, file->TargetPath);
5525 strcatW(image_path, szSpace);
5526 strcatW(image_path, args);
5528 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5529 start_type, err_control, image_path, load_order,
5530 NULL, depends, serv_name, pass);
5534 if (GetLastError() != ERROR_SERVICE_EXISTS)
5535 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5537 else if (sd.lpDescription)
5539 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5540 WARN("failed to set service description %u\n", GetLastError());
5543 if (image_path != file->TargetPath) msi_free(image_path);
5545 CloseServiceHandle(service);
5546 CloseServiceHandle(hscm);
5549 msi_free(sd.lpDescription);
5550 msi_free(load_order);
5551 msi_free(serv_name);
5556 return ERROR_SUCCESS;
5559 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5561 static const WCHAR query[] = {
5562 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5563 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5567 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5568 if (rc != ERROR_SUCCESS)
5569 return ERROR_SUCCESS;
5571 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5572 msiobj_release(&view->hdr);
5576 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5577 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5579 LPCWSTR *vector, *temp_vector;
5583 static const WCHAR separator[] = {'[','~',']',0};
5586 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5591 vector = msi_alloc(sizeof(LPWSTR));
5599 vector[*numargs - 1] = p;
5601 if ((q = strstrW(p, separator)))
5605 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5611 vector = temp_vector;
5620 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5622 MSIPACKAGE *package = param;
5625 SC_HANDLE scm = NULL, service = NULL;
5626 LPCWSTR component, *vector = NULL;
5627 LPWSTR name, args, display_name = NULL;
5628 DWORD event, numargs, len, wait, dummy;
5629 UINT r = ERROR_FUNCTION_FAILED;
5630 SERVICE_STATUS_PROCESS status;
5631 ULONGLONG start_time;
5633 component = MSI_RecordGetString(rec, 6);
5634 comp = msi_get_loaded_component(package, component);
5636 return ERROR_SUCCESS;
5638 comp->Action = msi_get_component_action( package, comp );
5639 if (comp->Action != INSTALLSTATE_LOCAL)
5641 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5642 return ERROR_SUCCESS;
5645 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5646 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5647 event = MSI_RecordGetInteger(rec, 3);
5648 wait = MSI_RecordGetInteger(rec, 5);
5650 if (!(event & msidbServiceControlEventStart))
5656 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5659 ERR("Failed to open the service control manager\n");
5664 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5665 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5667 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5668 GetServiceDisplayNameW( scm, name, display_name, &len );
5671 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5674 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5678 vector = msi_service_args_to_vector(args, &numargs);
5680 if (!StartServiceW(service, numargs, vector) &&
5681 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5683 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5690 /* wait for at most 30 seconds for the service to be up and running */
5691 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5692 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5694 TRACE("failed to query service status (%u)\n", GetLastError());
5697 start_time = GetTickCount64();
5698 while (status.dwCurrentState == SERVICE_START_PENDING)
5700 if (GetTickCount64() - start_time > 30000) break;
5702 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5703 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5705 TRACE("failed to query service status (%u)\n", GetLastError());
5709 if (status.dwCurrentState != SERVICE_RUNNING)
5711 WARN("service failed to start %u\n", status.dwCurrentState);
5712 r = ERROR_FUNCTION_FAILED;
5717 uirow = MSI_CreateRecord( 2 );
5718 MSI_RecordSetStringW( uirow, 1, display_name );
5719 MSI_RecordSetStringW( uirow, 2, name );
5720 msi_ui_actiondata( package, szStartServices, uirow );
5721 msiobj_release( &uirow->hdr );
5723 CloseServiceHandle(service);
5724 CloseServiceHandle(scm);
5729 msi_free(display_name);
5733 static UINT ACTION_StartServices( MSIPACKAGE *package )
5735 static const WCHAR query[] = {
5736 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5737 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5741 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5742 if (rc != ERROR_SUCCESS)
5743 return ERROR_SUCCESS;
5745 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5746 msiobj_release(&view->hdr);
5750 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5752 DWORD i, needed, count;
5753 ENUM_SERVICE_STATUSW *dependencies;
5757 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5758 0, &needed, &count))
5761 if (GetLastError() != ERROR_MORE_DATA)
5764 dependencies = msi_alloc(needed);
5768 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5769 needed, &needed, &count))
5772 for (i = 0; i < count; i++)
5774 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5775 SERVICE_STOP | SERVICE_QUERY_STATUS);
5779 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5786 msi_free(dependencies);
5790 static UINT stop_service( LPCWSTR name )
5792 SC_HANDLE scm = NULL, service = NULL;
5793 SERVICE_STATUS status;
5794 SERVICE_STATUS_PROCESS ssp;
5797 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5800 WARN("Failed to open the SCM: %d\n", GetLastError());
5804 service = OpenServiceW(scm, name,
5806 SERVICE_QUERY_STATUS |
5807 SERVICE_ENUMERATE_DEPENDENTS);
5810 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5814 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5815 sizeof(SERVICE_STATUS_PROCESS), &needed))
5817 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5821 if (ssp.dwCurrentState == SERVICE_STOPPED)
5824 stop_service_dependents(scm, service);
5826 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5827 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5830 CloseServiceHandle(service);
5831 CloseServiceHandle(scm);
5833 return ERROR_SUCCESS;
5836 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5838 MSIPACKAGE *package = param;
5842 LPWSTR name = NULL, display_name = NULL;
5846 event = MSI_RecordGetInteger( rec, 3 );
5847 if (!(event & msidbServiceControlEventStop))
5848 return ERROR_SUCCESS;
5850 component = MSI_RecordGetString( rec, 6 );
5851 comp = msi_get_loaded_component( package, component );
5853 return ERROR_SUCCESS;
5855 comp->Action = msi_get_component_action( package, comp );
5856 if (comp->Action != INSTALLSTATE_ABSENT)
5858 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5859 return ERROR_SUCCESS;
5862 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5865 ERR("Failed to open the service control manager\n");
5870 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5871 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5873 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5874 GetServiceDisplayNameW( scm, name, display_name, &len );
5876 CloseServiceHandle( scm );
5878 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5879 stop_service( name );
5882 uirow = MSI_CreateRecord( 2 );
5883 MSI_RecordSetStringW( uirow, 1, display_name );
5884 MSI_RecordSetStringW( uirow, 2, name );
5885 msi_ui_actiondata( package, szStopServices, uirow );
5886 msiobj_release( &uirow->hdr );
5889 msi_free( display_name );
5890 return ERROR_SUCCESS;
5893 static UINT ACTION_StopServices( MSIPACKAGE *package )
5895 static const WCHAR query[] = {
5896 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5897 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5901 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5902 if (rc != ERROR_SUCCESS)
5903 return ERROR_SUCCESS;
5905 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5906 msiobj_release(&view->hdr);
5910 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5912 MSIPACKAGE *package = param;
5915 LPWSTR name = NULL, display_name = NULL;
5917 SC_HANDLE scm = NULL, service = NULL;
5919 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5921 return ERROR_SUCCESS;
5923 event = MSI_RecordGetInteger( rec, 3 );
5924 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5926 comp->Action = msi_get_component_action( package, comp );
5927 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5928 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5930 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5932 return ERROR_SUCCESS;
5934 stop_service( name );
5936 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5939 WARN("Failed to open the SCM: %d\n", GetLastError());
5944 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5945 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5947 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5948 GetServiceDisplayNameW( scm, name, display_name, &len );
5951 service = OpenServiceW( scm, name, DELETE );
5954 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5958 if (!DeleteService( service ))
5959 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5962 uirow = MSI_CreateRecord( 2 );
5963 MSI_RecordSetStringW( uirow, 1, display_name );
5964 MSI_RecordSetStringW( uirow, 2, name );
5965 msi_ui_actiondata( package, szDeleteServices, uirow );
5966 msiobj_release( &uirow->hdr );
5968 CloseServiceHandle( service );
5969 CloseServiceHandle( scm );
5971 msi_free( display_name );
5973 return ERROR_SUCCESS;
5976 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5978 static const WCHAR query[] = {
5979 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5980 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5984 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5985 if (rc != ERROR_SUCCESS)
5986 return ERROR_SUCCESS;
5988 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5989 msiobj_release( &view->hdr );
5993 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5995 MSIPACKAGE *package = param;
5996 LPWSTR driver, driver_path, ptr;
5997 WCHAR outpath[MAX_PATH];
5998 MSIFILE *driver_file = NULL, *setup_file = NULL;
6001 LPCWSTR desc, file_key, component;
6003 UINT r = ERROR_SUCCESS;
6005 static const WCHAR driver_fmt[] = {
6006 'D','r','i','v','e','r','=','%','s',0};
6007 static const WCHAR setup_fmt[] = {
6008 'S','e','t','u','p','=','%','s',0};
6009 static const WCHAR usage_fmt[] = {
6010 'F','i','l','e','U','s','a','g','e','=','1',0};
6012 component = MSI_RecordGetString( rec, 2 );
6013 comp = msi_get_loaded_component( package, component );
6015 return ERROR_SUCCESS;
6017 comp->Action = msi_get_component_action( package, comp );
6018 if (comp->Action != INSTALLSTATE_LOCAL)
6020 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6021 return ERROR_SUCCESS;
6023 desc = MSI_RecordGetString(rec, 3);
6025 file_key = MSI_RecordGetString( rec, 4 );
6026 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6028 file_key = MSI_RecordGetString( rec, 5 );
6029 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6033 ERR("ODBC Driver entry not found!\n");
6034 return ERROR_FUNCTION_FAILED;
6037 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6039 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6040 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6042 driver = msi_alloc(len * sizeof(WCHAR));
6044 return ERROR_OUTOFMEMORY;
6047 lstrcpyW(ptr, desc);
6048 ptr += lstrlenW(ptr) + 1;
6050 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6055 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6059 lstrcpyW(ptr, usage_fmt);
6060 ptr += lstrlenW(ptr) + 1;
6063 driver_path = strdupW(driver_file->TargetPath);
6064 ptr = strrchrW(driver_path, '\\');
6065 if (ptr) *ptr = '\0';
6067 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6068 NULL, ODBC_INSTALL_COMPLETE, &usage))
6070 ERR("Failed to install SQL driver!\n");
6071 r = ERROR_FUNCTION_FAILED;
6074 uirow = MSI_CreateRecord( 5 );
6075 MSI_RecordSetStringW( uirow, 1, desc );
6076 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6077 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6078 msi_ui_actiondata( package, szInstallODBC, uirow );
6079 msiobj_release( &uirow->hdr );
6082 msi_free(driver_path);
6087 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6089 MSIPACKAGE *package = param;
6090 LPWSTR translator, translator_path, ptr;
6091 WCHAR outpath[MAX_PATH];
6092 MSIFILE *translator_file = NULL, *setup_file = NULL;
6095 LPCWSTR desc, file_key, component;
6097 UINT r = ERROR_SUCCESS;
6099 static const WCHAR translator_fmt[] = {
6100 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6101 static const WCHAR setup_fmt[] = {
6102 'S','e','t','u','p','=','%','s',0};
6104 component = MSI_RecordGetString( rec, 2 );
6105 comp = msi_get_loaded_component( package, component );
6107 return ERROR_SUCCESS;
6109 comp->Action = msi_get_component_action( package, comp );
6110 if (comp->Action != INSTALLSTATE_LOCAL)
6112 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6113 return ERROR_SUCCESS;
6115 desc = MSI_RecordGetString(rec, 3);
6117 file_key = MSI_RecordGetString( rec, 4 );
6118 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6120 file_key = MSI_RecordGetString( rec, 5 );
6121 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6123 if (!translator_file)
6125 ERR("ODBC Translator entry not found!\n");
6126 return ERROR_FUNCTION_FAILED;
6129 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6131 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6133 translator = msi_alloc(len * sizeof(WCHAR));
6135 return ERROR_OUTOFMEMORY;
6138 lstrcpyW(ptr, desc);
6139 ptr += lstrlenW(ptr) + 1;
6141 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6146 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6151 translator_path = strdupW(translator_file->TargetPath);
6152 ptr = strrchrW(translator_path, '\\');
6153 if (ptr) *ptr = '\0';
6155 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6156 NULL, ODBC_INSTALL_COMPLETE, &usage))
6158 ERR("Failed to install SQL translator!\n");
6159 r = ERROR_FUNCTION_FAILED;
6162 uirow = MSI_CreateRecord( 5 );
6163 MSI_RecordSetStringW( uirow, 1, desc );
6164 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6165 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6166 msi_ui_actiondata( package, szInstallODBC, uirow );
6167 msiobj_release( &uirow->hdr );
6169 msi_free(translator);
6170 msi_free(translator_path);
6175 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6177 MSIPACKAGE *package = param;
6180 LPCWSTR desc, driver, component;
6181 WORD request = ODBC_ADD_SYS_DSN;
6184 UINT r = ERROR_SUCCESS;
6187 static const WCHAR attrs_fmt[] = {
6188 'D','S','N','=','%','s',0 };
6190 component = MSI_RecordGetString( rec, 2 );
6191 comp = msi_get_loaded_component( package, component );
6193 return ERROR_SUCCESS;
6195 comp->Action = msi_get_component_action( package, comp );
6196 if (comp->Action != INSTALLSTATE_LOCAL)
6198 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6199 return ERROR_SUCCESS;
6202 desc = MSI_RecordGetString(rec, 3);
6203 driver = MSI_RecordGetString(rec, 4);
6204 registration = MSI_RecordGetInteger(rec, 5);
6206 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6207 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6209 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6210 attrs = msi_alloc(len * sizeof(WCHAR));
6212 return ERROR_OUTOFMEMORY;
6214 len = sprintfW(attrs, attrs_fmt, desc);
6217 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6219 ERR("Failed to install SQL data source!\n");
6220 r = ERROR_FUNCTION_FAILED;
6223 uirow = MSI_CreateRecord( 5 );
6224 MSI_RecordSetStringW( uirow, 1, desc );
6225 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6226 MSI_RecordSetInteger( uirow, 3, request );
6227 msi_ui_actiondata( package, szInstallODBC, uirow );
6228 msiobj_release( &uirow->hdr );
6235 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6237 static const WCHAR driver_query[] = {
6238 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6239 'O','D','B','C','D','r','i','v','e','r',0};
6240 static const WCHAR translator_query[] = {
6241 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6242 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6243 static const WCHAR source_query[] = {
6244 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6245 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6249 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6250 if (rc == ERROR_SUCCESS)
6252 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6253 msiobj_release(&view->hdr);
6254 if (rc != ERROR_SUCCESS)
6257 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6258 if (rc == ERROR_SUCCESS)
6260 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6261 msiobj_release(&view->hdr);
6262 if (rc != ERROR_SUCCESS)
6265 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6266 if (rc == ERROR_SUCCESS)
6268 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6269 msiobj_release(&view->hdr);
6270 if (rc != ERROR_SUCCESS)
6273 return ERROR_SUCCESS;
6276 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6278 MSIPACKAGE *package = param;
6282 LPCWSTR desc, component;
6284 component = MSI_RecordGetString( rec, 2 );
6285 comp = msi_get_loaded_component( package, component );
6287 return ERROR_SUCCESS;
6289 comp->Action = msi_get_component_action( package, comp );
6290 if (comp->Action != INSTALLSTATE_ABSENT)
6292 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6293 return ERROR_SUCCESS;
6296 desc = MSI_RecordGetString( rec, 3 );
6297 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6299 WARN("Failed to remove ODBC driver\n");
6303 FIXME("Usage count reached 0\n");
6306 uirow = MSI_CreateRecord( 2 );
6307 MSI_RecordSetStringW( uirow, 1, desc );
6308 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6309 msi_ui_actiondata( package, szRemoveODBC, uirow );
6310 msiobj_release( &uirow->hdr );
6312 return ERROR_SUCCESS;
6315 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6317 MSIPACKAGE *package = param;
6321 LPCWSTR desc, component;
6323 component = MSI_RecordGetString( rec, 2 );
6324 comp = msi_get_loaded_component( package, component );
6326 return ERROR_SUCCESS;
6328 comp->Action = msi_get_component_action( package, comp );
6329 if (comp->Action != INSTALLSTATE_ABSENT)
6331 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6332 return ERROR_SUCCESS;
6335 desc = MSI_RecordGetString( rec, 3 );
6336 if (!SQLRemoveTranslatorW( desc, &usage ))
6338 WARN("Failed to remove ODBC translator\n");
6342 FIXME("Usage count reached 0\n");
6345 uirow = MSI_CreateRecord( 2 );
6346 MSI_RecordSetStringW( uirow, 1, desc );
6347 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6348 msi_ui_actiondata( package, szRemoveODBC, uirow );
6349 msiobj_release( &uirow->hdr );
6351 return ERROR_SUCCESS;
6354 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6356 MSIPACKAGE *package = param;
6360 LPCWSTR desc, driver, component;
6361 WORD request = ODBC_REMOVE_SYS_DSN;
6365 static const WCHAR attrs_fmt[] = {
6366 'D','S','N','=','%','s',0 };
6368 component = MSI_RecordGetString( rec, 2 );
6369 comp = msi_get_loaded_component( package, component );
6371 return ERROR_SUCCESS;
6373 comp->Action = msi_get_component_action( package, comp );
6374 if (comp->Action != INSTALLSTATE_ABSENT)
6376 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6377 return ERROR_SUCCESS;
6380 desc = MSI_RecordGetString( rec, 3 );
6381 driver = MSI_RecordGetString( rec, 4 );
6382 registration = MSI_RecordGetInteger( rec, 5 );
6384 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6385 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6387 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6388 attrs = msi_alloc( len * sizeof(WCHAR) );
6390 return ERROR_OUTOFMEMORY;
6392 FIXME("Use ODBCSourceAttribute table\n");
6394 len = sprintfW( attrs, attrs_fmt, desc );
6397 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6399 WARN("Failed to remove ODBC data source\n");
6403 uirow = MSI_CreateRecord( 3 );
6404 MSI_RecordSetStringW( uirow, 1, desc );
6405 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6406 MSI_RecordSetInteger( uirow, 3, request );
6407 msi_ui_actiondata( package, szRemoveODBC, uirow );
6408 msiobj_release( &uirow->hdr );
6410 return ERROR_SUCCESS;
6413 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6415 static const WCHAR driver_query[] = {
6416 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6417 'O','D','B','C','D','r','i','v','e','r',0};
6418 static const WCHAR translator_query[] = {
6419 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6420 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6421 static const WCHAR source_query[] = {
6422 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6423 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6427 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6428 if (rc == ERROR_SUCCESS)
6430 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6431 msiobj_release( &view->hdr );
6432 if (rc != ERROR_SUCCESS)
6435 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6436 if (rc == ERROR_SUCCESS)
6438 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6439 msiobj_release( &view->hdr );
6440 if (rc != ERROR_SUCCESS)
6443 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6444 if (rc == ERROR_SUCCESS)
6446 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6447 msiobj_release( &view->hdr );
6448 if (rc != ERROR_SUCCESS)
6451 return ERROR_SUCCESS;
6454 #define ENV_ACT_SETALWAYS 0x1
6455 #define ENV_ACT_SETABSENT 0x2
6456 #define ENV_ACT_REMOVE 0x4
6457 #define ENV_ACT_REMOVEMATCH 0x8
6459 #define ENV_MOD_MACHINE 0x20000000
6460 #define ENV_MOD_APPEND 0x40000000
6461 #define ENV_MOD_PREFIX 0x80000000
6462 #define ENV_MOD_MASK 0xC0000000
6464 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6466 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6468 LPCWSTR cptr = *name;
6470 static const WCHAR prefix[] = {'[','~',']',0};
6471 static const int prefix_len = 3;
6477 *flags |= ENV_ACT_SETALWAYS;
6478 else if (*cptr == '+')
6479 *flags |= ENV_ACT_SETABSENT;
6480 else if (*cptr == '-')
6481 *flags |= ENV_ACT_REMOVE;
6482 else if (*cptr == '!')
6483 *flags |= ENV_ACT_REMOVEMATCH;
6484 else if (*cptr == '*')
6485 *flags |= ENV_MOD_MACHINE;
6495 ERR("Missing environment variable\n");
6496 return ERROR_FUNCTION_FAILED;
6501 LPCWSTR ptr = *value;
6502 if (!strncmpW(ptr, prefix, prefix_len))
6504 if (ptr[prefix_len] == szSemiColon[0])
6506 *flags |= ENV_MOD_APPEND;
6507 *value += lstrlenW(prefix);
6514 else if (lstrlenW(*value) >= prefix_len)
6516 ptr += lstrlenW(ptr) - prefix_len;
6517 if (!strcmpW( ptr, prefix ))
6519 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6521 *flags |= ENV_MOD_PREFIX;
6522 /* the "[~]" will be removed by deformat_string */;
6532 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6533 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6534 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6535 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6537 ERR("Invalid flags: %08x\n", *flags);
6538 return ERROR_FUNCTION_FAILED;
6542 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6544 return ERROR_SUCCESS;
6547 static UINT open_env_key( DWORD flags, HKEY *key )
6549 static const WCHAR user_env[] =
6550 {'E','n','v','i','r','o','n','m','e','n','t',0};
6551 static const WCHAR machine_env[] =
6552 {'S','y','s','t','e','m','\\',
6553 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6554 'C','o','n','t','r','o','l','\\',
6555 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6556 'E','n','v','i','r','o','n','m','e','n','t',0};
6561 if (flags & ENV_MOD_MACHINE)
6564 root = HKEY_LOCAL_MACHINE;
6569 root = HKEY_CURRENT_USER;
6572 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6573 if (res != ERROR_SUCCESS)
6575 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6576 return ERROR_FUNCTION_FAILED;
6579 return ERROR_SUCCESS;
6582 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6584 MSIPACKAGE *package = param;
6585 LPCWSTR name, value, component;
6586 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6587 DWORD flags, type, size;
6594 component = MSI_RecordGetString(rec, 4);
6595 comp = msi_get_loaded_component(package, component);
6597 return ERROR_SUCCESS;
6599 comp->Action = msi_get_component_action( package, comp );
6600 if (comp->Action != INSTALLSTATE_LOCAL)
6602 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6603 return ERROR_SUCCESS;
6605 name = MSI_RecordGetString(rec, 2);
6606 value = MSI_RecordGetString(rec, 3);
6608 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6610 res = env_parse_flags(&name, &value, &flags);
6611 if (res != ERROR_SUCCESS || !value)
6614 if (value && !deformat_string(package, value, &deformatted))
6616 res = ERROR_OUTOFMEMORY;
6620 value = deformatted;
6622 res = open_env_key( flags, &env );
6623 if (res != ERROR_SUCCESS)
6626 if (flags & ENV_MOD_MACHINE)
6627 action |= 0x20000000;
6631 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6632 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6633 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6636 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6640 /* Nothing to do. */
6643 res = ERROR_SUCCESS;
6647 /* If we are appending but the string was empty, strip ; */
6648 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6650 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6651 newval = strdupW(value);
6654 res = ERROR_OUTOFMEMORY;
6662 /* Contrary to MSDN, +-variable to [~];path works */
6663 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6665 res = ERROR_SUCCESS;
6669 data = msi_alloc(size);
6673 return ERROR_OUTOFMEMORY;
6676 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6677 if (res != ERROR_SUCCESS)
6680 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6683 res = RegDeleteValueW(env, name);
6684 if (res != ERROR_SUCCESS)
6685 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6689 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6690 if (flags & ENV_MOD_MASK)
6694 if (flags & ENV_MOD_APPEND) multiplier++;
6695 if (flags & ENV_MOD_PREFIX) multiplier++;
6696 mod_size = lstrlenW(value) * multiplier;
6697 size += mod_size * sizeof(WCHAR);
6700 newval = msi_alloc(size);
6704 res = ERROR_OUTOFMEMORY;
6708 if (flags & ENV_MOD_PREFIX)
6710 lstrcpyW(newval, value);
6711 ptr = newval + lstrlenW(value);
6712 action |= 0x80000000;
6715 lstrcpyW(ptr, data);
6717 if (flags & ENV_MOD_APPEND)
6719 lstrcatW(newval, value);
6720 action |= 0x40000000;
6723 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6724 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6727 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6731 uirow = MSI_CreateRecord( 3 );
6732 MSI_RecordSetStringW( uirow, 1, name );
6733 MSI_RecordSetStringW( uirow, 2, newval );
6734 MSI_RecordSetInteger( uirow, 3, action );
6735 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6736 msiobj_release( &uirow->hdr );
6738 if (env) RegCloseKey(env);
6739 msi_free(deformatted);
6745 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6747 static const WCHAR query[] = {
6748 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6749 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6753 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6754 if (rc != ERROR_SUCCESS)
6755 return ERROR_SUCCESS;
6757 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6758 msiobj_release(&view->hdr);
6762 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6764 MSIPACKAGE *package = param;
6765 LPCWSTR name, value, component;
6766 LPWSTR deformatted = NULL;
6775 component = MSI_RecordGetString( rec, 4 );
6776 comp = msi_get_loaded_component( package, component );
6778 return ERROR_SUCCESS;
6780 comp->Action = msi_get_component_action( package, comp );
6781 if (comp->Action != INSTALLSTATE_ABSENT)
6783 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6784 return ERROR_SUCCESS;
6786 name = MSI_RecordGetString( rec, 2 );
6787 value = MSI_RecordGetString( rec, 3 );
6789 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6791 r = env_parse_flags( &name, &value, &flags );
6792 if (r != ERROR_SUCCESS)
6795 if (!(flags & ENV_ACT_REMOVE))
6797 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6798 return ERROR_SUCCESS;
6801 if (value && !deformat_string( package, value, &deformatted ))
6802 return ERROR_OUTOFMEMORY;
6804 value = deformatted;
6806 r = open_env_key( flags, &env );
6807 if (r != ERROR_SUCCESS)
6813 if (flags & ENV_MOD_MACHINE)
6814 action |= 0x20000000;
6816 TRACE("Removing %s\n", debugstr_w(name));
6818 res = RegDeleteValueW( env, name );
6819 if (res != ERROR_SUCCESS)
6821 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6826 uirow = MSI_CreateRecord( 3 );
6827 MSI_RecordSetStringW( uirow, 1, name );
6828 MSI_RecordSetStringW( uirow, 2, value );
6829 MSI_RecordSetInteger( uirow, 3, action );
6830 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6831 msiobj_release( &uirow->hdr );
6833 if (env) RegCloseKey( env );
6834 msi_free( deformatted );
6838 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6840 static const WCHAR query[] = {
6841 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6842 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6846 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6847 if (rc != ERROR_SUCCESS)
6848 return ERROR_SUCCESS;
6850 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6851 msiobj_release( &view->hdr );
6855 UINT msi_validate_product_id( MSIPACKAGE *package )
6857 LPWSTR key, template, id;
6858 UINT r = ERROR_SUCCESS;
6860 id = msi_dup_property( package->db, szProductID );
6864 return ERROR_SUCCESS;
6866 template = msi_dup_property( package->db, szPIDTemplate );
6867 key = msi_dup_property( package->db, szPIDKEY );
6868 if (key && template)
6870 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6871 r = msi_set_property( package->db, szProductID, key );
6873 msi_free( template );
6878 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6880 return msi_validate_product_id( package );
6883 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6886 package->need_reboot = 1;
6887 return ERROR_SUCCESS;
6890 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6892 static const WCHAR szAvailableFreeReg[] =
6893 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6895 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6897 TRACE("%p %d kilobytes\n", package, space);
6899 uirow = MSI_CreateRecord( 1 );
6900 MSI_RecordSetInteger( uirow, 1, space );
6901 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6902 msiobj_release( &uirow->hdr );
6904 return ERROR_SUCCESS;
6907 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6909 TRACE("%p\n", package);
6911 msi_set_property( package->db, szRollbackDisabled, szOne );
6912 return ERROR_SUCCESS;
6915 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6917 FIXME("%p\n", package);
6918 return ERROR_SUCCESS;
6921 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6923 static const WCHAR driver_query[] = {
6924 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6925 'O','D','B','C','D','r','i','v','e','r',0};
6926 static const WCHAR translator_query[] = {
6927 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6928 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6932 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6933 if (r == ERROR_SUCCESS)
6936 r = MSI_IterateRecords( view, &count, NULL, package );
6937 msiobj_release( &view->hdr );
6938 if (r != ERROR_SUCCESS)
6940 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6942 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6943 if (r == ERROR_SUCCESS)
6946 r = MSI_IterateRecords( view, &count, NULL, package );
6947 msiobj_release( &view->hdr );
6948 if (r != ERROR_SUCCESS)
6950 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6952 return ERROR_SUCCESS;
6955 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6957 MSIPACKAGE *package = param;
6958 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6961 if ((value = msi_dup_property( package->db, property )))
6963 FIXME("remove %s\n", debugstr_w(value));
6966 return ERROR_SUCCESS;
6969 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6971 static const WCHAR query[] = {
6972 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6973 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6977 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6978 if (r == ERROR_SUCCESS)
6980 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6981 msiobj_release( &view->hdr );
6982 if (r != ERROR_SUCCESS)
6985 return ERROR_SUCCESS;
6988 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6990 MSIPACKAGE *package = param;
6991 int attributes = MSI_RecordGetInteger( rec, 5 );
6993 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6995 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6996 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6997 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6998 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7002 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7004 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7005 if (r != ERROR_SUCCESS)
7006 return ERROR_SUCCESS;
7010 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7011 if (r != ERROR_SUCCESS)
7012 return ERROR_SUCCESS;
7014 RegCloseKey( hkey );
7016 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7017 debugstr_w(upgrade_code), debugstr_w(version_min),
7018 debugstr_w(version_max), debugstr_w(language));
7020 return ERROR_SUCCESS;
7023 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7025 static const WCHAR query[] = {
7026 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7027 'U','p','g','r','a','d','e',0};
7031 if (msi_get_property_int( package->db, szInstalled, 0 ))
7033 TRACE("product is installed, skipping action\n");
7034 return ERROR_SUCCESS;
7036 if (msi_get_property_int( package->db, szPreselected, 0 ))
7038 TRACE("Preselected property is set, not migrating feature states\n");
7039 return ERROR_SUCCESS;
7041 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7042 if (r == ERROR_SUCCESS)
7044 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7045 msiobj_release( &view->hdr );
7046 if (r != ERROR_SUCCESS)
7049 return ERROR_SUCCESS;
7052 static void bind_image( const char *filename, const char *path )
7054 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7056 WARN("failed to bind image %u\n", GetLastError());
7060 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7064 MSIPACKAGE *package = param;
7065 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7066 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7067 char *filenameA, *pathA;
7068 WCHAR *pathW, **path_list;
7070 if (!(file = msi_get_loaded_file( package, key )))
7072 WARN("file %s not found\n", debugstr_w(key));
7073 return ERROR_SUCCESS;
7075 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7076 path_list = msi_split_string( paths, ';' );
7077 if (!path_list) bind_image( filenameA, NULL );
7080 for (i = 0; path_list[i] && path_list[i][0]; i++)
7082 deformat_string( package, path_list[i], &pathW );
7083 if ((pathA = strdupWtoA( pathW )))
7085 bind_image( filenameA, pathA );
7091 msi_free( path_list );
7092 msi_free( filenameA );
7093 return ERROR_SUCCESS;
7096 static UINT ACTION_BindImage( MSIPACKAGE *package )
7098 static const WCHAR query[] = {
7099 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7100 'B','i','n','d','I','m','a','g','e',0};
7104 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7105 if (r == ERROR_SUCCESS)
7107 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7108 msiobj_release( &view->hdr );
7109 if (r != ERROR_SUCCESS)
7112 return ERROR_SUCCESS;
7115 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7117 static const WCHAR query[] = {
7118 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7123 r = MSI_OpenQuery( package->db, &view, query, table );
7124 if (r == ERROR_SUCCESS)
7126 r = MSI_IterateRecords(view, &count, NULL, package);
7127 msiobj_release(&view->hdr);
7128 if (r != ERROR_SUCCESS)
7131 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7132 return ERROR_SUCCESS;
7135 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7137 static const WCHAR table[] = {
7138 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7139 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7142 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7144 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7145 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7148 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7150 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7151 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7154 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7156 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7157 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7160 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7162 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7163 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7168 const WCHAR *action;
7169 UINT (*handler)(MSIPACKAGE *);
7170 const WCHAR *action_rollback;
7174 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7175 { szAppSearch, ACTION_AppSearch, NULL },
7176 { szBindImage, ACTION_BindImage, NULL },
7177 { szCCPSearch, ACTION_CCPSearch, NULL },
7178 { szCostFinalize, ACTION_CostFinalize, NULL },
7179 { szCostInitialize, ACTION_CostInitialize, NULL },
7180 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7181 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7182 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7183 { szDisableRollback, ACTION_DisableRollback, NULL },
7184 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7185 { szExecuteAction, ACTION_ExecuteAction, NULL },
7186 { szFileCost, ACTION_FileCost, NULL },
7187 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7188 { szForceReboot, ACTION_ForceReboot, NULL },
7189 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7190 { szInstallExecute, ACTION_InstallExecute, NULL },
7191 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7192 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7193 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7194 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7195 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7196 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7197 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7198 { szInstallValidate, ACTION_InstallValidate, NULL },
7199 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7200 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7201 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7202 { szMoveFiles, ACTION_MoveFiles, NULL },
7203 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7204 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7205 { szPatchFiles, ACTION_PatchFiles, NULL },
7206 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7207 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7208 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7209 { szPublishProduct, ACTION_PublishProduct, NULL },
7210 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7211 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7212 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7213 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7214 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7215 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7216 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7217 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7218 { szRegisterUser, ACTION_RegisterUser, NULL },
7219 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7220 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7221 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7222 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7223 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7224 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7225 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7226 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7227 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7228 { szResolveSource, ACTION_ResolveSource, NULL },
7229 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7230 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7231 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7232 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7233 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7234 { szStartServices, ACTION_StartServices, szStopServices },
7235 { szStopServices, ACTION_StopServices, szStartServices },
7236 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7237 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7238 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7239 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7240 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7241 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7242 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7243 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7244 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7245 { szValidateProductID, ACTION_ValidateProductID, NULL },
7246 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7247 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7248 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7249 { NULL, NULL, NULL }
7252 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7258 while (StandardActions[i].action != NULL)
7260 if (!strcmpW( StandardActions[i].action, action ))
7262 ui_actionstart( package, action );
7263 if (StandardActions[i].handler)
7265 ui_actioninfo( package, action, TRUE, 0 );
7266 *rc = StandardActions[i].handler( package );
7267 ui_actioninfo( package, action, FALSE, *rc );
7269 if (StandardActions[i].action_rollback && !package->need_rollback)
7271 TRACE("scheduling rollback action\n");
7272 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7277 FIXME("unhandled standard action %s\n", debugstr_w(action));
7278 *rc = ERROR_SUCCESS;
7288 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7290 UINT rc = ERROR_SUCCESS;
7293 TRACE("Performing action (%s)\n", debugstr_w(action));
7295 handled = ACTION_HandleStandardAction(package, action, &rc);
7298 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7302 WARN("unhandled msi action %s\n", debugstr_w(action));
7303 rc = ERROR_FUNCTION_NOT_CALLED;
7309 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7311 UINT rc = ERROR_SUCCESS;
7312 BOOL handled = FALSE;
7314 TRACE("Performing action (%s)\n", debugstr_w(action));
7316 handled = ACTION_HandleStandardAction(package, action, &rc);
7319 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7321 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7326 WARN("unhandled msi action %s\n", debugstr_w(action));
7327 rc = ERROR_FUNCTION_NOT_CALLED;
7333 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7335 UINT rc = ERROR_SUCCESS;
7338 static const WCHAR query[] =
7339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7340 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7341 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7342 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7343 static const WCHAR ui_query[] =
7344 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7345 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7346 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7347 ' ', '=',' ','%','i',0};
7349 if (needs_ui_sequence(package))
7350 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7352 row = MSI_QueryGetRecord(package->db, query, seq);
7356 LPCWSTR action, cond;
7358 TRACE("Running the actions\n");
7360 /* check conditions */
7361 cond = MSI_RecordGetString(row, 2);
7363 /* this is a hack to skip errors in the condition code */
7364 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7366 msiobj_release(&row->hdr);
7367 return ERROR_SUCCESS;
7370 action = MSI_RecordGetString(row, 1);
7373 ERR("failed to fetch action\n");
7374 msiobj_release(&row->hdr);
7375 return ERROR_FUNCTION_FAILED;
7378 if (needs_ui_sequence(package))
7379 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7381 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7383 msiobj_release(&row->hdr);
7389 /****************************************************
7390 * TOP level entry points
7391 *****************************************************/
7393 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7394 LPCWSTR szCommandLine )
7396 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7397 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7398 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7399 WCHAR *reinstall = NULL;
7403 msi_set_property( package->db, szAction, szInstall );
7405 package->script->InWhatSequence = SEQUENCE_INSTALL;
7412 dir = strdupW(szPackagePath);
7413 p = strrchrW(dir, '\\');
7417 file = szPackagePath + (p - dir);
7422 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7423 GetCurrentDirectoryW(MAX_PATH, dir);
7424 lstrcatW(dir, szBackSlash);
7425 file = szPackagePath;
7428 msi_free( package->PackagePath );
7429 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7430 if (!package->PackagePath)
7433 return ERROR_OUTOFMEMORY;
7436 lstrcpyW(package->PackagePath, dir);
7437 lstrcatW(package->PackagePath, file);
7440 msi_set_sourcedir_props(package, FALSE);
7443 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7444 if (rc != ERROR_SUCCESS)
7447 msi_apply_transforms( package );
7448 msi_apply_patches( package );
7450 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7452 TRACE("setting reinstall property\n");
7453 msi_set_property( package->db, szReinstall, szAll );
7456 /* properties may have been added by a transform */
7457 msi_clone_properties( package );
7459 msi_parse_command_line( package, szCommandLine, FALSE );
7460 msi_adjust_privilege_properties( package );
7461 msi_set_context( package );
7463 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7465 TRACE("disabling rollback\n");
7466 msi_set_property( package->db, szRollbackDisabled, szOne );
7469 if (needs_ui_sequence( package))
7471 package->script->InWhatSequence |= SEQUENCE_UI;
7472 rc = ACTION_ProcessUISequence(package);
7473 ui_exists = ui_sequence_exists(package);
7474 if (rc == ERROR_SUCCESS || !ui_exists)
7476 package->script->InWhatSequence |= SEQUENCE_EXEC;
7477 rc = ACTION_ProcessExecSequence(package, ui_exists);
7481 rc = ACTION_ProcessExecSequence(package, FALSE);
7483 package->script->CurrentlyScripting = FALSE;
7485 /* process the ending type action */
7486 if (rc == ERROR_SUCCESS)
7487 ACTION_PerformActionSequence(package, -1);
7488 else if (rc == ERROR_INSTALL_USEREXIT)
7489 ACTION_PerformActionSequence(package, -2);
7490 else if (rc == ERROR_INSTALL_SUSPEND)
7491 ACTION_PerformActionSequence(package, -4);
7494 ACTION_PerformActionSequence(package, -3);
7495 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7497 package->need_rollback = TRUE;
7501 /* finish up running custom actions */
7502 ACTION_FinishCustomActions(package);
7504 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7506 WARN("installation failed, running rollback script\n");
7507 execute_script( package, SCRIPT_ROLLBACK );
7509 msi_free( reinstall );
7511 if (rc == ERROR_SUCCESS && package->need_reboot)
7512 return ERROR_SUCCESS_REBOOT_REQUIRED;