2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
191 sprintfW(message,template_s,timet,action);
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
221 case state_whitespace:
231 if (in_quotes && p[1] != '\"') count--;
247 if (in_quotes) count--;
251 state = state_whitespace;
252 if (!count) goto done;
257 if (!count) in_quotes = 0;
268 if (in_quotes && p[1] != '\"') count--;
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
279 if (!count) in_quotes = 0;
288 if (!ignore) *out++ = *p;
292 if (!len) *value = 0;
299 static void remove_quotes( WCHAR *str )
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
321 return ERROR_SUCCESS;
326 while (*ptr == ' ') ptr++;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
338 if (!preserve_case) struprW( prop );
341 while (*ptr2 == ' ') ptr2++;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
348 WARN("unbalanced quotes\n");
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
372 LPWSTR p, *ret = NULL;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
395 for( count = 0; (ret[count] = p); count++ )
397 p = strchrW( p, sep );
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 db = msi_dup_property( package->db, szOriginalDatabase );
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
448 p = strrchrW( db, '/' );
452 return ERROR_SUCCESS;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
543 rc = ACTION_ForceReboot( package );
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property(package->db, szSourceDir, NULL);
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
736 if (!(slash = strrchrW( new_path, '\\' )))
741 len = slash - new_path;
743 if (!msi_create_full_path( new_path ))
748 new_path[len] = '\\';
750 msi_free( new_path );
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 return comp->ActionRequest;
815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
817 if (package->need_rollback) return feature->Installed;
818 return feature->ActionRequest;
821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
823 MSIPACKAGE *package = param;
824 LPCWSTR dir, component, full_path;
829 component = MSI_RecordGetString(row, 2);
831 return ERROR_SUCCESS;
833 comp = msi_get_loaded_component(package, component);
835 return ERROR_SUCCESS;
837 comp->Action = msi_get_component_action( package, comp );
838 if (comp->Action != INSTALLSTATE_LOCAL)
840 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
841 return ERROR_SUCCESS;
844 dir = MSI_RecordGetString(row,1);
847 ERR("Unable to get folder id\n");
848 return ERROR_SUCCESS;
851 uirow = MSI_CreateRecord(1);
852 MSI_RecordSetStringW(uirow, 1, dir);
853 msi_ui_actiondata(package, szCreateFolders, uirow);
854 msiobj_release(&uirow->hdr);
856 full_path = msi_get_target_folder( package, dir );
859 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
860 return ERROR_SUCCESS;
862 TRACE("folder is %s\n", debugstr_w(full_path));
864 folder = msi_get_loaded_folder( package, dir );
865 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
866 folder->State = FOLDER_STATE_CREATED;
867 return ERROR_SUCCESS;
870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
872 static const WCHAR query[] = {
873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
874 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
879 if (rc != ERROR_SUCCESS)
880 return ERROR_SUCCESS;
882 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
883 msiobj_release(&view->hdr);
887 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
889 MSIPACKAGE *package = param;
890 LPCWSTR dir, component, full_path;
895 component = MSI_RecordGetString(row, 2);
897 return ERROR_SUCCESS;
899 comp = msi_get_loaded_component(package, component);
901 return ERROR_SUCCESS;
903 comp->Action = msi_get_component_action( package, comp );
904 if (comp->Action != INSTALLSTATE_ABSENT)
906 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
907 return ERROR_SUCCESS;
910 dir = MSI_RecordGetString( row, 1 );
913 ERR("Unable to get folder id\n");
914 return ERROR_SUCCESS;
917 full_path = msi_get_target_folder( package, dir );
920 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
921 return ERROR_SUCCESS;
923 TRACE("folder is %s\n", debugstr_w(full_path));
925 uirow = MSI_CreateRecord( 1 );
926 MSI_RecordSetStringW( uirow, 1, dir );
927 msi_ui_actiondata( package, szRemoveFolders, uirow );
928 msiobj_release( &uirow->hdr );
930 RemoveDirectoryW( full_path );
931 folder = msi_get_loaded_folder( package, dir );
932 folder->State = FOLDER_STATE_REMOVED;
933 return ERROR_SUCCESS;
936 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
938 static const WCHAR query[] = {
939 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
940 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
944 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
945 if (rc != ERROR_SUCCESS)
946 return ERROR_SUCCESS;
948 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
949 msiobj_release( &view->hdr );
953 static UINT load_component( MSIRECORD *row, LPVOID param )
955 MSIPACKAGE *package = param;
958 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
960 return ERROR_FUNCTION_FAILED;
962 list_add_tail( &package->components, &comp->entry );
964 /* fill in the data */
965 comp->Component = msi_dup_record_field( row, 1 );
967 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
969 comp->ComponentId = msi_dup_record_field( row, 2 );
970 comp->Directory = msi_dup_record_field( row, 3 );
971 comp->Attributes = MSI_RecordGetInteger(row,4);
972 comp->Condition = msi_dup_record_field( row, 5 );
973 comp->KeyPath = msi_dup_record_field( row, 6 );
975 comp->Installed = INSTALLSTATE_UNKNOWN;
976 comp->Action = INSTALLSTATE_UNKNOWN;
977 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
979 comp->assembly = msi_load_assembly( package, comp );
980 return ERROR_SUCCESS;
983 UINT msi_load_all_components( MSIPACKAGE *package )
985 static const WCHAR query[] = {
986 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
987 '`','C','o','m','p','o','n','e','n','t','`',0};
991 if (!list_empty(&package->components))
992 return ERROR_SUCCESS;
994 r = MSI_DatabaseOpenViewW( package->db, query, &view );
995 if (r != ERROR_SUCCESS)
998 if (!msi_init_assembly_caches( package ))
1000 ERR("can't initialize assembly caches\n");
1001 msiobj_release( &view->hdr );
1002 return ERROR_FUNCTION_FAILED;
1005 r = MSI_IterateRecords(view, NULL, load_component, package);
1006 msiobj_release(&view->hdr);
1007 msi_destroy_assembly_caches( package );
1012 MSIPACKAGE *package;
1013 MSIFEATURE *feature;
1016 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1020 cl = msi_alloc( sizeof (*cl) );
1022 return ERROR_NOT_ENOUGH_MEMORY;
1023 cl->component = comp;
1024 list_add_tail( &feature->Components, &cl->entry );
1026 return ERROR_SUCCESS;
1029 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1033 fl = msi_alloc( sizeof(*fl) );
1035 return ERROR_NOT_ENOUGH_MEMORY;
1036 fl->feature = child;
1037 list_add_tail( &parent->Children, &fl->entry );
1039 return ERROR_SUCCESS;
1042 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1044 _ilfs* ilfs = param;
1048 component = MSI_RecordGetString(row,1);
1050 /* check to see if the component is already loaded */
1051 comp = msi_get_loaded_component( ilfs->package, component );
1054 WARN("ignoring unknown component %s\n", debugstr_w(component));
1055 return ERROR_SUCCESS;
1057 add_feature_component( ilfs->feature, comp );
1058 comp->Enabled = TRUE;
1060 return ERROR_SUCCESS;
1063 static UINT load_feature(MSIRECORD * row, LPVOID param)
1065 static const WCHAR query[] = {
1066 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1067 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1068 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1069 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1070 MSIPACKAGE *package = param;
1071 MSIFEATURE *feature;
1076 /* fill in the data */
1078 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1080 return ERROR_NOT_ENOUGH_MEMORY;
1082 list_init( &feature->Children );
1083 list_init( &feature->Components );
1085 feature->Feature = msi_dup_record_field( row, 1 );
1087 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1089 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1090 feature->Title = msi_dup_record_field( row, 3 );
1091 feature->Description = msi_dup_record_field( row, 4 );
1093 if (!MSI_RecordIsNull(row,5))
1094 feature->Display = MSI_RecordGetInteger(row,5);
1096 feature->Level= MSI_RecordGetInteger(row,6);
1097 feature->Directory = msi_dup_record_field( row, 7 );
1098 feature->Attributes = MSI_RecordGetInteger(row,8);
1100 feature->Installed = INSTALLSTATE_UNKNOWN;
1101 feature->Action = INSTALLSTATE_UNKNOWN;
1102 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1104 list_add_tail( &package->features, &feature->entry );
1106 /* load feature components */
1108 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1109 if (rc != ERROR_SUCCESS)
1110 return ERROR_SUCCESS;
1112 ilfs.package = package;
1113 ilfs.feature = feature;
1115 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1116 msiobj_release(&view->hdr);
1120 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1122 MSIPACKAGE *package = param;
1123 MSIFEATURE *parent, *child;
1125 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1127 return ERROR_FUNCTION_FAILED;
1129 if (!child->Feature_Parent)
1130 return ERROR_SUCCESS;
1132 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1134 return ERROR_FUNCTION_FAILED;
1136 add_feature_child( parent, child );
1137 return ERROR_SUCCESS;
1140 UINT msi_load_all_features( MSIPACKAGE *package )
1142 static const WCHAR query[] = {
1143 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1144 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1145 '`','D','i','s','p','l','a','y','`',0};
1149 if (!list_empty(&package->features))
1150 return ERROR_SUCCESS;
1152 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1153 if (r != ERROR_SUCCESS)
1156 r = MSI_IterateRecords( view, NULL, load_feature, package );
1157 if (r != ERROR_SUCCESS)
1159 msiobj_release( &view->hdr );
1162 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1163 msiobj_release( &view->hdr );
1167 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1178 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1180 static const WCHAR query[] = {
1181 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1182 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1183 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1184 MSIQUERY *view = NULL;
1185 MSIRECORD *row = NULL;
1188 TRACE("%s\n", debugstr_w(file->File));
1190 r = MSI_OpenQuery(package->db, &view, query, file->File);
1191 if (r != ERROR_SUCCESS)
1194 r = MSI_ViewExecute(view, NULL);
1195 if (r != ERROR_SUCCESS)
1198 r = MSI_ViewFetch(view, &row);
1199 if (r != ERROR_SUCCESS)
1202 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1203 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1204 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1205 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1206 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1209 if (view) msiobj_release(&view->hdr);
1210 if (row) msiobj_release(&row->hdr);
1214 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1217 static const WCHAR query[] = {
1218 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1219 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1220 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1222 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1225 WARN("query failed\n");
1226 return ERROR_FUNCTION_FAILED;
1229 file->disk_id = MSI_RecordGetInteger( row, 1 );
1230 msiobj_release( &row->hdr );
1231 return ERROR_SUCCESS;
1234 static UINT load_file(MSIRECORD *row, LPVOID param)
1236 MSIPACKAGE* package = param;
1240 /* fill in the data */
1242 file = msi_alloc_zero( sizeof (MSIFILE) );
1244 return ERROR_NOT_ENOUGH_MEMORY;
1246 file->File = msi_dup_record_field( row, 1 );
1248 component = MSI_RecordGetString( row, 2 );
1249 file->Component = msi_get_loaded_component( package, component );
1251 if (!file->Component)
1253 WARN("Component not found: %s\n", debugstr_w(component));
1254 msi_free(file->File);
1256 return ERROR_SUCCESS;
1259 file->FileName = msi_dup_record_field( row, 3 );
1260 msi_reduce_to_long_filename( file->FileName );
1262 file->ShortName = msi_dup_record_field( row, 3 );
1263 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1265 file->FileSize = MSI_RecordGetInteger( row, 4 );
1266 file->Version = msi_dup_record_field( row, 5 );
1267 file->Language = msi_dup_record_field( row, 6 );
1268 file->Attributes = MSI_RecordGetInteger( row, 7 );
1269 file->Sequence = MSI_RecordGetInteger( row, 8 );
1271 file->state = msifs_invalid;
1273 /* if the compressed bits are not set in the file attributes,
1274 * then read the information from the package word count property
1276 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1278 file->IsCompressed = FALSE;
1280 else if (file->Attributes &
1281 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1283 file->IsCompressed = TRUE;
1285 else if (file->Attributes & msidbFileAttributesNoncompressed)
1287 file->IsCompressed = FALSE;
1291 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1294 load_file_hash(package, file);
1295 load_file_disk_id(package, file);
1297 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1299 list_add_tail( &package->files, &file->entry );
1301 return ERROR_SUCCESS;
1304 static UINT load_all_files(MSIPACKAGE *package)
1306 static const WCHAR query[] = {
1307 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1308 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1309 '`','S','e','q','u','e','n','c','e','`', 0};
1313 if (!list_empty(&package->files))
1314 return ERROR_SUCCESS;
1316 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1317 if (rc != ERROR_SUCCESS)
1318 return ERROR_SUCCESS;
1320 rc = MSI_IterateRecords(view, NULL, load_file, package);
1321 msiobj_release(&view->hdr);
1325 static UINT load_media( MSIRECORD *row, LPVOID param )
1327 MSIPACKAGE *package = param;
1328 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1329 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1331 /* FIXME: load external cabinets and directory sources too */
1332 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1333 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1334 return ERROR_SUCCESS;
1337 static UINT load_all_media( MSIPACKAGE *package )
1339 static const WCHAR query[] = {
1340 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1341 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1342 '`','D','i','s','k','I','d','`',0};
1346 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1347 if (r != ERROR_SUCCESS)
1348 return ERROR_SUCCESS;
1350 r = MSI_IterateRecords( view, NULL, load_media, package );
1351 msiobj_release( &view->hdr );
1355 static UINT load_patch(MSIRECORD *row, LPVOID param)
1357 MSIPACKAGE *package = param;
1358 MSIFILEPATCH *patch;
1361 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1363 return ERROR_NOT_ENOUGH_MEMORY;
1365 file_key = msi_dup_record_field( row, 1 );
1366 patch->File = msi_get_loaded_file( package, file_key );
1371 ERR("Failed to find target for patch in File table\n");
1373 return ERROR_FUNCTION_FAILED;
1376 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1378 /* FIXME: The database should be properly transformed */
1379 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1381 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1382 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1383 patch->IsApplied = FALSE;
1386 * Header field - for patch validation.
1387 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1390 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1392 list_add_tail( &package->filepatches, &patch->entry );
1394 return ERROR_SUCCESS;
1397 static UINT load_all_patches(MSIPACKAGE *package)
1399 static const WCHAR query[] = {
1400 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1401 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1402 '`','S','e','q','u','e','n','c','e','`',0};
1406 if (!list_empty(&package->filepatches))
1407 return ERROR_SUCCESS;
1409 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1410 if (rc != ERROR_SUCCESS)
1411 return ERROR_SUCCESS;
1413 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1414 msiobj_release(&view->hdr);
1418 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1420 static const WCHAR query[] = {
1421 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1422 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1423 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1426 folder->persistent = FALSE;
1427 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1429 if (!MSI_ViewExecute( view, NULL ))
1432 if (!MSI_ViewFetch( view, &rec ))
1434 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1435 folder->persistent = TRUE;
1436 msiobj_release( &rec->hdr );
1439 msiobj_release( &view->hdr );
1441 return ERROR_SUCCESS;
1444 static UINT load_folder( MSIRECORD *row, LPVOID param )
1446 MSIPACKAGE *package = param;
1447 static WCHAR szEmpty[] = { 0 };
1448 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1451 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1452 list_init( &folder->children );
1453 folder->Directory = msi_dup_record_field( row, 1 );
1454 folder->Parent = msi_dup_record_field( row, 2 );
1455 p = msi_dup_record_field(row, 3);
1457 TRACE("%s\n", debugstr_w(folder->Directory));
1459 /* split src and target dir */
1461 src_short = folder_split_path( p, ':' );
1463 /* split the long and short paths */
1464 tgt_long = folder_split_path( tgt_short, '|' );
1465 src_long = folder_split_path( src_short, '|' );
1467 /* check for no-op dirs */
1468 if (tgt_short && !strcmpW( szDot, tgt_short ))
1469 tgt_short = szEmpty;
1470 if (src_short && !strcmpW( szDot, src_short ))
1471 src_short = szEmpty;
1474 tgt_long = tgt_short;
1477 src_short = tgt_short;
1478 src_long = tgt_long;
1482 src_long = src_short;
1484 /* FIXME: use the target short path too */
1485 folder->TargetDefault = strdupW(tgt_long);
1486 folder->SourceShortPath = strdupW(src_short);
1487 folder->SourceLongPath = strdupW(src_long);
1490 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1491 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1492 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1494 load_folder_persistence( package, folder );
1496 list_add_tail( &package->folders, &folder->entry );
1497 return ERROR_SUCCESS;
1500 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1504 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1506 list_add_tail( &parent->children, &fl->entry );
1507 return ERROR_SUCCESS;
1510 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1512 MSIPACKAGE *package = param;
1513 MSIFOLDER *parent, *child;
1515 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1516 return ERROR_FUNCTION_FAILED;
1518 if (!child->Parent) return ERROR_SUCCESS;
1520 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1521 return ERROR_FUNCTION_FAILED;
1523 return add_folder_child( parent, child );
1526 static UINT load_all_folders( MSIPACKAGE *package )
1528 static const WCHAR query[] = {
1529 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1530 '`','D','i','r','e','c','t','o','r','y','`',0};
1534 if (!list_empty(&package->folders))
1535 return ERROR_SUCCESS;
1537 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1538 if (r != ERROR_SUCCESS)
1541 r = MSI_IterateRecords( view, NULL, load_folder, package );
1542 if (r != ERROR_SUCCESS)
1544 msiobj_release( &view->hdr );
1547 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1548 msiobj_release( &view->hdr );
1552 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1554 msi_set_property( package->db, szCostingComplete, szZero );
1555 msi_set_property( package->db, szRootDrive, szCRoot );
1557 load_all_folders( package );
1558 msi_load_all_components( package );
1559 msi_load_all_features( package );
1560 load_all_files( package );
1561 load_all_patches( package );
1562 load_all_media( package );
1564 return ERROR_SUCCESS;
1567 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1569 const WCHAR *action = package->script->Actions[script][index];
1570 ui_actionstart( package, action );
1571 TRACE("executing %s\n", debugstr_w(action));
1572 return ACTION_PerformAction( package, action, script );
1575 static UINT execute_script( MSIPACKAGE *package, UINT script )
1577 UINT i, rc = ERROR_SUCCESS;
1579 TRACE("executing script %u\n", script);
1581 if (!package->script)
1583 ERR("no script!\n");
1584 return ERROR_FUNCTION_FAILED;
1586 if (script == SCRIPT_ROLLBACK)
1588 for (i = package->script->ActionCount[script]; i > 0; i--)
1590 rc = execute_script_action( package, script, i - 1 );
1591 if (rc != ERROR_SUCCESS) break;
1596 for (i = 0; i < package->script->ActionCount[script]; i++)
1598 rc = execute_script_action( package, script, i );
1599 if (rc != ERROR_SUCCESS) break;
1602 msi_free_action_script(package, script);
1606 static UINT ACTION_FileCost(MSIPACKAGE *package)
1608 return ERROR_SUCCESS;
1611 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1616 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1618 if (!comp->ComponentId) continue;
1620 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1621 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1623 if (r != ERROR_SUCCESS)
1624 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1625 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1627 if (r != ERROR_SUCCESS)
1628 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1629 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1631 if (r != ERROR_SUCCESS)
1632 comp->Installed = INSTALLSTATE_ABSENT;
1636 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1638 MSIFEATURE *feature;
1640 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1642 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1644 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1645 feature->Installed = INSTALLSTATE_ABSENT;
1647 feature->Installed = state;
1651 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1653 return (feature->Level > 0 && feature->Level <= level);
1656 static BOOL process_state_property(MSIPACKAGE* package, int level,
1657 LPCWSTR property, INSTALLSTATE state)
1660 MSIFEATURE *feature;
1662 override = msi_dup_property( package->db, property );
1666 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1668 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1671 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1673 if (!strcmpiW( override, szAll ))
1675 if (feature->Installed != state)
1677 feature->Action = state;
1678 feature->ActionRequest = state;
1683 LPWSTR ptr = override;
1684 LPWSTR ptr2 = strchrW(override,',');
1688 int len = ptr2 - ptr;
1690 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1691 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1693 if (feature->Installed != state)
1695 feature->Action = state;
1696 feature->ActionRequest = state;
1703 ptr2 = strchrW(ptr,',');
1714 static BOOL process_overrides( MSIPACKAGE *package, int level )
1716 static const WCHAR szAddLocal[] =
1717 {'A','D','D','L','O','C','A','L',0};
1718 static const WCHAR szAddSource[] =
1719 {'A','D','D','S','O','U','R','C','E',0};
1720 static const WCHAR szAdvertise[] =
1721 {'A','D','V','E','R','T','I','S','E',0};
1724 /* all these activation/deactivation things happen in order and things
1725 * later on the list override things earlier on the list.
1727 * 0 INSTALLLEVEL processing
1740 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1741 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1742 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1743 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1744 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1747 msi_set_property( package->db, szPreselected, szOne );
1752 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1755 MSICOMPONENT* component;
1756 MSIFEATURE *feature;
1758 TRACE("Checking Install Level\n");
1760 level = msi_get_property_int(package->db, szInstallLevel, 1);
1762 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1764 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1766 if (!is_feature_selected( feature, level )) continue;
1768 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1770 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1772 feature->Action = INSTALLSTATE_SOURCE;
1773 feature->ActionRequest = INSTALLSTATE_SOURCE;
1775 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1777 feature->Action = INSTALLSTATE_ADVERTISED;
1778 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1782 feature->Action = INSTALLSTATE_LOCAL;
1783 feature->ActionRequest = INSTALLSTATE_LOCAL;
1787 /* disable child features of unselected parent or follow parent */
1788 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1792 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1794 if (!is_feature_selected( feature, level ))
1796 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1797 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1799 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1801 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1802 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1803 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1804 fl->feature->Action = feature->Action;
1805 fl->feature->ActionRequest = feature->ActionRequest;
1810 else /* preselected */
1812 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1814 if (!is_feature_selected( feature, level )) continue;
1816 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1818 if (feature->Installed == INSTALLSTATE_ABSENT)
1820 feature->Action = INSTALLSTATE_UNKNOWN;
1821 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1825 feature->Action = feature->Installed;
1826 feature->ActionRequest = feature->Installed;
1830 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1834 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1836 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1837 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1839 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1840 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1841 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1842 fl->feature->Action = feature->Action;
1843 fl->feature->ActionRequest = feature->ActionRequest;
1849 /* now we want to set component state based based on feature state */
1850 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1854 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1855 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1856 feature->ActionRequest, feature->Action);
1858 if (!is_feature_selected( feature, level )) continue;
1860 /* features with components that have compressed files are made local */
1861 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1863 if (cl->component->ForceLocalState &&
1864 feature->ActionRequest == INSTALLSTATE_SOURCE)
1866 feature->Action = INSTALLSTATE_LOCAL;
1867 feature->ActionRequest = INSTALLSTATE_LOCAL;
1872 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1874 component = cl->component;
1876 switch (feature->ActionRequest)
1878 case INSTALLSTATE_ABSENT:
1879 component->anyAbsent = 1;
1881 case INSTALLSTATE_ADVERTISED:
1882 component->hasAdvertiseFeature = 1;
1884 case INSTALLSTATE_SOURCE:
1885 component->hasSourceFeature = 1;
1887 case INSTALLSTATE_LOCAL:
1888 component->hasLocalFeature = 1;
1890 case INSTALLSTATE_DEFAULT:
1891 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1892 component->hasAdvertiseFeature = 1;
1893 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1894 component->hasSourceFeature = 1;
1896 component->hasLocalFeature = 1;
1904 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1906 /* check if it's local or source */
1907 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1908 (component->hasLocalFeature || component->hasSourceFeature))
1910 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1911 !component->ForceLocalState)
1913 component->Action = INSTALLSTATE_SOURCE;
1914 component->ActionRequest = INSTALLSTATE_SOURCE;
1918 component->Action = INSTALLSTATE_LOCAL;
1919 component->ActionRequest = INSTALLSTATE_LOCAL;
1924 /* if any feature is local, the component must be local too */
1925 if (component->hasLocalFeature)
1927 component->Action = INSTALLSTATE_LOCAL;
1928 component->ActionRequest = INSTALLSTATE_LOCAL;
1931 if (component->hasSourceFeature)
1933 component->Action = INSTALLSTATE_SOURCE;
1934 component->ActionRequest = INSTALLSTATE_SOURCE;
1937 if (component->hasAdvertiseFeature)
1939 component->Action = INSTALLSTATE_ADVERTISED;
1940 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1943 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1944 if (component->anyAbsent &&
1945 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1947 component->Action = INSTALLSTATE_ABSENT;
1948 component->ActionRequest = INSTALLSTATE_ABSENT;
1952 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1954 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1956 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1957 component->Action = INSTALLSTATE_LOCAL;
1958 component->ActionRequest = INSTALLSTATE_LOCAL;
1961 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1962 component->Installed == INSTALLSTATE_SOURCE &&
1963 component->hasSourceFeature)
1965 component->Action = INSTALLSTATE_UNKNOWN;
1966 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1969 TRACE("component %s (installed %d request %d action %d)\n",
1970 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1973 return ERROR_SUCCESS;
1976 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1978 MSIPACKAGE *package = param;
1980 MSIFEATURE *feature;
1982 name = MSI_RecordGetString( row, 1 );
1984 feature = msi_get_loaded_feature( package, name );
1986 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1990 Condition = MSI_RecordGetString(row,3);
1992 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1994 int level = MSI_RecordGetInteger(row,2);
1995 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1996 feature->Level = level;
1999 return ERROR_SUCCESS;
2002 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2004 static const WCHAR name[] = {'\\',0};
2005 VS_FIXEDFILEINFO *ptr, *ret;
2007 DWORD versize, handle;
2010 versize = GetFileVersionInfoSizeW( filename, &handle );
2014 version = msi_alloc( versize );
2018 GetFileVersionInfoW( filename, 0, versize, version );
2020 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2022 msi_free( version );
2026 ret = msi_alloc( sz );
2027 memcpy( ret, ptr, sz );
2029 msi_free( version );
2033 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2037 msi_parse_version_string( version, &ms, &ls );
2039 if (fi->dwFileVersionMS > ms) return 1;
2040 else if (fi->dwFileVersionMS < ms) return -1;
2041 else if (fi->dwFileVersionLS > ls) return 1;
2042 else if (fi->dwFileVersionLS < ls) return -1;
2046 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2050 msi_parse_version_string( ver1, &ms1, NULL );
2051 msi_parse_version_string( ver2, &ms2, NULL );
2053 if (ms1 > ms2) return 1;
2054 else if (ms1 < ms2) return -1;
2058 DWORD msi_get_disk_file_size( LPCWSTR filename )
2063 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2064 if (file == INVALID_HANDLE_VALUE)
2065 return INVALID_FILE_SIZE;
2067 size = GetFileSize( file, NULL );
2068 TRACE("size is %u\n", size);
2069 CloseHandle( file );
2073 BOOL msi_file_hash_matches( MSIFILE *file )
2076 MSIFILEHASHINFO hash;
2078 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2079 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2080 if (r != ERROR_SUCCESS)
2083 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2086 static WCHAR *get_temp_dir( void )
2089 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2091 GetTempPathW( MAX_PATH, tmp );
2094 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2095 if (CreateDirectoryW( dir, NULL )) break;
2097 return strdupW( dir );
2101 * msi_build_directory_name()
2103 * This function is to save messing round with directory names
2104 * It handles adding backslashes between path segments,
2105 * and can add \ at the end of the directory name if told to.
2107 * It takes a variable number of arguments.
2108 * It always allocates a new string for the result, so make sure
2109 * to free the return value when finished with it.
2111 * The first arg is the number of path segments that follow.
2112 * The arguments following count are a list of path segments.
2113 * A path segment may be NULL.
2115 * Path segments will be added with a \ separating them.
2116 * A \ will not be added after the last segment, however if the
2117 * last segment is NULL, then the last character will be a \
2119 WCHAR *msi_build_directory_name( DWORD count, ... )
2125 va_start( va, count );
2126 for (i = 0; i < count; i++)
2128 const WCHAR *str = va_arg( va, const WCHAR * );
2129 if (str) sz += strlenW( str ) + 1;
2133 dir = msi_alloc( sz * sizeof(WCHAR) );
2136 va_start( va, count );
2137 for (i = 0; i < count; i++)
2139 const WCHAR *str = va_arg( va, const WCHAR * );
2141 strcatW( dir, str );
2142 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2148 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2150 MSIASSEMBLY *assembly = file->Component->assembly;
2152 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2154 msi_free( file->TargetPath );
2155 if (assembly && !assembly->application)
2157 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2158 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2159 msi_track_tempfile( package, file->TargetPath );
2163 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2164 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2167 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2170 static UINT calculate_file_cost( MSIPACKAGE *package )
2172 VS_FIXEDFILEINFO *file_version;
2173 WCHAR *font_version;
2176 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2178 MSICOMPONENT *comp = file->Component;
2181 if (!comp->Enabled) continue;
2183 if (file->IsCompressed)
2184 comp->ForceLocalState = TRUE;
2186 set_target_path( package, file );
2188 if ((comp->assembly && !comp->assembly->installed) ||
2189 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2191 comp->Cost += file->FileSize;
2194 file_size = msi_get_disk_file_size( file->TargetPath );
2198 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2200 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2202 comp->Cost += file->FileSize - file_size;
2204 msi_free( file_version );
2207 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2209 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2211 comp->Cost += file->FileSize - file_size;
2213 msi_free( font_version );
2217 if (file_size != file->FileSize)
2219 comp->Cost += file->FileSize - file_size;
2222 return ERROR_SUCCESS;
2225 WCHAR *msi_normalize_path( const WCHAR *in )
2227 const WCHAR *p = in;
2229 int n, len = strlenW( in ) + 2;
2231 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2236 /* copy until the end of the string or a space */
2237 while (*p != ' ' && (*q = *p))
2240 /* reduce many backslashes to one */
2241 if (*p != '\\' || *q != '\\')
2245 /* quit at the end of the string */
2249 /* count the number of spaces */
2254 /* if it's leading or trailing space, skip it */
2255 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2257 else /* copy n spaces */
2258 while (n && (*q++ = *p++)) n--;
2260 while (q - ret > 0 && q[-1] == ' ') q--;
2261 if (q - ret > 0 && q[-1] != '\\')
2269 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2272 MSIFOLDER *folder, *parent, *child;
2273 WCHAR *path, *normalized_path;
2275 TRACE("resolving %s\n", debugstr_w(name));
2277 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2279 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2281 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2283 path = msi_dup_property( package->db, szRootDrive );
2286 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2288 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2290 parent = msi_get_loaded_folder( package, folder->Parent );
2291 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2294 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2296 normalized_path = msi_normalize_path( path );
2298 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2300 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2301 msi_free( normalized_path );
2304 msi_set_property( package->db, folder->Directory, normalized_path );
2305 msi_free( folder->ResolvedTarget );
2306 folder->ResolvedTarget = normalized_path;
2308 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2311 msi_resolve_target_folder( package, child->Directory, load_prop );
2313 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2316 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2318 static const WCHAR query[] = {
2319 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2320 '`','C','o','n','d','i','t','i','o','n','`',0};
2321 static const WCHAR szOutOfDiskSpace[] = {
2322 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2328 TRACE("Building directory properties\n");
2329 msi_resolve_target_folder( package, szTargetDir, TRUE );
2331 TRACE("Evaluating component conditions\n");
2332 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2334 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2336 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2337 comp->Enabled = FALSE;
2340 comp->Enabled = TRUE;
2343 /* read components states from the registry */
2344 ACTION_GetComponentInstallStates(package);
2345 ACTION_GetFeatureInstallStates(package);
2347 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2349 TRACE("Evaluating feature conditions\n");
2351 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2352 if (rc == ERROR_SUCCESS)
2354 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2355 msiobj_release( &view->hdr );
2356 if (rc != ERROR_SUCCESS)
2361 TRACE("Calculating file cost\n");
2362 calculate_file_cost( package );
2364 msi_set_property( package->db, szCostingComplete, szOne );
2365 /* set default run level if not set */
2366 level = msi_dup_property( package->db, szInstallLevel );
2368 msi_set_property( package->db, szInstallLevel, szOne );
2371 /* FIXME: check volume disk space */
2372 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2374 return MSI_SetFeatureStates(package);
2377 /* OK this value is "interpreted" and then formatted based on the
2378 first few characters */
2379 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2384 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2390 LPWSTR deformated = NULL;
2393 deformat_string(package, &value[2], &deformated);
2395 /* binary value type */
2399 *size = (strlenW(ptr)/2)+1;
2401 *size = strlenW(ptr)/2;
2403 data = msi_alloc(*size);
2409 /* if uneven pad with a zero in front */
2415 data[count] = (BYTE)strtol(byte,NULL,0);
2417 TRACE("Uneven byte count\n");
2425 data[count] = (BYTE)strtol(byte,NULL,0);
2428 msi_free(deformated);
2430 TRACE("Data %i bytes(%i)\n",*size,count);
2437 deformat_string(package, &value[1], &deformated);
2440 *size = sizeof(DWORD);
2441 data = msi_alloc(*size);
2447 if ( (*p < '0') || (*p > '9') )
2453 if (deformated[0] == '-')
2456 TRACE("DWORD %i\n",*(LPDWORD)data);
2458 msi_free(deformated);
2463 static const WCHAR szMulti[] = {'[','~',']',0};
2472 *type=REG_EXPAND_SZ;
2480 if (strstrW(value, szMulti))
2481 *type = REG_MULTI_SZ;
2483 /* remove initial delimiter */
2484 if (!strncmpW(value, szMulti, 3))
2487 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2489 /* add double NULL terminator */
2490 if (*type == REG_MULTI_SZ)
2492 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2493 data = msi_realloc_zero(data, *size);
2499 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2506 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2508 *root_key = HKEY_LOCAL_MACHINE;
2513 *root_key = HKEY_CURRENT_USER;
2518 *root_key = HKEY_CLASSES_ROOT;
2522 *root_key = HKEY_CURRENT_USER;
2526 *root_key = HKEY_LOCAL_MACHINE;
2530 *root_key = HKEY_USERS;
2534 ERR("Unknown root %i\n", root);
2541 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2543 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2544 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2546 if (is_64bit && package->platform == PLATFORM_INTEL &&
2547 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2552 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2553 if (!(path_32node = msi_alloc( size ))) return NULL;
2555 memcpy( path_32node, path, len * sizeof(WCHAR) );
2556 strcpyW( path_32node + len, szWow6432Node );
2557 strcatW( path_32node, szBackSlash );
2558 strcatW( path_32node, path + len );
2562 return strdupW( path );
2565 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2567 MSIPACKAGE *package = param;
2568 LPSTR value_data = NULL;
2569 HKEY root_key, hkey;
2571 LPWSTR deformated, uikey, keypath;
2572 LPCWSTR szRoot, component, name, key, value;
2576 BOOL check_first = FALSE;
2579 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2581 component = MSI_RecordGetString(row, 6);
2582 comp = msi_get_loaded_component(package,component);
2584 return ERROR_SUCCESS;
2586 comp->Action = msi_get_component_action( package, comp );
2587 if (comp->Action != INSTALLSTATE_LOCAL)
2589 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2590 return ERROR_SUCCESS;
2593 name = MSI_RecordGetString(row, 4);
2594 if( MSI_RecordIsNull(row,5) && name )
2596 /* null values can have special meanings */
2597 if (name[0]=='-' && name[1] == 0)
2598 return ERROR_SUCCESS;
2599 else if ((name[0]=='+' && name[1] == 0) ||
2600 (name[0] == '*' && name[1] == 0))
2605 root = MSI_RecordGetInteger(row,2);
2606 key = MSI_RecordGetString(row, 3);
2608 szRoot = get_root_key( package, root, &root_key );
2610 return ERROR_SUCCESS;
2612 deformat_string(package, key , &deformated);
2613 size = strlenW(deformated) + strlenW(szRoot) + 1;
2614 uikey = msi_alloc(size*sizeof(WCHAR));
2615 strcpyW(uikey,szRoot);
2616 strcatW(uikey,deformated);
2618 keypath = get_keypath( package, root_key, deformated );
2619 msi_free( deformated );
2620 if (RegCreateKeyW( root_key, keypath, &hkey ))
2622 ERR("Could not create key %s\n", debugstr_w(keypath));
2625 return ERROR_SUCCESS;
2628 value = MSI_RecordGetString(row,5);
2630 value_data = parse_value(package, value, &type, &size);
2633 value_data = (LPSTR)strdupW(szEmpty);
2634 size = sizeof(szEmpty);
2638 deformat_string(package, name, &deformated);
2642 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2644 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2649 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2650 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2652 TRACE("value %s of %s checked already exists\n",
2653 debugstr_w(deformated), debugstr_w(uikey));
2657 TRACE("Checked and setting value %s of %s\n",
2658 debugstr_w(deformated), debugstr_w(uikey));
2659 if (deformated || size)
2660 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2665 uirow = MSI_CreateRecord(3);
2666 MSI_RecordSetStringW(uirow,2,deformated);
2667 MSI_RecordSetStringW(uirow,1,uikey);
2668 if (type == REG_SZ || type == REG_EXPAND_SZ)
2669 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2670 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2671 msiobj_release( &uirow->hdr );
2673 msi_free(value_data);
2674 msi_free(deformated);
2678 return ERROR_SUCCESS;
2681 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2683 static const WCHAR query[] = {
2684 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2685 '`','R','e','g','i','s','t','r','y','`',0};
2689 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2690 if (rc != ERROR_SUCCESS)
2691 return ERROR_SUCCESS;
2693 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2694 msiobj_release(&view->hdr);
2698 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2702 DWORD num_subkeys, num_values;
2704 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2706 if ((res = RegDeleteValueW( hkey, value )))
2708 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2710 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2711 NULL, NULL, NULL, NULL );
2712 RegCloseKey( hkey );
2713 if (!res && !num_subkeys && !num_values)
2715 TRACE("removing empty key %s\n", debugstr_w(keypath));
2716 RegDeleteKeyW( root, keypath );
2720 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2723 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2725 LONG res = RegDeleteTreeW( root, keypath );
2726 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2729 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2731 MSIPACKAGE *package = param;
2732 LPCWSTR component, name, key_str, root_key_str;
2733 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2736 BOOL delete_key = FALSE;
2741 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2743 component = MSI_RecordGetString( row, 6 );
2744 comp = msi_get_loaded_component( package, component );
2746 return ERROR_SUCCESS;
2748 comp->Action = msi_get_component_action( package, comp );
2749 if (comp->Action != INSTALLSTATE_ABSENT)
2751 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2752 return ERROR_SUCCESS;
2755 name = MSI_RecordGetString( row, 4 );
2756 if (MSI_RecordIsNull( row, 5 ) && name )
2758 if (name[0] == '+' && !name[1])
2759 return ERROR_SUCCESS;
2760 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2767 root = MSI_RecordGetInteger( row, 2 );
2768 key_str = MSI_RecordGetString( row, 3 );
2770 root_key_str = get_root_key( package, root, &hkey_root );
2772 return ERROR_SUCCESS;
2774 deformat_string( package, key_str, &deformated_key );
2775 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2776 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2777 strcpyW( ui_key_str, root_key_str );
2778 strcatW( ui_key_str, deformated_key );
2780 deformat_string( package, name, &deformated_name );
2782 keypath = get_keypath( package, hkey_root, deformated_key );
2783 msi_free( deformated_key );
2784 if (delete_key) delete_reg_key( hkey_root, keypath );
2785 else delete_reg_value( hkey_root, keypath, deformated_name );
2786 msi_free( keypath );
2788 uirow = MSI_CreateRecord( 2 );
2789 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2790 MSI_RecordSetStringW( uirow, 2, deformated_name );
2791 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2792 msiobj_release( &uirow->hdr );
2794 msi_free( ui_key_str );
2795 msi_free( deformated_name );
2796 return ERROR_SUCCESS;
2799 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2801 MSIPACKAGE *package = param;
2802 LPCWSTR component, name, key_str, root_key_str;
2803 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2806 BOOL delete_key = FALSE;
2811 component = MSI_RecordGetString( row, 5 );
2812 comp = msi_get_loaded_component( package, component );
2814 return ERROR_SUCCESS;
2816 comp->Action = msi_get_component_action( package, comp );
2817 if (comp->Action != INSTALLSTATE_LOCAL)
2819 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2820 return ERROR_SUCCESS;
2823 if ((name = MSI_RecordGetString( row, 4 )))
2825 if (name[0] == '-' && !name[1])
2832 root = MSI_RecordGetInteger( row, 2 );
2833 key_str = MSI_RecordGetString( row, 3 );
2835 root_key_str = get_root_key( package, root, &hkey_root );
2837 return ERROR_SUCCESS;
2839 deformat_string( package, key_str, &deformated_key );
2840 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2841 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2842 strcpyW( ui_key_str, root_key_str );
2843 strcatW( ui_key_str, deformated_key );
2845 deformat_string( package, name, &deformated_name );
2847 keypath = get_keypath( package, hkey_root, deformated_key );
2848 msi_free( deformated_key );
2849 if (delete_key) delete_reg_key( hkey_root, keypath );
2850 else delete_reg_value( hkey_root, keypath, deformated_name );
2851 msi_free( keypath );
2853 uirow = MSI_CreateRecord( 2 );
2854 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2855 MSI_RecordSetStringW( uirow, 2, deformated_name );
2856 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2857 msiobj_release( &uirow->hdr );
2859 msi_free( ui_key_str );
2860 msi_free( deformated_name );
2861 return ERROR_SUCCESS;
2864 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2866 static const WCHAR registry_query[] = {
2867 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2868 '`','R','e','g','i','s','t','r','y','`',0};
2869 static const WCHAR remove_registry_query[] = {
2870 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2871 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2875 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2876 if (rc == ERROR_SUCCESS)
2878 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2879 msiobj_release( &view->hdr );
2880 if (rc != ERROR_SUCCESS)
2883 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2884 if (rc == ERROR_SUCCESS)
2886 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2887 msiobj_release( &view->hdr );
2888 if (rc != ERROR_SUCCESS)
2891 return ERROR_SUCCESS;
2894 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2896 package->script->CurrentlyScripting = TRUE;
2898 return ERROR_SUCCESS;
2902 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2904 static const WCHAR query[]= {
2905 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2906 '`','R','e','g','i','s','t','r','y','`',0};
2908 DWORD total = 0, count = 0;
2910 MSIFEATURE *feature;
2914 TRACE("InstallValidate\n");
2916 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2917 if (rc == ERROR_SUCCESS)
2919 rc = MSI_IterateRecords( view, &count, NULL, package );
2920 msiobj_release( &view->hdr );
2921 if (rc != ERROR_SUCCESS)
2923 total += count * REG_PROGRESS_VALUE;
2925 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2926 total += COMPONENT_PROGRESS_VALUE;
2928 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2929 total += file->FileSize;
2931 msi_ui_progress( package, 0, total, 0, 0 );
2933 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2935 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2936 debugstr_w(feature->Feature), feature->Installed,
2937 feature->ActionRequest, feature->Action);
2939 return ERROR_SUCCESS;
2942 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2944 MSIPACKAGE* package = param;
2945 LPCWSTR cond = NULL;
2946 LPCWSTR message = NULL;
2949 static const WCHAR title[]=
2950 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2952 cond = MSI_RecordGetString(row,1);
2954 r = MSI_EvaluateConditionW(package,cond);
2955 if (r == MSICONDITION_FALSE)
2957 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2960 message = MSI_RecordGetString(row,2);
2961 deformat_string(package,message,&deformated);
2962 MessageBoxW(NULL,deformated,title,MB_OK);
2963 msi_free(deformated);
2966 return ERROR_INSTALL_FAILURE;
2969 return ERROR_SUCCESS;
2972 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2974 static const WCHAR query[] = {
2975 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2976 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2980 TRACE("Checking launch conditions\n");
2982 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2983 if (rc != ERROR_SUCCESS)
2984 return ERROR_SUCCESS;
2986 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2987 msiobj_release(&view->hdr);
2991 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2995 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2997 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2999 static const WCHAR query[] = {
3000 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3001 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3002 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3003 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3004 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3007 LPWSTR deformated, buffer, deformated_name;
3010 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3014 root = MSI_RecordGetInteger(row,2);
3015 key = MSI_RecordGetString(row, 3);
3016 name = MSI_RecordGetString(row, 4);
3017 deformat_string(package, key , &deformated);
3018 deformat_string(package, name, &deformated_name);
3020 len = strlenW(deformated) + 6;
3021 if (deformated_name)
3022 len+=strlenW(deformated_name);
3024 buffer = msi_alloc( len *sizeof(WCHAR));
3026 if (deformated_name)
3027 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3029 sprintfW(buffer,fmt,root,deformated);
3031 msi_free(deformated);
3032 msi_free(deformated_name);
3033 msiobj_release(&row->hdr);
3037 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3039 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3044 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3047 return strdupW( file->TargetPath );
3052 static HKEY openSharedDLLsKey(void)
3055 static const WCHAR path[] =
3056 {'S','o','f','t','w','a','r','e','\\',
3057 'M','i','c','r','o','s','o','f','t','\\',
3058 'W','i','n','d','o','w','s','\\',
3059 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3060 'S','h','a','r','e','d','D','L','L','s',0};
3062 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3066 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3071 DWORD sz = sizeof(count);
3074 hkey = openSharedDLLsKey();
3075 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3076 if (rc != ERROR_SUCCESS)
3082 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3086 hkey = openSharedDLLsKey();
3088 msi_reg_set_val_dword( hkey, path, count );
3090 RegDeleteValueW(hkey,path);
3095 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3097 MSIFEATURE *feature;
3101 /* only refcount DLLs */
3102 if (comp->KeyPath == NULL ||
3104 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3105 comp->Attributes & msidbComponentAttributesODBCDataSource)
3109 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3110 write = (count > 0);
3112 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3116 /* increment counts */
3117 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3121 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3124 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3126 if ( cl->component == comp )
3131 /* decrement counts */
3132 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3136 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3139 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3141 if ( cl->component == comp )
3146 /* ref count all the files in the component */
3151 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3153 if (file->Component == comp)
3154 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3158 /* add a count for permanent */
3159 if (comp->Attributes & msidbComponentAttributesPermanent)
3162 comp->RefCount = count;
3165 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3168 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3172 const WCHAR prefixW[] = {'<','\\',0};
3173 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3174 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3178 strcpyW( keypath, prefixW );
3179 strcatW( keypath, comp->assembly->display_name );
3183 return resolve_keypath( package, comp );
3186 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3188 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3195 squash_guid(package->ProductCode,squished_pc);
3196 msi_set_sourcedir_props(package, FALSE);
3198 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3201 INSTALLSTATE action;
3203 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3204 if (!comp->ComponentId)
3207 squash_guid( comp->ComponentId, squished_cc );
3208 msi_free( comp->FullKeypath );
3209 comp->FullKeypath = build_full_keypath( package, comp );
3211 ACTION_RefCountComponent( package, comp );
3213 if (package->need_rollback) action = comp->Installed;
3214 else action = comp->ActionRequest;
3216 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3217 debugstr_w(comp->Component), debugstr_w(squished_cc),
3218 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3220 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3222 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3223 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3225 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3227 if (rc != ERROR_SUCCESS)
3230 if (comp->Attributes & msidbComponentAttributesPermanent)
3232 static const WCHAR szPermKey[] =
3233 { '0','0','0','0','0','0','0','0','0','0','0','0',
3234 '0','0','0','0','0','0','0','0','0','0','0','0',
3235 '0','0','0','0','0','0','0','0',0 };
3237 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3239 if (action == INSTALLSTATE_LOCAL)
3240 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3246 WCHAR source[MAX_PATH];
3247 WCHAR base[MAX_PATH];
3250 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3251 static const WCHAR query[] = {
3252 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3253 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3254 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3255 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3256 '`','D','i','s','k','I','d','`',0};
3258 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3261 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3262 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3263 ptr2 = strrchrW(source, '\\') + 1;
3264 msiobj_release(&row->hdr);
3266 lstrcpyW(base, package->PackagePath);
3267 ptr = strrchrW(base, '\\');
3270 sourcepath = msi_resolve_file_source(package, file);
3271 ptr = sourcepath + lstrlenW(base);
3272 lstrcpyW(ptr2, ptr);
3273 msi_free(sourcepath);
3275 msi_reg_set_val_str(hkey, squished_pc, source);
3279 else if (action == INSTALLSTATE_ABSENT)
3281 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3282 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3284 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3288 uirow = MSI_CreateRecord(3);
3289 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3290 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3291 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3292 msi_ui_actiondata( package, szProcessComponents, uirow );
3293 msiobj_release( &uirow->hdr );
3295 return ERROR_SUCCESS;
3306 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3307 LPWSTR lpszName, LONG_PTR lParam)
3310 typelib_struct *tl_struct = (typelib_struct*) lParam;
3311 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3315 if (!IS_INTRESOURCE(lpszName))
3317 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3321 sz = strlenW(tl_struct->source)+4;
3322 sz *= sizeof(WCHAR);
3324 if ((INT_PTR)lpszName == 1)
3325 tl_struct->path = strdupW(tl_struct->source);
3328 tl_struct->path = msi_alloc(sz);
3329 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3332 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3333 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3336 msi_free(tl_struct->path);
3337 tl_struct->path = NULL;
3342 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3343 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3345 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3349 msi_free(tl_struct->path);
3350 tl_struct->path = NULL;
3352 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3353 ITypeLib_Release(tl_struct->ptLib);
3358 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3360 MSIPACKAGE* package = param;
3364 typelib_struct tl_struct;
3369 component = MSI_RecordGetString(row,3);
3370 comp = msi_get_loaded_component(package,component);
3372 return ERROR_SUCCESS;
3374 comp->Action = msi_get_component_action( package, comp );
3375 if (comp->Action != INSTALLSTATE_LOCAL)
3377 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3378 return ERROR_SUCCESS;
3381 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3383 TRACE("component has no key path\n");
3384 return ERROR_SUCCESS;
3386 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3388 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3392 guid = MSI_RecordGetString(row,1);
3393 CLSIDFromString( guid, &tl_struct.clsid);
3394 tl_struct.source = strdupW( file->TargetPath );
3395 tl_struct.path = NULL;
3397 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3398 (LONG_PTR)&tl_struct);
3402 LPCWSTR helpid, help_path = NULL;
3405 helpid = MSI_RecordGetString(row,6);
3407 if (helpid) help_path = msi_get_target_folder( package, helpid );
3408 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3411 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3413 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3415 ITypeLib_Release(tl_struct.ptLib);
3416 msi_free(tl_struct.path);
3418 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3420 FreeLibrary(module);
3421 msi_free(tl_struct.source);
3425 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3428 ERR("Failed to load type library: %08x\n", hr);
3429 return ERROR_INSTALL_FAILURE;
3432 ITypeLib_Release(tlib);
3435 return ERROR_SUCCESS;
3438 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3440 static const WCHAR query[] = {
3441 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3442 '`','T','y','p','e','L','i','b','`',0};
3446 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3447 if (rc != ERROR_SUCCESS)
3448 return ERROR_SUCCESS;
3450 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3451 msiobj_release(&view->hdr);
3455 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3457 MSIPACKAGE *package = param;
3458 LPCWSTR component, guid;
3466 component = MSI_RecordGetString( row, 3 );
3467 comp = msi_get_loaded_component( package, component );
3469 return ERROR_SUCCESS;
3471 comp->Action = msi_get_component_action( package, comp );
3472 if (comp->Action != INSTALLSTATE_ABSENT)
3474 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3475 return ERROR_SUCCESS;
3477 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3479 guid = MSI_RecordGetString( row, 1 );
3480 CLSIDFromString( guid, &libid );
3481 version = MSI_RecordGetInteger( row, 4 );
3482 language = MSI_RecordGetInteger( row, 2 );
3485 syskind = SYS_WIN64;
3487 syskind = SYS_WIN32;
3490 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3493 WARN("Failed to unregister typelib: %08x\n", hr);
3496 return ERROR_SUCCESS;
3499 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3501 static const WCHAR query[] = {
3502 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3503 '`','T','y','p','e','L','i','b','`',0};
3507 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3508 if (rc != ERROR_SUCCESS)
3509 return ERROR_SUCCESS;
3511 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3512 msiobj_release( &view->hdr );
3516 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3518 static const WCHAR szlnk[] = {'.','l','n','k',0};
3519 LPCWSTR directory, extension, link_folder;
3520 LPWSTR link_file, filename;
3522 directory = MSI_RecordGetString( row, 2 );
3523 link_folder = msi_get_target_folder( package, directory );
3526 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3529 /* may be needed because of a bug somewhere else */
3530 msi_create_full_path( link_folder );
3532 filename = msi_dup_record_field( row, 3 );
3533 msi_reduce_to_long_filename( filename );
3535 extension = strchrW( filename, '.' );
3536 if (!extension || strcmpiW( extension, szlnk ))
3538 int len = strlenW( filename );
3539 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3540 memcpy( filename + len, szlnk, sizeof(szlnk) );
3542 link_file = msi_build_directory_name( 2, link_folder, filename );
3543 msi_free( filename );
3548 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3550 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3551 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3552 WCHAR *folder, *dest, *path;
3554 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3555 folder = msi_dup_property( package->db, szWindowsFolder );
3558 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3559 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3560 msi_free( appdata );
3562 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3563 msi_create_full_path( dest );
3564 path = msi_build_directory_name( 2, dest, icon_name );
3570 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3572 MSIPACKAGE *package = param;
3573 LPWSTR link_file, deformated, path;
3574 LPCWSTR component, target;
3576 IShellLinkW *sl = NULL;
3577 IPersistFile *pf = NULL;
3580 component = MSI_RecordGetString(row, 4);
3581 comp = msi_get_loaded_component(package, component);
3583 return ERROR_SUCCESS;
3585 comp->Action = msi_get_component_action( package, comp );
3586 if (comp->Action != INSTALLSTATE_LOCAL)
3588 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3589 return ERROR_SUCCESS;
3591 msi_ui_actiondata( package, szCreateShortcuts, row );
3593 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3594 &IID_IShellLinkW, (LPVOID *) &sl );
3598 ERR("CLSID_ShellLink not available\n");
3602 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3605 ERR("QueryInterface(IID_IPersistFile) failed\n");
3609 target = MSI_RecordGetString(row, 5);
3610 if (strchrW(target, '['))
3612 deformat_string( package, target, &path );
3613 TRACE("target path is %s\n", debugstr_w(path));
3614 IShellLinkW_SetPath( sl, path );
3619 FIXME("poorly handled shortcut format, advertised shortcut\n");
3620 IShellLinkW_SetPath(sl,comp->FullKeypath);
3623 if (!MSI_RecordIsNull(row,6))
3625 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3626 deformat_string(package, arguments, &deformated);
3627 IShellLinkW_SetArguments(sl,deformated);
3628 msi_free(deformated);
3631 if (!MSI_RecordIsNull(row,7))
3633 LPCWSTR description = MSI_RecordGetString(row, 7);
3634 IShellLinkW_SetDescription(sl, description);
3637 if (!MSI_RecordIsNull(row,8))
3638 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3640 if (!MSI_RecordIsNull(row,9))
3643 LPCWSTR icon = MSI_RecordGetString(row, 9);
3645 path = msi_build_icon_path(package, icon);
3646 index = MSI_RecordGetInteger(row,10);
3648 /* no value means 0 */
3649 if (index == MSI_NULL_INTEGER)
3652 IShellLinkW_SetIconLocation(sl, path, index);
3656 if (!MSI_RecordIsNull(row,11))
3657 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3659 if (!MSI_RecordIsNull(row,12))
3661 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3662 full_path = msi_get_target_folder( package, wkdir );
3663 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3665 link_file = get_link_file(package, row);
3667 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3668 IPersistFile_Save(pf, link_file, FALSE);
3669 msi_free(link_file);
3673 IPersistFile_Release( pf );
3675 IShellLinkW_Release( sl );
3677 return ERROR_SUCCESS;
3680 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3682 static const WCHAR query[] = {
3683 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3684 '`','S','h','o','r','t','c','u','t','`',0};
3689 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3690 if (rc != ERROR_SUCCESS)
3691 return ERROR_SUCCESS;
3693 res = CoInitialize( NULL );
3695 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3696 msiobj_release(&view->hdr);
3698 if (SUCCEEDED(res)) CoUninitialize();
3702 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3704 MSIPACKAGE *package = param;
3709 component = MSI_RecordGetString( row, 4 );
3710 comp = msi_get_loaded_component( package, component );
3712 return ERROR_SUCCESS;
3714 comp->Action = msi_get_component_action( package, comp );
3715 if (comp->Action != INSTALLSTATE_ABSENT)
3717 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3718 return ERROR_SUCCESS;
3720 msi_ui_actiondata( package, szRemoveShortcuts, row );
3722 link_file = get_link_file( package, row );
3724 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3725 if (!DeleteFileW( link_file ))
3727 WARN("Failed to remove shortcut file %u\n", GetLastError());
3729 msi_free( link_file );
3731 return ERROR_SUCCESS;
3734 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3736 static const WCHAR query[] = {
3737 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3738 '`','S','h','o','r','t','c','u','t','`',0};
3742 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3743 if (rc != ERROR_SUCCESS)
3744 return ERROR_SUCCESS;
3746 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3747 msiobj_release( &view->hdr );
3751 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3753 MSIPACKAGE* package = param;
3761 FileName = MSI_RecordGetString(row,1);
3764 ERR("Unable to get FileName\n");
3765 return ERROR_SUCCESS;
3768 FilePath = msi_build_icon_path(package, FileName);
3770 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3772 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3773 FILE_ATTRIBUTE_NORMAL, NULL);
3775 if (the_file == INVALID_HANDLE_VALUE)
3777 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3779 return ERROR_SUCCESS;
3786 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3787 if (rc != ERROR_SUCCESS)
3789 ERR("Failed to get stream\n");
3790 CloseHandle(the_file);
3791 DeleteFileW(FilePath);
3794 WriteFile(the_file,buffer,sz,&write,NULL);
3795 } while (sz == 1024);
3798 CloseHandle(the_file);
3800 return ERROR_SUCCESS;
3803 static UINT msi_publish_icons(MSIPACKAGE *package)
3805 static const WCHAR query[]= {
3806 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3807 '`','I','c','o','n','`',0};
3811 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3812 if (r == ERROR_SUCCESS)
3814 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3815 msiobj_release(&view->hdr);
3816 if (r != ERROR_SUCCESS)
3819 return ERROR_SUCCESS;
3822 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3828 MSISOURCELISTINFO *info;
3830 r = RegCreateKeyW(hkey, szSourceList, &source);
3831 if (r != ERROR_SUCCESS)
3834 RegCloseKey(source);
3836 buffer = strrchrW(package->PackagePath, '\\') + 1;
3837 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3838 package->Context, MSICODE_PRODUCT,
3839 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3840 if (r != ERROR_SUCCESS)
3843 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3844 package->Context, MSICODE_PRODUCT,
3845 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3846 if (r != ERROR_SUCCESS)
3849 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3850 package->Context, MSICODE_PRODUCT,
3851 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3852 if (r != ERROR_SUCCESS)
3855 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3857 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3858 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3859 info->options, info->value);
3861 MsiSourceListSetInfoW(package->ProductCode, NULL,
3862 info->context, info->options,
3863 info->property, info->value);
3866 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3868 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3869 disk->context, disk->options,
3870 disk->disk_id, disk->volume_label, disk->disk_prompt);
3873 return ERROR_SUCCESS;
3876 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3878 MSIHANDLE hdb, suminfo;
3879 WCHAR guids[MAX_PATH];
3880 WCHAR packcode[SQUISH_GUID_SIZE];
3887 static const WCHAR szARPProductIcon[] =
3888 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3889 static const WCHAR szAssignment[] =
3890 {'A','s','s','i','g','n','m','e','n','t',0};
3891 static const WCHAR szAdvertiseFlags[] =
3892 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3893 static const WCHAR szClients[] =
3894 {'C','l','i','e','n','t','s',0};
3895 static const WCHAR szColon[] = {':',0};
3897 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3898 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3901 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3902 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3905 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3907 buffer = msi_dup_property(package->db, szARPProductIcon);
3910 LPWSTR path = msi_build_icon_path(package, buffer);
3911 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3916 buffer = msi_dup_property(package->db, szProductVersion);
3919 DWORD verdword = msi_version_str_to_dword(buffer);
3920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3924 msi_reg_set_val_dword(hkey, szAssignment, 0);
3925 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3926 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3927 msi_reg_set_val_str(hkey, szClients, szColon);
3929 hdb = alloc_msihandle(&package->db->hdr);
3931 return ERROR_NOT_ENOUGH_MEMORY;
3933 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3934 MsiCloseHandle(hdb);
3935 if (r != ERROR_SUCCESS)
3939 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3940 NULL, guids, &size);
3941 if (r != ERROR_SUCCESS)
3944 ptr = strchrW(guids, ';');
3946 squash_guid(guids, packcode);
3947 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3950 MsiCloseHandle(suminfo);
3951 return ERROR_SUCCESS;
3954 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3959 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3961 upgrade = msi_dup_property(package->db, szUpgradeCode);
3963 return ERROR_SUCCESS;
3965 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3966 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3968 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3970 if (r != ERROR_SUCCESS)
3972 WARN("failed to open upgrade code key\n");
3974 return ERROR_SUCCESS;
3976 squash_guid(package->ProductCode, squashed_pc);
3977 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3980 return ERROR_SUCCESS;
3983 static BOOL msi_check_publish(MSIPACKAGE *package)
3985 MSIFEATURE *feature;
3987 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3989 feature->Action = msi_get_feature_action( package, feature );
3990 if (feature->Action == INSTALLSTATE_LOCAL)
3997 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3999 MSIFEATURE *feature;
4001 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4003 feature->Action = msi_get_feature_action( package, feature );
4004 if (feature->Action != INSTALLSTATE_ABSENT)
4011 static UINT msi_publish_patches( MSIPACKAGE *package )
4013 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4014 WCHAR patch_squashed[GUID_SIZE];
4015 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4017 MSIPATCHINFO *patch;
4019 WCHAR *p, *all_patches = NULL;
4022 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4023 if (r != ERROR_SUCCESS)
4024 return ERROR_FUNCTION_FAILED;
4026 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4027 if (res != ERROR_SUCCESS)
4029 r = ERROR_FUNCTION_FAILED;
4033 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4034 if (r != ERROR_SUCCESS)
4037 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4039 squash_guid( patch->patchcode, patch_squashed );
4040 len += strlenW( patch_squashed ) + 1;
4043 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4047 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4051 squash_guid( patch->patchcode, p );
4052 p += strlenW( p ) + 1;
4054 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4055 (const BYTE *)patch->transforms,
4056 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4057 if (res != ERROR_SUCCESS)
4060 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4061 if (r != ERROR_SUCCESS)
4064 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4065 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4066 RegCloseKey( patch_key );
4067 if (res != ERROR_SUCCESS)
4070 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4072 res = GetLastError();
4073 ERR("Unable to copy patch package %d\n", res);
4076 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4077 if (res != ERROR_SUCCESS)
4080 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4081 RegCloseKey( patch_key );
4082 if (res != ERROR_SUCCESS)
4086 all_patches[len] = 0;
4087 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4088 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4089 if (res != ERROR_SUCCESS)
4092 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4093 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4094 if (res != ERROR_SUCCESS)
4095 r = ERROR_FUNCTION_FAILED;
4098 RegCloseKey( product_patches_key );
4099 RegCloseKey( patches_key );
4100 RegCloseKey( product_key );
4101 msi_free( all_patches );
4105 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4108 HKEY hukey = NULL, hudkey = NULL;
4111 if (!list_empty(&package->patches))
4113 rc = msi_publish_patches(package);
4114 if (rc != ERROR_SUCCESS)
4118 /* FIXME: also need to publish if the product is in advertise mode */
4119 if (!msi_check_publish(package))
4120 return ERROR_SUCCESS;
4122 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4124 if (rc != ERROR_SUCCESS)
4127 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4128 NULL, &hudkey, TRUE);
4129 if (rc != ERROR_SUCCESS)
4132 rc = msi_publish_upgrade_code(package);
4133 if (rc != ERROR_SUCCESS)
4136 rc = msi_publish_product_properties(package, hukey);
4137 if (rc != ERROR_SUCCESS)
4140 rc = msi_publish_sourcelist(package, hukey);
4141 if (rc != ERROR_SUCCESS)
4144 rc = msi_publish_icons(package);
4147 uirow = MSI_CreateRecord( 1 );
4148 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4149 msi_ui_actiondata( package, szPublishProduct, uirow );
4150 msiobj_release( &uirow->hdr );
4153 RegCloseKey(hudkey);
4157 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4159 WCHAR *filename, *ptr, *folder, *ret;
4160 const WCHAR *dirprop;
4162 filename = msi_dup_record_field( row, 2 );
4163 if (filename && (ptr = strchrW( filename, '|' )))
4168 dirprop = MSI_RecordGetString( row, 3 );
4171 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4172 if (!folder) folder = msi_dup_property( package->db, dirprop );
4175 folder = msi_dup_property( package->db, szWindowsFolder );
4179 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4180 msi_free( filename );
4184 ret = msi_build_directory_name( 2, folder, ptr );
4186 msi_free( filename );
4191 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4193 MSIPACKAGE *package = param;
4194 LPCWSTR component, section, key, value, identifier;
4195 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4200 component = MSI_RecordGetString(row, 8);
4201 comp = msi_get_loaded_component(package,component);
4203 return ERROR_SUCCESS;
4205 comp->Action = msi_get_component_action( package, comp );
4206 if (comp->Action != INSTALLSTATE_LOCAL)
4208 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4209 return ERROR_SUCCESS;
4212 identifier = MSI_RecordGetString(row,1);
4213 section = MSI_RecordGetString(row,4);
4214 key = MSI_RecordGetString(row,5);
4215 value = MSI_RecordGetString(row,6);
4216 action = MSI_RecordGetInteger(row,7);
4218 deformat_string(package,section,&deformated_section);
4219 deformat_string(package,key,&deformated_key);
4220 deformat_string(package,value,&deformated_value);
4222 fullname = get_ini_file_name(package, row);
4226 TRACE("Adding value %s to section %s in %s\n",
4227 debugstr_w(deformated_key), debugstr_w(deformated_section),
4228 debugstr_w(fullname));
4229 WritePrivateProfileStringW(deformated_section, deformated_key,
4230 deformated_value, fullname);
4232 else if (action == 1)
4235 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4236 returned, 10, fullname);
4237 if (returned[0] == 0)
4239 TRACE("Adding value %s to section %s in %s\n",
4240 debugstr_w(deformated_key), debugstr_w(deformated_section),
4241 debugstr_w(fullname));
4243 WritePrivateProfileStringW(deformated_section, deformated_key,
4244 deformated_value, fullname);
4247 else if (action == 3)
4248 FIXME("Append to existing section not yet implemented\n");
4250 uirow = MSI_CreateRecord(4);
4251 MSI_RecordSetStringW(uirow,1,identifier);
4252 MSI_RecordSetStringW(uirow,2,deformated_section);
4253 MSI_RecordSetStringW(uirow,3,deformated_key);
4254 MSI_RecordSetStringW(uirow,4,deformated_value);
4255 msi_ui_actiondata( package, szWriteIniValues, uirow );
4256 msiobj_release( &uirow->hdr );
4259 msi_free(deformated_key);
4260 msi_free(deformated_value);
4261 msi_free(deformated_section);
4262 return ERROR_SUCCESS;
4265 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4267 static const WCHAR query[] = {
4268 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4269 '`','I','n','i','F','i','l','e','`',0};
4273 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4274 if (rc != ERROR_SUCCESS)
4275 return ERROR_SUCCESS;
4277 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4278 msiobj_release(&view->hdr);
4282 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4284 MSIPACKAGE *package = param;
4285 LPCWSTR component, section, key, value, identifier;
4286 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4291 component = MSI_RecordGetString( row, 8 );
4292 comp = msi_get_loaded_component( package, component );
4294 return ERROR_SUCCESS;
4296 comp->Action = msi_get_component_action( package, comp );
4297 if (comp->Action != INSTALLSTATE_ABSENT)
4299 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4300 return ERROR_SUCCESS;
4303 identifier = MSI_RecordGetString( row, 1 );
4304 section = MSI_RecordGetString( row, 4 );
4305 key = MSI_RecordGetString( row, 5 );
4306 value = MSI_RecordGetString( row, 6 );
4307 action = MSI_RecordGetInteger( row, 7 );
4309 deformat_string( package, section, &deformated_section );
4310 deformat_string( package, key, &deformated_key );
4311 deformat_string( package, value, &deformated_value );
4313 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4315 filename = get_ini_file_name( package, row );
4317 TRACE("Removing key %s from section %s in %s\n",
4318 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4320 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4322 WARN("Unable to remove key %u\n", GetLastError());
4324 msi_free( filename );
4327 FIXME("Unsupported action %d\n", action);
4330 uirow = MSI_CreateRecord( 4 );
4331 MSI_RecordSetStringW( uirow, 1, identifier );
4332 MSI_RecordSetStringW( uirow, 2, deformated_section );
4333 MSI_RecordSetStringW( uirow, 3, deformated_key );
4334 MSI_RecordSetStringW( uirow, 4, deformated_value );
4335 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4336 msiobj_release( &uirow->hdr );
4338 msi_free( deformated_key );
4339 msi_free( deformated_value );
4340 msi_free( deformated_section );
4341 return ERROR_SUCCESS;
4344 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4346 MSIPACKAGE *package = param;
4347 LPCWSTR component, section, key, value, identifier;
4348 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4353 component = MSI_RecordGetString( row, 8 );
4354 comp = msi_get_loaded_component( package, component );
4356 return ERROR_SUCCESS;
4358 comp->Action = msi_get_component_action( package, comp );
4359 if (comp->Action != INSTALLSTATE_LOCAL)
4361 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4362 return ERROR_SUCCESS;
4365 identifier = MSI_RecordGetString( row, 1 );
4366 section = MSI_RecordGetString( row, 4 );
4367 key = MSI_RecordGetString( row, 5 );
4368 value = MSI_RecordGetString( row, 6 );
4369 action = MSI_RecordGetInteger( row, 7 );
4371 deformat_string( package, section, &deformated_section );
4372 deformat_string( package, key, &deformated_key );
4373 deformat_string( package, value, &deformated_value );
4375 if (action == msidbIniFileActionRemoveLine)
4377 filename = get_ini_file_name( package, row );
4379 TRACE("Removing key %s from section %s in %s\n",
4380 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4382 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4384 WARN("Unable to remove key %u\n", GetLastError());
4386 msi_free( filename );
4389 FIXME("Unsupported action %d\n", action);
4391 uirow = MSI_CreateRecord( 4 );
4392 MSI_RecordSetStringW( uirow, 1, identifier );
4393 MSI_RecordSetStringW( uirow, 2, deformated_section );
4394 MSI_RecordSetStringW( uirow, 3, deformated_key );
4395 MSI_RecordSetStringW( uirow, 4, deformated_value );
4396 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4397 msiobj_release( &uirow->hdr );
4399 msi_free( deformated_key );
4400 msi_free( deformated_value );
4401 msi_free( deformated_section );
4402 return ERROR_SUCCESS;
4405 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4407 static const WCHAR query[] = {
4408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4409 '`','I','n','i','F','i','l','e','`',0};
4410 static const WCHAR remove_query[] = {
4411 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4412 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4416 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4417 if (rc == ERROR_SUCCESS)
4419 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4420 msiobj_release( &view->hdr );
4421 if (rc != ERROR_SUCCESS)
4424 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4425 if (rc == ERROR_SUCCESS)
4427 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4428 msiobj_release( &view->hdr );
4429 if (rc != ERROR_SUCCESS)
4432 return ERROR_SUCCESS;
4435 static void register_dll( const WCHAR *dll, BOOL unregister )
4439 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4442 HRESULT (WINAPI *func_ptr)( void );
4443 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4445 func_ptr = (void *)GetProcAddress( hmod, func );
4448 HRESULT hr = func_ptr();
4450 WARN("failed to register dll 0x%08x\n", hr);
4453 WARN("entry point %s not found\n", func);
4454 FreeLibrary( hmod );
4457 WARN("failed to load library %u\n", GetLastError());
4460 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4462 MSIPACKAGE *package = param;
4467 filename = MSI_RecordGetString( row, 1 );
4468 file = msi_get_loaded_file( package, filename );
4471 WARN("unable to find file %s\n", debugstr_w(filename));
4472 return ERROR_SUCCESS;
4474 file->Component->Action = msi_get_component_action( package, file->Component );
4475 if (file->Component->Action != INSTALLSTATE_LOCAL)
4477 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4478 return ERROR_SUCCESS;
4481 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4482 register_dll( file->TargetPath, FALSE );
4484 uirow = MSI_CreateRecord( 2 );
4485 MSI_RecordSetStringW( uirow, 1, file->File );
4486 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4487 msi_ui_actiondata( package, szSelfRegModules, uirow );
4488 msiobj_release( &uirow->hdr );
4490 return ERROR_SUCCESS;
4493 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4495 static const WCHAR query[] = {
4496 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4497 '`','S','e','l','f','R','e','g','`',0};
4501 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4502 if (rc != ERROR_SUCCESS)
4503 return ERROR_SUCCESS;
4505 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4506 msiobj_release(&view->hdr);
4510 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4512 MSIPACKAGE *package = param;
4517 filename = MSI_RecordGetString( row, 1 );
4518 file = msi_get_loaded_file( package, filename );
4521 WARN("unable to find file %s\n", debugstr_w(filename));
4522 return ERROR_SUCCESS;
4524 file->Component->Action = msi_get_component_action( package, file->Component );
4525 if (file->Component->Action != INSTALLSTATE_ABSENT)
4527 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4528 return ERROR_SUCCESS;
4531 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4532 register_dll( file->TargetPath, TRUE );
4534 uirow = MSI_CreateRecord( 2 );
4535 MSI_RecordSetStringW( uirow, 1, file->File );
4536 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4537 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4538 msiobj_release( &uirow->hdr );
4540 return ERROR_SUCCESS;
4543 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4545 static const WCHAR query[] = {
4546 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4547 '`','S','e','l','f','R','e','g','`',0};
4551 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4552 if (rc != ERROR_SUCCESS)
4553 return ERROR_SUCCESS;
4555 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4556 msiobj_release( &view->hdr );
4560 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4562 MSIFEATURE *feature;
4564 HKEY hkey = NULL, userdata = NULL;
4566 if (!msi_check_publish(package))
4567 return ERROR_SUCCESS;
4569 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4571 if (rc != ERROR_SUCCESS)
4574 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4576 if (rc != ERROR_SUCCESS)
4579 /* here the guids are base 85 encoded */
4580 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4586 BOOL absent = FALSE;
4589 if (feature->Action != INSTALLSTATE_LOCAL &&
4590 feature->Action != INSTALLSTATE_SOURCE &&
4591 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4594 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4598 if (feature->Feature_Parent)
4599 size += strlenW( feature->Feature_Parent )+2;
4601 data = msi_alloc(size * sizeof(WCHAR));
4604 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4606 MSICOMPONENT* component = cl->component;
4610 if (component->ComponentId)
4612 TRACE("From %s\n",debugstr_w(component->ComponentId));
4613 CLSIDFromString(component->ComponentId, &clsid);
4614 encode_base85_guid(&clsid,buf);
4615 TRACE("to %s\n",debugstr_w(buf));
4620 if (feature->Feature_Parent)
4622 static const WCHAR sep[] = {'\2',0};
4624 strcatW(data,feature->Feature_Parent);
4627 msi_reg_set_val_str( userdata, feature->Feature, data );
4631 if (feature->Feature_Parent)
4632 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4635 size += sizeof(WCHAR);
4636 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4637 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4641 size += 2*sizeof(WCHAR);
4642 data = msi_alloc(size);
4645 if (feature->Feature_Parent)
4646 strcpyW( &data[1], feature->Feature_Parent );
4647 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4653 uirow = MSI_CreateRecord( 1 );
4654 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4655 msi_ui_actiondata( package, szPublishFeatures, uirow );
4656 msiobj_release( &uirow->hdr );
4657 /* FIXME: call msi_ui_progress? */
4662 RegCloseKey(userdata);
4666 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4672 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4674 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4676 if (r == ERROR_SUCCESS)
4678 RegDeleteValueW(hkey, feature->Feature);
4682 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4684 if (r == ERROR_SUCCESS)
4686 RegDeleteValueW(hkey, feature->Feature);
4690 uirow = MSI_CreateRecord( 1 );
4691 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4692 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4693 msiobj_release( &uirow->hdr );
4695 return ERROR_SUCCESS;
4698 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4700 MSIFEATURE *feature;
4702 if (!msi_check_unpublish(package))
4703 return ERROR_SUCCESS;
4705 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4707 msi_unpublish_feature(package, feature);
4710 return ERROR_SUCCESS;
4713 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4717 WCHAR date[9], *val, *buffer;
4718 const WCHAR *prop, *key;
4720 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4721 static const WCHAR modpath_fmt[] =
4722 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4723 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4724 static const WCHAR szModifyPath[] =
4725 {'M','o','d','i','f','y','P','a','t','h',0};
4726 static const WCHAR szUninstallString[] =
4727 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4728 static const WCHAR szEstimatedSize[] =
4729 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4730 static const WCHAR szDisplayVersion[] =
4731 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4732 static const WCHAR szInstallSource[] =
4733 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4734 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4735 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4736 static const WCHAR szAuthorizedCDFPrefix[] =
4737 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4738 static const WCHAR szARPCONTACT[] =
4739 {'A','R','P','C','O','N','T','A','C','T',0};
4740 static const WCHAR szContact[] =
4741 {'C','o','n','t','a','c','t',0};
4742 static const WCHAR szARPCOMMENTS[] =
4743 {'A','R','P','C','O','M','M','E','N','T','S',0};
4744 static const WCHAR szComments[] =
4745 {'C','o','m','m','e','n','t','s',0};
4746 static const WCHAR szProductName[] =
4747 {'P','r','o','d','u','c','t','N','a','m','e',0};
4748 static const WCHAR szDisplayName[] =
4749 {'D','i','s','p','l','a','y','N','a','m','e',0};
4750 static const WCHAR szARPHELPLINK[] =
4751 {'A','R','P','H','E','L','P','L','I','N','K',0};
4752 static const WCHAR szHelpLink[] =
4753 {'H','e','l','p','L','i','n','k',0};
4754 static const WCHAR szARPHELPTELEPHONE[] =
4755 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4756 static const WCHAR szHelpTelephone[] =
4757 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4758 static const WCHAR szARPINSTALLLOCATION[] =
4759 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4760 static const WCHAR szInstallLocation[] =
4761 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4762 static const WCHAR szManufacturer[] =
4763 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4764 static const WCHAR szPublisher[] =
4765 {'P','u','b','l','i','s','h','e','r',0};
4766 static const WCHAR szARPREADME[] =
4767 {'A','R','P','R','E','A','D','M','E',0};
4768 static const WCHAR szReadme[] =
4769 {'R','e','a','d','M','e',0};
4770 static const WCHAR szARPSIZE[] =
4771 {'A','R','P','S','I','Z','E',0};
4772 static const WCHAR szSize[] =
4773 {'S','i','z','e',0};
4774 static const WCHAR szARPURLINFOABOUT[] =
4775 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4776 static const WCHAR szURLInfoAbout[] =
4777 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4778 static const WCHAR szARPURLUPDATEINFO[] =
4779 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4780 static const WCHAR szURLUpdateInfo[] =
4781 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4782 static const WCHAR szARPSYSTEMCOMPONENT[] =
4783 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4784 static const WCHAR szSystemComponent[] =
4785 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4787 static const WCHAR *propval[] = {
4788 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4789 szARPCONTACT, szContact,
4790 szARPCOMMENTS, szComments,
4791 szProductName, szDisplayName,
4792 szARPHELPLINK, szHelpLink,
4793 szARPHELPTELEPHONE, szHelpTelephone,
4794 szARPINSTALLLOCATION, szInstallLocation,
4795 szSourceDir, szInstallSource,
4796 szManufacturer, szPublisher,
4797 szARPREADME, szReadme,
4799 szARPURLINFOABOUT, szURLInfoAbout,
4800 szARPURLUPDATEINFO, szURLUpdateInfo,
4803 const WCHAR **p = propval;
4809 val = msi_dup_property(package->db, prop);
4810 msi_reg_set_val_str(hkey, key, val);
4814 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4815 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4817 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4819 size = deformat_string(package, modpath_fmt, &buffer);
4820 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4821 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4824 /* FIXME: Write real Estimated Size when we have it */
4825 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4827 GetLocalTime(&systime);
4828 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4829 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4831 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4832 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4834 buffer = msi_dup_property(package->db, szProductVersion);
4835 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4838 DWORD verdword = msi_version_str_to_dword(buffer);
4840 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4841 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4842 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4846 return ERROR_SUCCESS;
4849 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4851 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4853 LPWSTR upgrade_code;
4854 HKEY hkey, props, upgrade_key;
4857 /* FIXME: also need to publish if the product is in advertise mode */
4858 if (!msi_check_publish(package))
4859 return ERROR_SUCCESS;
4861 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4862 if (rc != ERROR_SUCCESS)
4865 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4866 if (rc != ERROR_SUCCESS)
4869 rc = msi_publish_install_properties(package, hkey);
4870 if (rc != ERROR_SUCCESS)
4873 rc = msi_publish_install_properties(package, props);
4874 if (rc != ERROR_SUCCESS)
4877 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4880 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4881 if (rc == ERROR_SUCCESS)
4883 squash_guid( package->ProductCode, squashed_pc );
4884 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4885 RegCloseKey( upgrade_key );
4887 msi_free( upgrade_code );
4889 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4890 package->delete_on_close = FALSE;
4893 uirow = MSI_CreateRecord( 1 );
4894 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4895 msi_ui_actiondata( package, szRegisterProduct, uirow );
4896 msiobj_release( &uirow->hdr );
4899 return ERROR_SUCCESS;
4902 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4904 return execute_script(package, SCRIPT_INSTALL);
4907 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4909 MSIPACKAGE *package = param;
4910 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4911 WCHAR *p, *icon_path;
4913 if (!icon) return ERROR_SUCCESS;
4914 if ((icon_path = msi_build_icon_path( package, icon )))
4916 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4917 DeleteFileW( icon_path );
4918 if ((p = strrchrW( icon_path, '\\' )))
4921 RemoveDirectoryW( icon_path );
4923 msi_free( icon_path );
4925 return ERROR_SUCCESS;
4928 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4930 static const WCHAR query[]= {
4931 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4935 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4936 if (r == ERROR_SUCCESS)
4938 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4939 msiobj_release( &view->hdr );
4940 if (r != ERROR_SUCCESS)
4943 return ERROR_SUCCESS;
4946 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4948 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4949 WCHAR *upgrade, **features;
4950 BOOL full_uninstall = TRUE;
4951 MSIFEATURE *feature;
4952 MSIPATCHINFO *patch;
4955 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4957 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4959 features = msi_split_string( remove, ',' );
4960 for (i = 0; features && features[i]; i++)
4962 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4966 if (!full_uninstall)
4967 return ERROR_SUCCESS;
4969 MSIREG_DeleteProductKey(package->ProductCode);
4970 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4971 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4973 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4974 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4975 MSIREG_DeleteUserProductKey(package->ProductCode);
4976 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4978 upgrade = msi_dup_property(package->db, szUpgradeCode);
4981 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4982 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4986 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4988 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4989 if (!strcmpW( package->ProductCode, patch->products ))
4991 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
4992 patch->delete_on_close = TRUE;
4994 /* FIXME: remove local patch package if this is the last product */
4996 TRACE("removing local package %s\n", debugstr_w(package->localfile));
4997 package->delete_on_close = TRUE;
4999 msi_unpublish_icons( package );
5000 return ERROR_SUCCESS;
5003 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5008 /* turn off scheduling */
5009 package->script->CurrentlyScripting= FALSE;
5011 /* first do the same as an InstallExecute */
5012 rc = ACTION_InstallExecute(package);
5013 if (rc != ERROR_SUCCESS)
5016 /* then handle commit actions */
5017 rc = execute_script(package, SCRIPT_COMMIT);
5018 if (rc != ERROR_SUCCESS)
5021 remove = msi_dup_property(package->db, szRemove);
5022 rc = msi_unpublish_product(package, remove);
5027 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5029 static const WCHAR RunOnce[] = {
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 'R','u','n','O','n','c','e',0};
5035 static const WCHAR InstallRunOnce[] = {
5036 'S','o','f','t','w','a','r','e','\\',
5037 'M','i','c','r','o','s','o','f','t','\\',
5038 'W','i','n','d','o','w','s','\\',
5039 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5040 'I','n','s','t','a','l','l','e','r','\\',
5041 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5043 static const WCHAR msiexec_fmt[] = {
5045 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5046 '\"','%','s','\"',0};
5047 static const WCHAR install_fmt[] = {
5048 '/','I',' ','\"','%','s','\"',' ',
5049 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5050 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5051 WCHAR buffer[256], sysdir[MAX_PATH];
5053 WCHAR squished_pc[100];
5055 squash_guid(package->ProductCode,squished_pc);
5057 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5058 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5059 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5062 msi_reg_set_val_str( hkey, squished_pc, buffer );
5065 TRACE("Reboot command %s\n",debugstr_w(buffer));
5067 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5068 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5070 msi_reg_set_val_str( hkey, squished_pc, buffer );
5073 return ERROR_INSTALL_SUSPEND;
5076 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5078 static const WCHAR query[] =
5079 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5080 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5081 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5082 MSIRECORD *rec, *row;
5088 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5090 rec = MSI_CreateRecord( count + 2 );
5091 str = MSI_RecordGetString( row, 1 );
5092 MSI_RecordSetStringW( rec, 0, str );
5093 msiobj_release( &row->hdr );
5094 MSI_RecordSetInteger( rec, 1, error );
5096 va_start( va, count );
5097 for (i = 0; i < count; i++)
5099 str = va_arg( va, const WCHAR *);
5100 MSI_RecordSetStringW( rec, i + 2, str );
5104 MSI_FormatRecordW( package, rec, NULL, &size );
5106 data = msi_alloc( size * sizeof(WCHAR) );
5107 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5109 msiobj_release( &rec->hdr );
5113 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5119 * We are currently doing what should be done here in the top level Install
5120 * however for Administrative and uninstalls this step will be needed
5122 if (!package->PackagePath)
5123 return ERROR_SUCCESS;
5125 msi_set_sourcedir_props(package, TRUE);
5127 attrib = GetFileAttributesW(package->db->path);
5128 if (attrib == INVALID_FILE_ATTRIBUTES)
5133 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5134 package->Context, MSICODE_PRODUCT,
5135 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5136 if (rc == ERROR_MORE_DATA)
5138 prompt = msi_alloc(size * sizeof(WCHAR));
5139 MsiSourceListGetInfoW(package->ProductCode, NULL,
5140 package->Context, MSICODE_PRODUCT,
5141 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5144 prompt = strdupW(package->db->path);
5146 msg = msi_build_error_string(package, 1302, 1, prompt);
5148 while(attrib == INVALID_FILE_ATTRIBUTES)
5150 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5154 return ERROR_INSTALL_USEREXIT;
5156 attrib = GetFileAttributesW(package->db->path);
5162 return ERROR_SUCCESS;
5167 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5170 LPWSTR buffer, productid = NULL;
5171 UINT i, rc = ERROR_SUCCESS;
5174 static const WCHAR szPropKeys[][80] =
5176 {'P','r','o','d','u','c','t','I','D',0},
5177 {'U','S','E','R','N','A','M','E',0},
5178 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5182 static const WCHAR szRegKeys[][80] =
5184 {'P','r','o','d','u','c','t','I','D',0},
5185 {'R','e','g','O','w','n','e','r',0},
5186 {'R','e','g','C','o','m','p','a','n','y',0},
5190 if (msi_check_unpublish(package))
5192 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5196 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5200 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5202 if (rc != ERROR_SUCCESS)
5205 for( i = 0; szPropKeys[i][0]; i++ )
5207 buffer = msi_dup_property( package->db, szPropKeys[i] );
5208 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5213 uirow = MSI_CreateRecord( 1 );
5214 MSI_RecordSetStringW( uirow, 1, productid );
5215 msi_ui_actiondata( package, szRegisterUser, uirow );
5216 msiobj_release( &uirow->hdr );
5218 msi_free(productid);
5224 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5228 package->script->InWhatSequence |= SEQUENCE_EXEC;
5229 rc = ACTION_ProcessExecSequence(package,FALSE);
5233 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5235 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5236 WCHAR productid_85[21], component_85[21], *ret;
5240 /* > is used if there is a component GUID and < if not. */
5242 productid_85[0] = 0;
5243 component_85[0] = 0;
5244 CLSIDFromString( package->ProductCode, &clsid );
5246 encode_base85_guid( &clsid, productid_85 );
5249 CLSIDFromString( component->ComponentId, &clsid );
5250 encode_base85_guid( &clsid, component_85 );
5253 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5254 debugstr_w(component_85));
5256 sz = 20 + strlenW( feature ) + 20 + 3;
5257 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5258 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5262 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5264 MSIPACKAGE *package = param;
5265 LPCWSTR compgroupid, component, feature, qualifier, text;
5266 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5275 feature = MSI_RecordGetString(rec, 5);
5276 feat = msi_get_loaded_feature(package, feature);
5278 return ERROR_SUCCESS;
5280 feat->Action = msi_get_feature_action( package, feat );
5281 if (feat->Action != INSTALLSTATE_LOCAL &&
5282 feat->Action != INSTALLSTATE_SOURCE &&
5283 feat->Action != INSTALLSTATE_ADVERTISED)
5285 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5286 return ERROR_SUCCESS;
5289 component = MSI_RecordGetString(rec, 3);
5290 comp = msi_get_loaded_component(package, component);
5292 return ERROR_SUCCESS;
5294 compgroupid = MSI_RecordGetString(rec,1);
5295 qualifier = MSI_RecordGetString(rec,2);
5297 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5298 if (rc != ERROR_SUCCESS)
5301 advertise = msi_create_component_advertise_string( package, comp, feature );
5302 text = MSI_RecordGetString( rec, 4 );
5305 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5306 strcpyW( p, advertise );
5308 msi_free( advertise );
5311 existing = msi_reg_get_val_str( hkey, qualifier );
5313 sz = strlenW( advertise ) + 1;
5316 for (p = existing; *p; p += len)
5318 len = strlenW( p ) + 1;
5319 if (strcmpW( advertise, p )) sz += len;
5322 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5324 rc = ERROR_OUTOFMEMORY;
5330 for (p = existing; *p; p += len)
5332 len = strlenW( p ) + 1;
5333 if (strcmpW( advertise, p ))
5335 memcpy( q, p, len * sizeof(WCHAR) );
5340 strcpyW( q, advertise );
5341 q[strlenW( q ) + 1] = 0;
5343 msi_reg_set_val_multi_str( hkey, qualifier, output );
5348 msi_free( advertise );
5349 msi_free( existing );
5352 uirow = MSI_CreateRecord( 2 );
5353 MSI_RecordSetStringW( uirow, 1, compgroupid );
5354 MSI_RecordSetStringW( uirow, 2, qualifier);
5355 msi_ui_actiondata( package, szPublishComponents, uirow );
5356 msiobj_release( &uirow->hdr );
5357 /* FIXME: call ui_progress? */
5363 * At present I am ignorning the advertised components part of this and only
5364 * focusing on the qualified component sets
5366 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5368 static const WCHAR query[] = {
5369 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5370 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5374 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5375 if (rc != ERROR_SUCCESS)
5376 return ERROR_SUCCESS;
5378 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5379 msiobj_release(&view->hdr);
5383 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5385 static const WCHAR szInstallerComponents[] = {
5386 'S','o','f','t','w','a','r','e','\\',
5387 'M','i','c','r','o','s','o','f','t','\\',
5388 'I','n','s','t','a','l','l','e','r','\\',
5389 'C','o','m','p','o','n','e','n','t','s','\\',0};
5391 MSIPACKAGE *package = param;
5392 LPCWSTR compgroupid, component, feature, qualifier;
5396 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5399 feature = MSI_RecordGetString( rec, 5 );
5400 feat = msi_get_loaded_feature( package, feature );
5402 return ERROR_SUCCESS;
5404 feat->Action = msi_get_feature_action( package, feat );
5405 if (feat->Action != INSTALLSTATE_ABSENT)
5407 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5408 return ERROR_SUCCESS;
5411 component = MSI_RecordGetString( rec, 3 );
5412 comp = msi_get_loaded_component( package, component );
5414 return ERROR_SUCCESS;
5416 compgroupid = MSI_RecordGetString( rec, 1 );
5417 qualifier = MSI_RecordGetString( rec, 2 );
5419 squash_guid( compgroupid, squashed );
5420 strcpyW( keypath, szInstallerComponents );
5421 strcatW( keypath, squashed );
5423 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5424 if (res != ERROR_SUCCESS)
5426 WARN("Unable to delete component key %d\n", res);
5429 uirow = MSI_CreateRecord( 2 );
5430 MSI_RecordSetStringW( uirow, 1, compgroupid );
5431 MSI_RecordSetStringW( uirow, 2, qualifier );
5432 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5433 msiobj_release( &uirow->hdr );
5435 return ERROR_SUCCESS;
5438 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5440 static const WCHAR query[] = {
5441 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5442 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5446 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5447 if (rc != ERROR_SUCCESS)
5448 return ERROR_SUCCESS;
5450 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5451 msiobj_release( &view->hdr );
5455 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5457 static const WCHAR query[] =
5458 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5459 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5460 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5461 MSIPACKAGE *package = param;
5462 MSICOMPONENT *component;
5465 SC_HANDLE hscm = NULL, service = NULL;
5467 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5468 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5469 DWORD serv_type, start_type, err_control;
5470 SERVICE_DESCRIPTIONW sd = {NULL};
5472 comp = MSI_RecordGetString( rec, 12 );
5473 component = msi_get_loaded_component( package, comp );
5476 WARN("service component not found\n");
5479 component->Action = msi_get_component_action( package, component );
5480 if (component->Action != INSTALLSTATE_LOCAL)
5482 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5485 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5488 ERR("Failed to open the SC Manager!\n");
5492 start_type = MSI_RecordGetInteger(rec, 5);
5493 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5496 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5497 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5498 serv_type = MSI_RecordGetInteger(rec, 4);
5499 err_control = MSI_RecordGetInteger(rec, 6);
5500 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5501 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5502 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5503 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5504 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5505 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5507 /* fetch the service path */
5508 row = MSI_QueryGetRecord(package->db, query, comp);
5511 ERR("Query failed\n");
5514 key = MSI_RecordGetString(row, 6);
5515 file = msi_get_loaded_file(package, key);
5516 msiobj_release(&row->hdr);
5519 ERR("Failed to load the service file\n");
5523 if (!args || !args[0]) image_path = file->TargetPath;
5526 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5527 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5528 return ERROR_OUTOFMEMORY;
5530 strcpyW(image_path, file->TargetPath);
5531 strcatW(image_path, szSpace);
5532 strcatW(image_path, args);
5534 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5535 start_type, err_control, image_path, load_order,
5536 NULL, depends, serv_name, pass);
5540 if (GetLastError() != ERROR_SERVICE_EXISTS)
5541 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5543 else if (sd.lpDescription)
5545 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5546 WARN("failed to set service description %u\n", GetLastError());
5549 if (image_path != file->TargetPath) msi_free(image_path);
5551 CloseServiceHandle(service);
5552 CloseServiceHandle(hscm);
5555 msi_free(sd.lpDescription);
5556 msi_free(load_order);
5557 msi_free(serv_name);
5562 return ERROR_SUCCESS;
5565 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5567 static const WCHAR query[] = {
5568 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5569 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5573 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5574 if (rc != ERROR_SUCCESS)
5575 return ERROR_SUCCESS;
5577 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5578 msiobj_release(&view->hdr);
5582 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5583 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5585 LPCWSTR *vector, *temp_vector;
5589 static const WCHAR separator[] = {'[','~',']',0};
5592 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5597 vector = msi_alloc(sizeof(LPWSTR));
5605 vector[*numargs - 1] = p;
5607 if ((q = strstrW(p, separator)))
5611 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5617 vector = temp_vector;
5626 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5628 MSIPACKAGE *package = param;
5631 SC_HANDLE scm = NULL, service = NULL;
5632 LPCWSTR component, *vector = NULL;
5633 LPWSTR name, args, display_name = NULL;
5634 DWORD event, numargs, len, wait, dummy;
5635 UINT r = ERROR_FUNCTION_FAILED;
5636 SERVICE_STATUS_PROCESS status;
5637 ULONGLONG start_time;
5639 component = MSI_RecordGetString(rec, 6);
5640 comp = msi_get_loaded_component(package, component);
5642 return ERROR_SUCCESS;
5644 comp->Action = msi_get_component_action( package, comp );
5645 if (comp->Action != INSTALLSTATE_LOCAL)
5647 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5648 return ERROR_SUCCESS;
5651 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5652 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5653 event = MSI_RecordGetInteger(rec, 3);
5654 wait = MSI_RecordGetInteger(rec, 5);
5656 if (!(event & msidbServiceControlEventStart))
5662 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5665 ERR("Failed to open the service control manager\n");
5670 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5671 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5673 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5674 GetServiceDisplayNameW( scm, name, display_name, &len );
5677 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5680 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5684 vector = msi_service_args_to_vector(args, &numargs);
5686 if (!StartServiceW(service, numargs, vector) &&
5687 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5689 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5696 /* wait for at most 30 seconds for the service to be up and running */
5697 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5698 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5700 TRACE("failed to query service status (%u)\n", GetLastError());
5703 start_time = GetTickCount64();
5704 while (status.dwCurrentState == SERVICE_START_PENDING)
5706 if (GetTickCount64() - start_time > 30000) break;
5708 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5709 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5711 TRACE("failed to query service status (%u)\n", GetLastError());
5715 if (status.dwCurrentState != SERVICE_RUNNING)
5717 WARN("service failed to start %u\n", status.dwCurrentState);
5718 r = ERROR_FUNCTION_FAILED;
5723 uirow = MSI_CreateRecord( 2 );
5724 MSI_RecordSetStringW( uirow, 1, display_name );
5725 MSI_RecordSetStringW( uirow, 2, name );
5726 msi_ui_actiondata( package, szStartServices, uirow );
5727 msiobj_release( &uirow->hdr );
5729 CloseServiceHandle(service);
5730 CloseServiceHandle(scm);
5735 msi_free(display_name);
5739 static UINT ACTION_StartServices( MSIPACKAGE *package )
5741 static const WCHAR query[] = {
5742 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5743 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5747 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5748 if (rc != ERROR_SUCCESS)
5749 return ERROR_SUCCESS;
5751 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5752 msiobj_release(&view->hdr);
5756 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5758 DWORD i, needed, count;
5759 ENUM_SERVICE_STATUSW *dependencies;
5763 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5764 0, &needed, &count))
5767 if (GetLastError() != ERROR_MORE_DATA)
5770 dependencies = msi_alloc(needed);
5774 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5775 needed, &needed, &count))
5778 for (i = 0; i < count; i++)
5780 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5781 SERVICE_STOP | SERVICE_QUERY_STATUS);
5785 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5792 msi_free(dependencies);
5796 static UINT stop_service( LPCWSTR name )
5798 SC_HANDLE scm = NULL, service = NULL;
5799 SERVICE_STATUS status;
5800 SERVICE_STATUS_PROCESS ssp;
5803 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5806 WARN("Failed to open the SCM: %d\n", GetLastError());
5810 service = OpenServiceW(scm, name,
5812 SERVICE_QUERY_STATUS |
5813 SERVICE_ENUMERATE_DEPENDENTS);
5816 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5820 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5821 sizeof(SERVICE_STATUS_PROCESS), &needed))
5823 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5827 if (ssp.dwCurrentState == SERVICE_STOPPED)
5830 stop_service_dependents(scm, service);
5832 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5833 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5836 CloseServiceHandle(service);
5837 CloseServiceHandle(scm);
5839 return ERROR_SUCCESS;
5842 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5844 MSIPACKAGE *package = param;
5848 LPWSTR name = NULL, display_name = NULL;
5852 event = MSI_RecordGetInteger( rec, 3 );
5853 if (!(event & msidbServiceControlEventStop))
5854 return ERROR_SUCCESS;
5856 component = MSI_RecordGetString( rec, 6 );
5857 comp = msi_get_loaded_component( package, component );
5859 return ERROR_SUCCESS;
5861 comp->Action = msi_get_component_action( package, comp );
5862 if (comp->Action != INSTALLSTATE_ABSENT)
5864 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5865 return ERROR_SUCCESS;
5868 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5871 ERR("Failed to open the service control manager\n");
5876 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5877 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5879 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5880 GetServiceDisplayNameW( scm, name, display_name, &len );
5882 CloseServiceHandle( scm );
5884 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5885 stop_service( name );
5888 uirow = MSI_CreateRecord( 2 );
5889 MSI_RecordSetStringW( uirow, 1, display_name );
5890 MSI_RecordSetStringW( uirow, 2, name );
5891 msi_ui_actiondata( package, szStopServices, uirow );
5892 msiobj_release( &uirow->hdr );
5895 msi_free( display_name );
5896 return ERROR_SUCCESS;
5899 static UINT ACTION_StopServices( MSIPACKAGE *package )
5901 static const WCHAR query[] = {
5902 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5903 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5907 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5908 if (rc != ERROR_SUCCESS)
5909 return ERROR_SUCCESS;
5911 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5912 msiobj_release(&view->hdr);
5916 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5918 MSIPACKAGE *package = param;
5921 LPWSTR name = NULL, display_name = NULL;
5923 SC_HANDLE scm = NULL, service = NULL;
5925 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5927 return ERROR_SUCCESS;
5929 event = MSI_RecordGetInteger( rec, 3 );
5930 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5932 comp->Action = msi_get_component_action( package, comp );
5933 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5934 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5936 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5938 return ERROR_SUCCESS;
5940 stop_service( name );
5942 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5945 WARN("Failed to open the SCM: %d\n", GetLastError());
5950 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5951 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5953 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5954 GetServiceDisplayNameW( scm, name, display_name, &len );
5957 service = OpenServiceW( scm, name, DELETE );
5960 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5964 if (!DeleteService( service ))
5965 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5968 uirow = MSI_CreateRecord( 2 );
5969 MSI_RecordSetStringW( uirow, 1, display_name );
5970 MSI_RecordSetStringW( uirow, 2, name );
5971 msi_ui_actiondata( package, szDeleteServices, uirow );
5972 msiobj_release( &uirow->hdr );
5974 CloseServiceHandle( service );
5975 CloseServiceHandle( scm );
5977 msi_free( display_name );
5979 return ERROR_SUCCESS;
5982 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5984 static const WCHAR query[] = {
5985 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5986 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5990 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5991 if (rc != ERROR_SUCCESS)
5992 return ERROR_SUCCESS;
5994 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5995 msiobj_release( &view->hdr );
5999 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6001 MSIPACKAGE *package = param;
6002 LPWSTR driver, driver_path, ptr;
6003 WCHAR outpath[MAX_PATH];
6004 MSIFILE *driver_file = NULL, *setup_file = NULL;
6007 LPCWSTR desc, file_key, component;
6009 UINT r = ERROR_SUCCESS;
6011 static const WCHAR driver_fmt[] = {
6012 'D','r','i','v','e','r','=','%','s',0};
6013 static const WCHAR setup_fmt[] = {
6014 'S','e','t','u','p','=','%','s',0};
6015 static const WCHAR usage_fmt[] = {
6016 'F','i','l','e','U','s','a','g','e','=','1',0};
6018 component = MSI_RecordGetString( rec, 2 );
6019 comp = msi_get_loaded_component( package, component );
6021 return ERROR_SUCCESS;
6023 comp->Action = msi_get_component_action( package, comp );
6024 if (comp->Action != INSTALLSTATE_LOCAL)
6026 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6027 return ERROR_SUCCESS;
6029 desc = MSI_RecordGetString(rec, 3);
6031 file_key = MSI_RecordGetString( rec, 4 );
6032 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6034 file_key = MSI_RecordGetString( rec, 5 );
6035 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6039 ERR("ODBC Driver entry not found!\n");
6040 return ERROR_FUNCTION_FAILED;
6043 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6045 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6046 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6048 driver = msi_alloc(len * sizeof(WCHAR));
6050 return ERROR_OUTOFMEMORY;
6053 lstrcpyW(ptr, desc);
6054 ptr += lstrlenW(ptr) + 1;
6056 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6061 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6065 lstrcpyW(ptr, usage_fmt);
6066 ptr += lstrlenW(ptr) + 1;
6069 driver_path = strdupW(driver_file->TargetPath);
6070 ptr = strrchrW(driver_path, '\\');
6071 if (ptr) *ptr = '\0';
6073 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6074 NULL, ODBC_INSTALL_COMPLETE, &usage))
6076 ERR("Failed to install SQL driver!\n");
6077 r = ERROR_FUNCTION_FAILED;
6080 uirow = MSI_CreateRecord( 5 );
6081 MSI_RecordSetStringW( uirow, 1, desc );
6082 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6083 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6084 msi_ui_actiondata( package, szInstallODBC, uirow );
6085 msiobj_release( &uirow->hdr );
6088 msi_free(driver_path);
6093 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6095 MSIPACKAGE *package = param;
6096 LPWSTR translator, translator_path, ptr;
6097 WCHAR outpath[MAX_PATH];
6098 MSIFILE *translator_file = NULL, *setup_file = NULL;
6101 LPCWSTR desc, file_key, component;
6103 UINT r = ERROR_SUCCESS;
6105 static const WCHAR translator_fmt[] = {
6106 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6107 static const WCHAR setup_fmt[] = {
6108 'S','e','t','u','p','=','%','s',0};
6110 component = MSI_RecordGetString( rec, 2 );
6111 comp = msi_get_loaded_component( package, component );
6113 return ERROR_SUCCESS;
6115 comp->Action = msi_get_component_action( package, comp );
6116 if (comp->Action != INSTALLSTATE_LOCAL)
6118 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6119 return ERROR_SUCCESS;
6121 desc = MSI_RecordGetString(rec, 3);
6123 file_key = MSI_RecordGetString( rec, 4 );
6124 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6126 file_key = MSI_RecordGetString( rec, 5 );
6127 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6129 if (!translator_file)
6131 ERR("ODBC Translator entry not found!\n");
6132 return ERROR_FUNCTION_FAILED;
6135 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6137 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6139 translator = msi_alloc(len * sizeof(WCHAR));
6141 return ERROR_OUTOFMEMORY;
6144 lstrcpyW(ptr, desc);
6145 ptr += lstrlenW(ptr) + 1;
6147 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6152 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6157 translator_path = strdupW(translator_file->TargetPath);
6158 ptr = strrchrW(translator_path, '\\');
6159 if (ptr) *ptr = '\0';
6161 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6162 NULL, ODBC_INSTALL_COMPLETE, &usage))
6164 ERR("Failed to install SQL translator!\n");
6165 r = ERROR_FUNCTION_FAILED;
6168 uirow = MSI_CreateRecord( 5 );
6169 MSI_RecordSetStringW( uirow, 1, desc );
6170 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6171 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6172 msi_ui_actiondata( package, szInstallODBC, uirow );
6173 msiobj_release( &uirow->hdr );
6175 msi_free(translator);
6176 msi_free(translator_path);
6181 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6183 MSIPACKAGE *package = param;
6186 LPCWSTR desc, driver, component;
6187 WORD request = ODBC_ADD_SYS_DSN;
6190 UINT r = ERROR_SUCCESS;
6193 static const WCHAR attrs_fmt[] = {
6194 'D','S','N','=','%','s',0 };
6196 component = MSI_RecordGetString( rec, 2 );
6197 comp = msi_get_loaded_component( package, component );
6199 return ERROR_SUCCESS;
6201 comp->Action = msi_get_component_action( package, comp );
6202 if (comp->Action != INSTALLSTATE_LOCAL)
6204 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6205 return ERROR_SUCCESS;
6208 desc = MSI_RecordGetString(rec, 3);
6209 driver = MSI_RecordGetString(rec, 4);
6210 registration = MSI_RecordGetInteger(rec, 5);
6212 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6213 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6215 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6216 attrs = msi_alloc(len * sizeof(WCHAR));
6218 return ERROR_OUTOFMEMORY;
6220 len = sprintfW(attrs, attrs_fmt, desc);
6223 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6225 ERR("Failed to install SQL data source!\n");
6226 r = ERROR_FUNCTION_FAILED;
6229 uirow = MSI_CreateRecord( 5 );
6230 MSI_RecordSetStringW( uirow, 1, desc );
6231 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6232 MSI_RecordSetInteger( uirow, 3, request );
6233 msi_ui_actiondata( package, szInstallODBC, uirow );
6234 msiobj_release( &uirow->hdr );
6241 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6243 static const WCHAR driver_query[] = {
6244 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6245 'O','D','B','C','D','r','i','v','e','r',0};
6246 static const WCHAR translator_query[] = {
6247 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6248 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6249 static const WCHAR source_query[] = {
6250 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6251 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6255 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6256 if (rc == ERROR_SUCCESS)
6258 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6259 msiobj_release(&view->hdr);
6260 if (rc != ERROR_SUCCESS)
6263 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6264 if (rc == ERROR_SUCCESS)
6266 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6267 msiobj_release(&view->hdr);
6268 if (rc != ERROR_SUCCESS)
6271 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6272 if (rc == ERROR_SUCCESS)
6274 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6275 msiobj_release(&view->hdr);
6276 if (rc != ERROR_SUCCESS)
6279 return ERROR_SUCCESS;
6282 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6284 MSIPACKAGE *package = param;
6288 LPCWSTR desc, component;
6290 component = MSI_RecordGetString( rec, 2 );
6291 comp = msi_get_loaded_component( package, component );
6293 return ERROR_SUCCESS;
6295 comp->Action = msi_get_component_action( package, comp );
6296 if (comp->Action != INSTALLSTATE_ABSENT)
6298 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6299 return ERROR_SUCCESS;
6302 desc = MSI_RecordGetString( rec, 3 );
6303 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6305 WARN("Failed to remove ODBC driver\n");
6309 FIXME("Usage count reached 0\n");
6312 uirow = MSI_CreateRecord( 2 );
6313 MSI_RecordSetStringW( uirow, 1, desc );
6314 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6315 msi_ui_actiondata( package, szRemoveODBC, uirow );
6316 msiobj_release( &uirow->hdr );
6318 return ERROR_SUCCESS;
6321 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6323 MSIPACKAGE *package = param;
6327 LPCWSTR desc, component;
6329 component = MSI_RecordGetString( rec, 2 );
6330 comp = msi_get_loaded_component( package, component );
6332 return ERROR_SUCCESS;
6334 comp->Action = msi_get_component_action( package, comp );
6335 if (comp->Action != INSTALLSTATE_ABSENT)
6337 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6338 return ERROR_SUCCESS;
6341 desc = MSI_RecordGetString( rec, 3 );
6342 if (!SQLRemoveTranslatorW( desc, &usage ))
6344 WARN("Failed to remove ODBC translator\n");
6348 FIXME("Usage count reached 0\n");
6351 uirow = MSI_CreateRecord( 2 );
6352 MSI_RecordSetStringW( uirow, 1, desc );
6353 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6354 msi_ui_actiondata( package, szRemoveODBC, uirow );
6355 msiobj_release( &uirow->hdr );
6357 return ERROR_SUCCESS;
6360 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6362 MSIPACKAGE *package = param;
6366 LPCWSTR desc, driver, component;
6367 WORD request = ODBC_REMOVE_SYS_DSN;
6371 static const WCHAR attrs_fmt[] = {
6372 'D','S','N','=','%','s',0 };
6374 component = MSI_RecordGetString( rec, 2 );
6375 comp = msi_get_loaded_component( package, component );
6377 return ERROR_SUCCESS;
6379 comp->Action = msi_get_component_action( package, comp );
6380 if (comp->Action != INSTALLSTATE_ABSENT)
6382 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6383 return ERROR_SUCCESS;
6386 desc = MSI_RecordGetString( rec, 3 );
6387 driver = MSI_RecordGetString( rec, 4 );
6388 registration = MSI_RecordGetInteger( rec, 5 );
6390 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6391 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6393 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6394 attrs = msi_alloc( len * sizeof(WCHAR) );
6396 return ERROR_OUTOFMEMORY;
6398 FIXME("Use ODBCSourceAttribute table\n");
6400 len = sprintfW( attrs, attrs_fmt, desc );
6403 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6405 WARN("Failed to remove ODBC data source\n");
6409 uirow = MSI_CreateRecord( 3 );
6410 MSI_RecordSetStringW( uirow, 1, desc );
6411 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6412 MSI_RecordSetInteger( uirow, 3, request );
6413 msi_ui_actiondata( package, szRemoveODBC, uirow );
6414 msiobj_release( &uirow->hdr );
6416 return ERROR_SUCCESS;
6419 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6421 static const WCHAR driver_query[] = {
6422 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6423 'O','D','B','C','D','r','i','v','e','r',0};
6424 static const WCHAR translator_query[] = {
6425 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6426 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6427 static const WCHAR source_query[] = {
6428 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6429 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6433 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6434 if (rc == ERROR_SUCCESS)
6436 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6437 msiobj_release( &view->hdr );
6438 if (rc != ERROR_SUCCESS)
6441 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6442 if (rc == ERROR_SUCCESS)
6444 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6445 msiobj_release( &view->hdr );
6446 if (rc != ERROR_SUCCESS)
6449 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6450 if (rc == ERROR_SUCCESS)
6452 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6453 msiobj_release( &view->hdr );
6454 if (rc != ERROR_SUCCESS)
6457 return ERROR_SUCCESS;
6460 #define ENV_ACT_SETALWAYS 0x1
6461 #define ENV_ACT_SETABSENT 0x2
6462 #define ENV_ACT_REMOVE 0x4
6463 #define ENV_ACT_REMOVEMATCH 0x8
6465 #define ENV_MOD_MACHINE 0x20000000
6466 #define ENV_MOD_APPEND 0x40000000
6467 #define ENV_MOD_PREFIX 0x80000000
6468 #define ENV_MOD_MASK 0xC0000000
6470 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6472 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6474 LPCWSTR cptr = *name;
6476 static const WCHAR prefix[] = {'[','~',']',0};
6477 static const int prefix_len = 3;
6483 *flags |= ENV_ACT_SETALWAYS;
6484 else if (*cptr == '+')
6485 *flags |= ENV_ACT_SETABSENT;
6486 else if (*cptr == '-')
6487 *flags |= ENV_ACT_REMOVE;
6488 else if (*cptr == '!')
6489 *flags |= ENV_ACT_REMOVEMATCH;
6490 else if (*cptr == '*')
6491 *flags |= ENV_MOD_MACHINE;
6501 ERR("Missing environment variable\n");
6502 return ERROR_FUNCTION_FAILED;
6507 LPCWSTR ptr = *value;
6508 if (!strncmpW(ptr, prefix, prefix_len))
6510 if (ptr[prefix_len] == szSemiColon[0])
6512 *flags |= ENV_MOD_APPEND;
6513 *value += lstrlenW(prefix);
6520 else if (lstrlenW(*value) >= prefix_len)
6522 ptr += lstrlenW(ptr) - prefix_len;
6523 if (!strcmpW( ptr, prefix ))
6525 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6527 *flags |= ENV_MOD_PREFIX;
6528 /* the "[~]" will be removed by deformat_string */;
6538 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6539 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6540 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6541 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6543 ERR("Invalid flags: %08x\n", *flags);
6544 return ERROR_FUNCTION_FAILED;
6548 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6550 return ERROR_SUCCESS;
6553 static UINT open_env_key( DWORD flags, HKEY *key )
6555 static const WCHAR user_env[] =
6556 {'E','n','v','i','r','o','n','m','e','n','t',0};
6557 static const WCHAR machine_env[] =
6558 {'S','y','s','t','e','m','\\',
6559 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6560 'C','o','n','t','r','o','l','\\',
6561 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6562 'E','n','v','i','r','o','n','m','e','n','t',0};
6567 if (flags & ENV_MOD_MACHINE)
6570 root = HKEY_LOCAL_MACHINE;
6575 root = HKEY_CURRENT_USER;
6578 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6579 if (res != ERROR_SUCCESS)
6581 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6582 return ERROR_FUNCTION_FAILED;
6585 return ERROR_SUCCESS;
6588 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6590 MSIPACKAGE *package = param;
6591 LPCWSTR name, value, component;
6592 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6593 DWORD flags, type, size;
6600 component = MSI_RecordGetString(rec, 4);
6601 comp = msi_get_loaded_component(package, component);
6603 return ERROR_SUCCESS;
6605 comp->Action = msi_get_component_action( package, comp );
6606 if (comp->Action != INSTALLSTATE_LOCAL)
6608 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6609 return ERROR_SUCCESS;
6611 name = MSI_RecordGetString(rec, 2);
6612 value = MSI_RecordGetString(rec, 3);
6614 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6616 res = env_parse_flags(&name, &value, &flags);
6617 if (res != ERROR_SUCCESS || !value)
6620 if (value && !deformat_string(package, value, &deformatted))
6622 res = ERROR_OUTOFMEMORY;
6626 value = deformatted;
6628 res = open_env_key( flags, &env );
6629 if (res != ERROR_SUCCESS)
6632 if (flags & ENV_MOD_MACHINE)
6633 action |= 0x20000000;
6637 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6638 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6639 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6642 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6646 /* Nothing to do. */
6649 res = ERROR_SUCCESS;
6653 /* If we are appending but the string was empty, strip ; */
6654 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6656 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6657 newval = strdupW(value);
6660 res = ERROR_OUTOFMEMORY;
6668 /* Contrary to MSDN, +-variable to [~];path works */
6669 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6671 res = ERROR_SUCCESS;
6675 data = msi_alloc(size);
6679 return ERROR_OUTOFMEMORY;
6682 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6683 if (res != ERROR_SUCCESS)
6686 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6689 res = RegDeleteValueW(env, name);
6690 if (res != ERROR_SUCCESS)
6691 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6695 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6696 if (flags & ENV_MOD_MASK)
6700 if (flags & ENV_MOD_APPEND) multiplier++;
6701 if (flags & ENV_MOD_PREFIX) multiplier++;
6702 mod_size = lstrlenW(value) * multiplier;
6703 size += mod_size * sizeof(WCHAR);
6706 newval = msi_alloc(size);
6710 res = ERROR_OUTOFMEMORY;
6714 if (flags & ENV_MOD_PREFIX)
6716 lstrcpyW(newval, value);
6717 ptr = newval + lstrlenW(value);
6718 action |= 0x80000000;
6721 lstrcpyW(ptr, data);
6723 if (flags & ENV_MOD_APPEND)
6725 lstrcatW(newval, value);
6726 action |= 0x40000000;
6729 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6730 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6733 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6737 uirow = MSI_CreateRecord( 3 );
6738 MSI_RecordSetStringW( uirow, 1, name );
6739 MSI_RecordSetStringW( uirow, 2, newval );
6740 MSI_RecordSetInteger( uirow, 3, action );
6741 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6742 msiobj_release( &uirow->hdr );
6744 if (env) RegCloseKey(env);
6745 msi_free(deformatted);
6751 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6753 static const WCHAR query[] = {
6754 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6755 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6759 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6760 if (rc != ERROR_SUCCESS)
6761 return ERROR_SUCCESS;
6763 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6764 msiobj_release(&view->hdr);
6768 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6770 MSIPACKAGE *package = param;
6771 LPCWSTR name, value, component;
6772 LPWSTR deformatted = NULL;
6781 component = MSI_RecordGetString( rec, 4 );
6782 comp = msi_get_loaded_component( package, component );
6784 return ERROR_SUCCESS;
6786 comp->Action = msi_get_component_action( package, comp );
6787 if (comp->Action != INSTALLSTATE_ABSENT)
6789 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6790 return ERROR_SUCCESS;
6792 name = MSI_RecordGetString( rec, 2 );
6793 value = MSI_RecordGetString( rec, 3 );
6795 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6797 r = env_parse_flags( &name, &value, &flags );
6798 if (r != ERROR_SUCCESS)
6801 if (!(flags & ENV_ACT_REMOVE))
6803 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6804 return ERROR_SUCCESS;
6807 if (value && !deformat_string( package, value, &deformatted ))
6808 return ERROR_OUTOFMEMORY;
6810 value = deformatted;
6812 r = open_env_key( flags, &env );
6813 if (r != ERROR_SUCCESS)
6819 if (flags & ENV_MOD_MACHINE)
6820 action |= 0x20000000;
6822 TRACE("Removing %s\n", debugstr_w(name));
6824 res = RegDeleteValueW( env, name );
6825 if (res != ERROR_SUCCESS)
6827 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6832 uirow = MSI_CreateRecord( 3 );
6833 MSI_RecordSetStringW( uirow, 1, name );
6834 MSI_RecordSetStringW( uirow, 2, value );
6835 MSI_RecordSetInteger( uirow, 3, action );
6836 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6837 msiobj_release( &uirow->hdr );
6839 if (env) RegCloseKey( env );
6840 msi_free( deformatted );
6844 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6846 static const WCHAR query[] = {
6847 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6848 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6852 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6853 if (rc != ERROR_SUCCESS)
6854 return ERROR_SUCCESS;
6856 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6857 msiobj_release( &view->hdr );
6861 UINT msi_validate_product_id( MSIPACKAGE *package )
6863 LPWSTR key, template, id;
6864 UINT r = ERROR_SUCCESS;
6866 id = msi_dup_property( package->db, szProductID );
6870 return ERROR_SUCCESS;
6872 template = msi_dup_property( package->db, szPIDTemplate );
6873 key = msi_dup_property( package->db, szPIDKEY );
6874 if (key && template)
6876 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6877 r = msi_set_property( package->db, szProductID, key );
6879 msi_free( template );
6884 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6886 return msi_validate_product_id( package );
6889 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6892 package->need_reboot_at_end = 1;
6893 return ERROR_SUCCESS;
6896 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6898 static const WCHAR szAvailableFreeReg[] =
6899 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6901 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6903 TRACE("%p %d kilobytes\n", package, space);
6905 uirow = MSI_CreateRecord( 1 );
6906 MSI_RecordSetInteger( uirow, 1, space );
6907 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6908 msiobj_release( &uirow->hdr );
6910 return ERROR_SUCCESS;
6913 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6915 TRACE("%p\n", package);
6917 msi_set_property( package->db, szRollbackDisabled, szOne );
6918 return ERROR_SUCCESS;
6921 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6923 FIXME("%p\n", package);
6924 return ERROR_SUCCESS;
6927 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6929 static const WCHAR driver_query[] = {
6930 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6931 'O','D','B','C','D','r','i','v','e','r',0};
6932 static const WCHAR translator_query[] = {
6933 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6934 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6938 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6939 if (r == ERROR_SUCCESS)
6942 r = MSI_IterateRecords( view, &count, NULL, package );
6943 msiobj_release( &view->hdr );
6944 if (r != ERROR_SUCCESS)
6946 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6948 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6949 if (r == ERROR_SUCCESS)
6952 r = MSI_IterateRecords( view, &count, NULL, package );
6953 msiobj_release( &view->hdr );
6954 if (r != ERROR_SUCCESS)
6956 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6958 return ERROR_SUCCESS;
6961 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6963 MSIPACKAGE *package = param;
6964 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6967 if ((value = msi_dup_property( package->db, property )))
6969 FIXME("remove %s\n", debugstr_w(value));
6972 return ERROR_SUCCESS;
6975 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6977 static const WCHAR query[] = {
6978 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6979 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6983 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6984 if (r == ERROR_SUCCESS)
6986 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6987 msiobj_release( &view->hdr );
6988 if (r != ERROR_SUCCESS)
6991 return ERROR_SUCCESS;
6994 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6996 MSIPACKAGE *package = param;
6997 int attributes = MSI_RecordGetInteger( rec, 5 );
6999 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7001 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7002 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7003 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7004 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7008 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7010 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7011 if (r != ERROR_SUCCESS)
7012 return ERROR_SUCCESS;
7016 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7017 if (r != ERROR_SUCCESS)
7018 return ERROR_SUCCESS;
7020 RegCloseKey( hkey );
7022 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7023 debugstr_w(upgrade_code), debugstr_w(version_min),
7024 debugstr_w(version_max), debugstr_w(language));
7026 return ERROR_SUCCESS;
7029 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7031 static const WCHAR query[] = {
7032 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7033 'U','p','g','r','a','d','e',0};
7037 if (msi_get_property_int( package->db, szInstalled, 0 ))
7039 TRACE("product is installed, skipping action\n");
7040 return ERROR_SUCCESS;
7042 if (msi_get_property_int( package->db, szPreselected, 0 ))
7044 TRACE("Preselected property is set, not migrating feature states\n");
7045 return ERROR_SUCCESS;
7047 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7048 if (r == ERROR_SUCCESS)
7050 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7051 msiobj_release( &view->hdr );
7052 if (r != ERROR_SUCCESS)
7055 return ERROR_SUCCESS;
7058 static void bind_image( const char *filename, const char *path )
7060 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7062 WARN("failed to bind image %u\n", GetLastError());
7066 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7070 MSIPACKAGE *package = param;
7071 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7072 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7073 char *filenameA, *pathA;
7074 WCHAR *pathW, **path_list;
7076 if (!(file = msi_get_loaded_file( package, key )))
7078 WARN("file %s not found\n", debugstr_w(key));
7079 return ERROR_SUCCESS;
7081 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7082 path_list = msi_split_string( paths, ';' );
7083 if (!path_list) bind_image( filenameA, NULL );
7086 for (i = 0; path_list[i] && path_list[i][0]; i++)
7088 deformat_string( package, path_list[i], &pathW );
7089 if ((pathA = strdupWtoA( pathW )))
7091 bind_image( filenameA, pathA );
7097 msi_free( path_list );
7098 msi_free( filenameA );
7099 return ERROR_SUCCESS;
7102 static UINT ACTION_BindImage( MSIPACKAGE *package )
7104 static const WCHAR query[] = {
7105 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7106 'B','i','n','d','I','m','a','g','e',0};
7110 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7111 if (r == ERROR_SUCCESS)
7113 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7114 msiobj_release( &view->hdr );
7115 if (r != ERROR_SUCCESS)
7118 return ERROR_SUCCESS;
7121 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7123 static const WCHAR query[] = {
7124 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7129 r = MSI_OpenQuery( package->db, &view, query, table );
7130 if (r == ERROR_SUCCESS)
7132 r = MSI_IterateRecords(view, &count, NULL, package);
7133 msiobj_release(&view->hdr);
7134 if (r != ERROR_SUCCESS)
7137 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7138 return ERROR_SUCCESS;
7141 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7143 static const WCHAR table[] = {
7144 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7145 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7148 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7150 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7151 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7154 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7156 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7157 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7160 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7162 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7163 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7166 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7168 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7169 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7174 const WCHAR *action;
7175 UINT (*handler)(MSIPACKAGE *);
7176 const WCHAR *action_rollback;
7180 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7181 { szAppSearch, ACTION_AppSearch, NULL },
7182 { szBindImage, ACTION_BindImage, NULL },
7183 { szCCPSearch, ACTION_CCPSearch, NULL },
7184 { szCostFinalize, ACTION_CostFinalize, NULL },
7185 { szCostInitialize, ACTION_CostInitialize, NULL },
7186 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7187 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7188 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7189 { szDisableRollback, ACTION_DisableRollback, NULL },
7190 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7191 { szExecuteAction, ACTION_ExecuteAction, NULL },
7192 { szFileCost, ACTION_FileCost, NULL },
7193 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7194 { szForceReboot, ACTION_ForceReboot, NULL },
7195 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7196 { szInstallExecute, ACTION_InstallExecute, NULL },
7197 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7198 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7199 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7200 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7201 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7202 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7203 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7204 { szInstallValidate, ACTION_InstallValidate, NULL },
7205 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7206 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7207 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7208 { szMoveFiles, ACTION_MoveFiles, NULL },
7209 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7210 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7211 { szPatchFiles, ACTION_PatchFiles, NULL },
7212 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7213 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7214 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7215 { szPublishProduct, ACTION_PublishProduct, NULL },
7216 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7217 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7218 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7219 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7220 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7221 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7222 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7223 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7224 { szRegisterUser, ACTION_RegisterUser, NULL },
7225 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7226 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7227 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7228 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7229 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7230 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7231 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7232 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7233 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7234 { szResolveSource, ACTION_ResolveSource, NULL },
7235 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7236 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7237 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7238 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7239 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7240 { szStartServices, ACTION_StartServices, szStopServices },
7241 { szStopServices, ACTION_StopServices, szStartServices },
7242 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7243 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7244 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7245 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7246 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7247 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7248 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7249 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7250 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7251 { szValidateProductID, ACTION_ValidateProductID, NULL },
7252 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7253 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7254 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7255 { NULL, NULL, NULL }
7258 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7264 while (StandardActions[i].action != NULL)
7266 if (!strcmpW( StandardActions[i].action, action ))
7268 ui_actionstart( package, action );
7269 if (StandardActions[i].handler)
7271 ui_actioninfo( package, action, TRUE, 0 );
7272 *rc = StandardActions[i].handler( package );
7273 ui_actioninfo( package, action, FALSE, *rc );
7275 if (StandardActions[i].action_rollback && !package->need_rollback)
7277 TRACE("scheduling rollback action\n");
7278 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7283 FIXME("unhandled standard action %s\n", debugstr_w(action));
7284 *rc = ERROR_SUCCESS;
7294 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7296 UINT rc = ERROR_SUCCESS;
7299 TRACE("Performing action (%s)\n", debugstr_w(action));
7301 handled = ACTION_HandleStandardAction(package, action, &rc);
7304 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7308 WARN("unhandled msi action %s\n", debugstr_w(action));
7309 rc = ERROR_FUNCTION_NOT_CALLED;
7315 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7317 UINT rc = ERROR_SUCCESS;
7318 BOOL handled = FALSE;
7320 TRACE("Performing action (%s)\n", debugstr_w(action));
7322 handled = ACTION_HandleStandardAction(package, action, &rc);
7325 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7327 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7332 WARN("unhandled msi action %s\n", debugstr_w(action));
7333 rc = ERROR_FUNCTION_NOT_CALLED;
7339 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7341 UINT rc = ERROR_SUCCESS;
7344 static const WCHAR query[] =
7345 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7346 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7347 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7348 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7349 static const WCHAR ui_query[] =
7350 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7351 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7352 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7353 ' ', '=',' ','%','i',0};
7355 if (needs_ui_sequence(package))
7356 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7358 row = MSI_QueryGetRecord(package->db, query, seq);
7362 LPCWSTR action, cond;
7364 TRACE("Running the actions\n");
7366 /* check conditions */
7367 cond = MSI_RecordGetString(row, 2);
7369 /* this is a hack to skip errors in the condition code */
7370 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7372 msiobj_release(&row->hdr);
7373 return ERROR_SUCCESS;
7376 action = MSI_RecordGetString(row, 1);
7379 ERR("failed to fetch action\n");
7380 msiobj_release(&row->hdr);
7381 return ERROR_FUNCTION_FAILED;
7384 if (needs_ui_sequence(package))
7385 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7387 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7389 msiobj_release(&row->hdr);
7395 /****************************************************
7396 * TOP level entry points
7397 *****************************************************/
7399 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7400 LPCWSTR szCommandLine )
7402 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7403 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7404 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7405 WCHAR *reinstall = NULL;
7409 msi_set_property( package->db, szAction, szInstall );
7411 package->script->InWhatSequence = SEQUENCE_INSTALL;
7418 dir = strdupW(szPackagePath);
7419 p = strrchrW(dir, '\\');
7423 file = szPackagePath + (p - dir);
7428 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7429 GetCurrentDirectoryW(MAX_PATH, dir);
7430 lstrcatW(dir, szBackSlash);
7431 file = szPackagePath;
7434 msi_free( package->PackagePath );
7435 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7436 if (!package->PackagePath)
7439 return ERROR_OUTOFMEMORY;
7442 lstrcpyW(package->PackagePath, dir);
7443 lstrcatW(package->PackagePath, file);
7446 msi_set_sourcedir_props(package, FALSE);
7449 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7450 if (rc != ERROR_SUCCESS)
7453 msi_apply_transforms( package );
7454 msi_apply_patches( package );
7456 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7458 TRACE("setting reinstall property\n");
7459 msi_set_property( package->db, szReinstall, szAll );
7462 /* properties may have been added by a transform */
7463 msi_clone_properties( package );
7465 msi_parse_command_line( package, szCommandLine, FALSE );
7466 msi_adjust_privilege_properties( package );
7467 msi_set_context( package );
7469 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7471 TRACE("disabling rollback\n");
7472 msi_set_property( package->db, szRollbackDisabled, szOne );
7475 if (needs_ui_sequence( package))
7477 package->script->InWhatSequence |= SEQUENCE_UI;
7478 rc = ACTION_ProcessUISequence(package);
7479 ui_exists = ui_sequence_exists(package);
7480 if (rc == ERROR_SUCCESS || !ui_exists)
7482 package->script->InWhatSequence |= SEQUENCE_EXEC;
7483 rc = ACTION_ProcessExecSequence(package, ui_exists);
7487 rc = ACTION_ProcessExecSequence(package, FALSE);
7489 package->script->CurrentlyScripting = FALSE;
7491 /* process the ending type action */
7492 if (rc == ERROR_SUCCESS)
7493 ACTION_PerformActionSequence(package, -1);
7494 else if (rc == ERROR_INSTALL_USEREXIT)
7495 ACTION_PerformActionSequence(package, -2);
7496 else if (rc == ERROR_INSTALL_SUSPEND)
7497 ACTION_PerformActionSequence(package, -4);
7500 ACTION_PerformActionSequence(package, -3);
7501 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7503 package->need_rollback = TRUE;
7507 /* finish up running custom actions */
7508 ACTION_FinishCustomActions(package);
7510 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7512 WARN("installation failed, running rollback script\n");
7513 execute_script( package, SCRIPT_ROLLBACK );
7515 msi_free( reinstall );
7517 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7518 return ERROR_SUCCESS_REBOOT_REQUIRED;