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"
39 #include "wine/unicode.h"
42 #define REG_PROGRESS_VALUE 13200
43 #define COMPONENT_PROGRESS_VALUE 24000
45 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 * consts and values used
50 static const WCHAR c_colon[] = {'C',':','\\',0};
52 static const WCHAR szCreateFolders[] =
53 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
54 static const WCHAR szCostFinalize[] =
55 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
56 static const WCHAR szWriteRegistryValues[] =
57 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
58 static const WCHAR szCostInitialize[] =
59 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
60 static const WCHAR szFileCost[] =
61 {'F','i','l','e','C','o','s','t',0};
62 static const WCHAR szInstallInitialize[] =
63 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
64 static const WCHAR szInstallValidate[] =
65 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
66 static const WCHAR szLaunchConditions[] =
67 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
68 static const WCHAR szProcessComponents[] =
69 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
70 static const WCHAR szRegisterTypeLibraries[] =
71 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
72 static const WCHAR szCreateShortcuts[] =
73 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
74 static const WCHAR szPublishProduct[] =
75 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
76 static const WCHAR szWriteIniValues[] =
77 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
78 static const WCHAR szSelfRegModules[] =
79 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
80 static const WCHAR szPublishFeatures[] =
81 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
82 static const WCHAR szRegisterProduct[] =
83 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
84 static const WCHAR szInstallExecute[] =
85 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
86 static const WCHAR szInstallExecuteAgain[] =
87 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
88 static const WCHAR szInstallFinalize[] =
89 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
90 static const WCHAR szForceReboot[] =
91 {'F','o','r','c','e','R','e','b','o','o','t',0};
92 static const WCHAR szResolveSource[] =
93 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
94 static const WCHAR szAllocateRegistrySpace[] =
95 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
96 static const WCHAR szBindImage[] =
97 {'B','i','n','d','I','m','a','g','e',0};
98 static const WCHAR szDeleteServices[] =
99 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
100 static const WCHAR szDisableRollback[] =
101 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
102 static const WCHAR szExecuteAction[] =
103 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
104 static const WCHAR szInstallAdminPackage[] =
105 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
106 static const WCHAR szInstallSFPCatalogFile[] =
107 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
108 static const WCHAR szIsolateComponents[] =
109 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
110 static const WCHAR szMigrateFeatureStates[] =
111 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
112 static const WCHAR szMsiUnpublishAssemblies[] =
113 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
114 static const WCHAR szInstallODBC[] =
115 {'I','n','s','t','a','l','l','O','D','B','C',0};
116 static const WCHAR szInstallServices[] =
117 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
118 static const WCHAR szPublishComponents[] =
119 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
120 static const WCHAR szRegisterComPlus[] =
121 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
122 static const WCHAR szRegisterUser[] =
123 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
124 static const WCHAR szRemoveEnvironmentStrings[] =
125 {'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};
126 static const WCHAR szRemoveExistingProducts[] =
127 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
128 static const WCHAR szRemoveFolders[] =
129 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
130 static const WCHAR szRemoveIniValues[] =
131 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
132 static const WCHAR szRemoveODBC[] =
133 {'R','e','m','o','v','e','O','D','B','C',0};
134 static const WCHAR szRemoveRegistryValues[] =
135 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
136 static const WCHAR szRemoveShortcuts[] =
137 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
138 static const WCHAR szRMCCPSearch[] =
139 {'R','M','C','C','P','S','e','a','r','c','h',0};
140 static const WCHAR szScheduleReboot[] =
141 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
142 static const WCHAR szSelfUnregModules[] =
143 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
144 static const WCHAR szSetODBCFolders[] =
145 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
146 static const WCHAR szStartServices[] =
147 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
148 static const WCHAR szStopServices[] =
149 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
150 static const WCHAR szUnpublishComponents[] =
151 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
152 static const WCHAR szUnpublishFeatures[] =
153 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
154 static const WCHAR szUnregisterComPlus[] =
155 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
156 static const WCHAR szUnregisterTypeLibraries[] =
157 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
158 static const WCHAR szValidateProductID[] =
159 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
160 static const WCHAR szWriteEnvironmentStrings[] =
161 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
163 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
165 static const WCHAR Query_t[] =
166 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
167 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
168 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
169 ' ','\'','%','s','\'',0};
172 row = MSI_QueryGetRecord( package->db, Query_t, action );
175 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
176 msiobj_release(&row->hdr);
179 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
183 static const WCHAR template_s[]=
184 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
186 static const WCHAR template_e[]=
187 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
188 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
190 static const WCHAR format[] =
191 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
195 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
197 sprintfW(message,template_s,timet,action);
199 sprintfW(message,template_e,timet,action,rc);
201 row = MSI_CreateRecord(1);
202 MSI_RecordSetStringW(row,1,message);
204 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
205 msiobj_release(&row->hdr);
215 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
217 enum parse_state state = state_quote;
220 int ignore, in_quotes = 0, count = 0, len = 0;
222 for (p = str; *p; p++)
227 case state_whitespace:
231 if (!count) goto done;
238 if (in_quotes) count--;
243 if (!count) in_quotes = 0;
255 if (in_quotes) count--;
259 state = state_whitespace;
260 if (!count) goto done;
265 if (!count) in_quotes = 0;
276 if (in_quotes) count--;
280 state = state_whitespace;
281 if (!count || (count > 1 && !len)) goto done;
287 if (!count) in_quotes = 0;
296 if (!ignore) *out++ = *p;
300 if (!len) *value = 0;
307 static void remove_quotes( WCHAR *str )
310 int len = strlenW( str );
312 while ((p = strchrW( p, '"' )))
314 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
319 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
329 return ERROR_SUCCESS;
334 while (*ptr == ' ') ptr++;
337 ptr2 = strchrW( ptr, '=' );
338 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
341 if (!len) return ERROR_INVALID_COMMAND_LINE;
343 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
344 memcpy( prop, ptr, len * sizeof(WCHAR) );
346 if (!preserve_case) struprW( prop );
349 while (*ptr2 == ' ') ptr2++;
352 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
353 len = parse_prop( ptr2, val, &num_quotes );
356 WARN("unbalanced quotes\n");
359 return ERROR_INVALID_COMMAND_LINE;
361 remove_quotes( val );
362 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
364 r = msi_set_property( package->db, prop, val );
365 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
366 msi_reset_folders( package, TRUE );
374 return ERROR_SUCCESS;
377 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
380 LPWSTR p, *ret = NULL;
386 /* count the number of substrings */
387 for ( pc = str, count = 0; pc; count++ )
389 pc = strchrW( pc, sep );
394 /* allocate space for an array of substring pointers and the substrings */
395 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
396 (lstrlenW(str)+1) * sizeof(WCHAR) );
400 /* copy the string and set the pointers */
401 p = (LPWSTR) &ret[count+1];
403 for( count = 0; (ret[count] = p); count++ )
405 p = strchrW( p, sep );
413 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
415 static const WCHAR szSystemLanguageID[] =
416 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
418 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
419 UINT ret = ERROR_FUNCTION_FAILED;
421 prod_code = msi_dup_property( package->db, szProductCode );
422 patch_product = msi_get_suminfo_product( patch );
424 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
426 if ( strstrW( patch_product, prod_code ) )
431 si = MSI_GetSummaryInformationW( patch, 0 );
434 ERR("no summary information!\n");
438 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
441 ERR("no template property!\n");
442 msiobj_release( &si->hdr );
449 msiobj_release( &si->hdr );
453 langid = msi_dup_property( package->db, szSystemLanguageID );
456 msiobj_release( &si->hdr );
460 p = strchrW( template, ';' );
461 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
463 TRACE("applicable transform\n");
467 /* FIXME: check platform */
469 msiobj_release( &si->hdr );
473 msi_free( patch_product );
474 msi_free( prod_code );
475 msi_free( template );
481 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
482 MSIDATABASE *patch_db, LPCWSTR name )
484 UINT ret = ERROR_FUNCTION_FAILED;
485 IStorage *stg = NULL;
488 TRACE("%p %s\n", package, debugstr_w(name) );
492 ERR("expected a colon in %s\n", debugstr_w(name));
493 return ERROR_FUNCTION_FAILED;
496 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
499 ret = msi_check_transform_applicable( package, stg );
500 if (ret == ERROR_SUCCESS)
501 msi_table_apply_transform( package->db, stg );
503 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
504 IStorage_Release( stg );
507 ERR("failed to open substorage %s\n", debugstr_w(name));
509 return ERROR_SUCCESS;
512 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
514 LPWSTR guid_list, *guids, product_code;
515 UINT i, ret = ERROR_FUNCTION_FAILED;
517 product_code = msi_dup_property( package->db, szProductCode );
520 /* FIXME: the property ProductCode should be written into the DB somewhere */
521 ERR("no product code to check\n");
522 return ERROR_SUCCESS;
525 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
526 guids = msi_split_string( guid_list, ';' );
527 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
529 if (!strcmpW( guids[i], product_code ))
533 msi_free( guid_list );
534 msi_free( product_code );
539 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
542 MSIRECORD *rec = NULL;
547 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
548 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
549 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
550 '`','S','o','u','r','c','e','`',' ','I','S',' ',
551 'N','O','T',' ','N','U','L','L',0};
553 r = MSI_DatabaseOpenViewW(package->db, query, &view);
554 if (r != ERROR_SUCCESS)
557 r = MSI_ViewExecute(view, 0);
558 if (r != ERROR_SUCCESS)
561 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
563 prop = MSI_RecordGetString(rec, 1);
564 patch = msi_dup_property(package->db, szPatch);
565 msi_set_property(package->db, prop, patch);
570 if (rec) msiobj_release(&rec->hdr);
571 msiobj_release(&view->hdr);
576 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
579 UINT r = ERROR_SUCCESS;
582 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
584 return ERROR_OUTOFMEMORY;
586 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
590 return ERROR_OUTOFMEMORY;
596 msi_free( pi->patchcode );
598 return ERROR_PATCH_PACKAGE_INVALID;
601 p = strchrW( p + 1, '}' );
604 msi_free( pi->patchcode );
606 return ERROR_PATCH_PACKAGE_INVALID;
611 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
615 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
617 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
620 msi_free( pi->patchcode );
622 return ERROR_OUTOFMEMORY;
629 struct msi_patch_offset
636 struct msi_patch_offset_list
639 UINT count, min, max;
640 UINT offset_to_apply;
643 static struct msi_patch_offset_list *msi_patch_offset_list_create(void)
645 struct msi_patch_offset_list *pos = msi_alloc(sizeof(struct msi_patch_offset_list));
646 list_init( &pos->files );
647 pos->count = pos->max = 0;
653 static void msi_patch_offset_list_free(struct msi_patch_offset_list *pos)
655 struct msi_patch_offset *po, *po2;
657 LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct msi_patch_offset, entry )
659 msi_free( po->Name );
666 static void msi_patch_offset_get_patches(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
671 static const WCHAR query_patch[] = {
672 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
673 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
674 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
676 r = MSI_DatabaseOpenViewW( db, query_patch, &view );
677 if (r != ERROR_SUCCESS)
680 rec = MSI_CreateRecord( 1 );
681 MSI_RecordSetInteger(rec, 1, last_sequence);
683 r = MSI_ViewExecute( view, rec );
684 msiobj_release( &rec->hdr );
685 if (r != ERROR_SUCCESS)
688 while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
690 UINT sequence = MSI_RecordGetInteger( rec, 2 );
693 * We only use the max/min sequence numbers for now.
696 pos->min = min(pos->min, sequence);
697 pos->max = max(pos->max, sequence);
700 msiobj_release( &rec->hdr );
703 msiobj_release( &view->hdr );
706 static void msi_patch_offset_get_files(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
711 static const WCHAR query_files[] = {
712 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
713 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
714 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
716 r = MSI_DatabaseOpenViewW( db, query_files, &view );
717 if (r != ERROR_SUCCESS)
720 rec = MSI_CreateRecord( 1 );
721 MSI_RecordSetInteger(rec, 1, last_sequence);
723 r = MSI_ViewExecute( view, rec );
724 msiobj_release( &rec->hdr );
725 if (r != ERROR_SUCCESS)
728 while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
730 UINT attributes = MSI_RecordGetInteger( rec, 7 );
731 if (attributes & msidbFileAttributesPatchAdded)
733 struct msi_patch_offset *po = msi_alloc(sizeof(struct msi_patch_offset));
735 po->Name = msi_dup_record_field( rec, 1 );
736 po->Sequence = MSI_RecordGetInteger( rec, 8 );
738 pos->min = min(pos->min, po->Sequence);
739 pos->max = max(pos->max, po->Sequence);
741 list_add_tail( &pos->files, &po->entry );
744 msiobj_release( &rec->hdr );
747 msiobj_release( &view->hdr );
750 static UINT msi_patch_offset_modify_db(MSIDATABASE *db, struct msi_patch_offset_list *pos)
752 static const WCHAR query_files[] =
753 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
754 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ',
755 'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
756 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
757 struct msi_patch_offset *po;
762 r = MSI_DatabaseOpenViewW( db, query_files, &view );
763 if (r != ERROR_SUCCESS)
764 return ERROR_SUCCESS;
766 rec = MSI_CreateRecord( 2 );
767 MSI_RecordSetInteger( rec, 1, pos->min );
768 MSI_RecordSetInteger( rec, 2, pos->max );
770 r = MSI_ViewExecute( view, rec );
771 msiobj_release( &rec->hdr );
772 if (r != ERROR_SUCCESS)
775 LIST_FOR_EACH_ENTRY( po, &pos->files, struct msi_patch_offset, entry )
778 while ( (r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS )
780 LPCWSTR file = MSI_RecordGetString( rec, 1 );
783 if (!strcmpiW(file, po->Name))
786 seq = MSI_RecordGetInteger( rec, 8 );
787 MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
788 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
789 if (r != ERROR_SUCCESS)
790 ERR("Failed to update offset for file %s.\n", debugstr_w(file));
792 msiobj_release( &rec->hdr );
796 msiobj_release( &rec->hdr );
799 if (r_fetch != ERROR_SUCCESS)
804 msiobj_release( &view->hdr );
806 return ERROR_SUCCESS;
809 static const WCHAR patch_media_query[] = {
810 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
811 'W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
812 'A','N','D',' ','`','C','a','b','i','n','e','t','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
813 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
826 static UINT msi_add_patch_media( MSIPACKAGE *package, IStorage *patch )
828 static const WCHAR delete_query[] = {
829 'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
830 'W','H','E','R','E',' ','`','D','i','s','k','I','d','`','=','?',0};
831 static const WCHAR insert_query[] = {
832 'I','N','S','E','R','T',' ','I','N','T','O',' ','`','M','e','d','i','a','`',' ',
833 '(','`','D','i','s','k','I','d','`',',','`','L','a','s','t','S','e','q','u','e','n','c','e','`',',',
834 '`','D','i','s','k','P','r','o','m','p','t','`',',','`','C','a','b','i','n','e','t','`',',',
835 '`','V','o','l','u','m','e','L','a','b','e','l','`',',','`','S','o','u','r','c','e','`',')',' ',
836 'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
838 MSIRECORD *rec = NULL;
840 struct list media_list;
841 struct patch_media *media, *next;
843 r = MSI_DatabaseOpenViewW( package->db, patch_media_query, &view );
844 if (r != ERROR_SUCCESS) return r;
846 r = MSI_ViewExecute( view, 0 );
847 if (r != ERROR_SUCCESS)
849 msiobj_release( &view->hdr );
850 TRACE("query failed %u\n", r);
854 list_init( &media_list );
855 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
857 disk_id = MSI_RecordGetInteger( rec, 1 );
858 TRACE("disk_id %u\n", disk_id);
859 if (disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
861 msiobj_release( &rec->hdr );
864 if (!(media = msi_alloc( sizeof( *media )))) goto done;
865 media->disk_id = disk_id;
866 media->last_sequence = MSI_RecordGetInteger( rec, 2 );
867 media->prompt = msi_dup_record_field( rec, 3 );
868 media->cabinet = msi_dup_record_field( rec, 4 );
869 media->volume = msi_dup_record_field( rec, 5 );
870 media->source = msi_dup_record_field( rec, 6 );
872 list_add_tail( &media_list, &media->entry );
873 msiobj_release( &rec->hdr );
875 LIST_FOR_EACH_ENTRY( media, &media_list, struct patch_media, entry )
877 MSIQUERY *delete_view, *insert_view;
879 r = MSI_DatabaseOpenViewW( package->db, delete_query, &delete_view );
880 if (r != ERROR_SUCCESS) goto done;
882 rec = MSI_CreateRecord( 1 );
883 MSI_RecordSetInteger( rec, 1, media->disk_id );
885 r = MSI_ViewExecute( delete_view, rec );
886 msiobj_release( &delete_view->hdr );
887 msiobj_release( &rec->hdr );
888 if (r != ERROR_SUCCESS) goto done;
890 r = MSI_DatabaseOpenViewW( package->db, insert_query, &insert_view );
891 if (r != ERROR_SUCCESS) goto done;
893 disk_id = package->db->media_transform_disk_id;
894 TRACE("disk id %u\n", disk_id);
895 TRACE("last sequence %u\n", media->last_sequence);
896 TRACE("prompt %s\n", debugstr_w(media->prompt));
897 TRACE("cabinet %s\n", debugstr_w(media->cabinet));
898 TRACE("volume %s\n", debugstr_w(media->volume));
899 TRACE("source %s\n", debugstr_w(media->source));
901 rec = MSI_CreateRecord( 6 );
902 MSI_RecordSetInteger( rec, 1, disk_id );
903 MSI_RecordSetInteger( rec, 2, media->last_sequence );
904 MSI_RecordSetStringW( rec, 3, media->prompt );
905 MSI_RecordSetStringW( rec, 4, media->cabinet );
906 MSI_RecordSetStringW( rec, 5, media->volume );
907 MSI_RecordSetStringW( rec, 6, media->source );
909 r = MSI_ViewExecute( insert_view, rec );
910 msiobj_release( &insert_view->hdr );
911 msiobj_release( &rec->hdr );
912 if (r != ERROR_SUCCESS) goto done;
914 r = msi_add_cabinet_stream( package, disk_id, patch, media->cabinet );
915 if (r != ERROR_SUCCESS) WARN("failed to add cabinet stream %u\n", r);
916 package->db->media_transform_disk_id++;
920 msiobj_release( &view->hdr );
921 LIST_FOR_EACH_ENTRY_SAFE( media, next, &media_list, struct patch_media, entry )
923 list_remove( &media->entry );
924 msi_free( media->prompt );
925 msi_free( media->cabinet );
926 msi_free( media->volume );
927 msi_free( media->source );
933 static UINT msi_set_patch_offsets(MSIDATABASE *db)
936 MSIRECORD *rec = NULL;
939 r = MSI_DatabaseOpenViewW( db, patch_media_query, &view );
940 if (r != ERROR_SUCCESS)
943 r = MSI_ViewExecute( view, 0 );
944 if (r != ERROR_SUCCESS)
947 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
949 UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
950 struct msi_patch_offset_list *pos;
952 /* FIXME: Set/Check Source field instead? */
953 if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET)
955 msiobj_release( &rec->hdr );
959 pos = msi_patch_offset_list_create();
961 msi_patch_offset_get_files( db, last_sequence, pos );
962 msi_patch_offset_get_patches( db, last_sequence, pos );
966 UINT offset = db->media_transform_offset - pos->min;
967 last_sequence = offset + pos->max;
970 * This is for the patch table, which is not yet properly transformed.
972 last_sequence += pos->min;
974 pos->offset_to_apply = offset;
975 msi_patch_offset_modify_db( db, pos );
977 MSI_RecordSetInteger( rec, 2, last_sequence );
978 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
979 if (r != ERROR_SUCCESS)
980 ERR("Failed to update Media table entry, expect breakage (%u).\n", r);
982 db->media_transform_offset = last_sequence + 1;
985 msi_patch_offset_list_free( pos );
986 msiobj_release( &rec->hdr );
990 msiobj_release( &view->hdr );
994 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
996 UINT i, r = ERROR_SUCCESS;
999 /* apply substorage transforms */
1000 substorage = msi_split_string( patch->transforms, ';' );
1001 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
1003 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
1004 if (r == ERROR_SUCCESS)
1006 msi_add_patch_media( package, patch_db->storage );
1007 msi_set_patch_offsets( package->db );
1011 msi_free( substorage );
1012 if (r != ERROR_SUCCESS)
1015 msi_set_media_source_prop( package );
1017 patch->state = MSIPATCHSTATE_APPLIED;
1018 list_add_tail( &package->patches, &patch->entry );
1019 return ERROR_SUCCESS;
1022 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
1024 static const WCHAR dotmsp[] = {'.','m','s','p',0};
1025 MSIDATABASE *patch_db = NULL;
1026 WCHAR localfile[MAX_PATH];
1028 MSIPATCHINFO *patch = NULL;
1029 UINT r = ERROR_SUCCESS;
1031 TRACE("%p %s\n", package, debugstr_w( file ) );
1033 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
1034 if ( r != ERROR_SUCCESS )
1036 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
1040 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
1043 msiobj_release( &patch_db->hdr );
1044 return ERROR_FUNCTION_FAILED;
1047 r = msi_check_patch_applicable( package, si );
1048 if (r != ERROR_SUCCESS)
1050 TRACE("patch not applicable\n");
1055 r = msi_parse_patch_summary( si, &patch );
1056 if ( r != ERROR_SUCCESS )
1059 r = msi_get_local_package_name( localfile, dotmsp );
1060 if ( r != ERROR_SUCCESS )
1063 TRACE("copying to local package %s\n", debugstr_w(localfile));
1065 if (!CopyFileW( file, localfile, FALSE ))
1067 ERR("Unable to copy package (%s -> %s) (error %u)\n",
1068 debugstr_w(file), debugstr_w(localfile), GetLastError());
1072 patch->localfile = strdupW( localfile );
1074 r = msi_apply_patch_db( package, patch_db, patch );
1075 if ( r != ERROR_SUCCESS )
1076 WARN("patch failed to apply %u\n", r);
1079 msiobj_release( &si->hdr );
1080 msiobj_release( &patch_db->hdr );
1081 if (patch && r != ERROR_SUCCESS)
1083 if (patch->localfile)
1084 DeleteFileW( patch->localfile );
1086 msi_free( patch->patchcode );
1087 msi_free( patch->transforms );
1088 msi_free( patch->localfile );
1094 /* get the PATCH property, and apply all the patches it specifies */
1095 static UINT msi_apply_patches( MSIPACKAGE *package )
1097 LPWSTR patch_list, *patches;
1098 UINT i, r = ERROR_SUCCESS;
1100 patch_list = msi_dup_property( package->db, szPatch );
1102 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
1104 patches = msi_split_string( patch_list, ';' );
1105 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
1106 r = msi_apply_patch_package( package, patches[i] );
1108 msi_free( patches );
1109 msi_free( patch_list );
1114 static UINT msi_apply_transforms( MSIPACKAGE *package )
1116 static const WCHAR szTransforms[] = {
1117 'T','R','A','N','S','F','O','R','M','S',0 };
1118 LPWSTR xform_list, *xforms;
1119 UINT i, r = ERROR_SUCCESS;
1121 xform_list = msi_dup_property( package->db, szTransforms );
1122 xforms = msi_split_string( xform_list, ';' );
1124 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
1126 if (xforms[i][0] == ':')
1127 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
1132 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
1135 WCHAR *p = strrchrW( package->PackagePath, '\\' );
1136 DWORD len = p - package->PackagePath + 1;
1138 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
1141 msi_free( xform_list );
1142 return ERROR_OUTOFMEMORY;
1144 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
1145 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
1147 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
1148 if (transform != xforms[i]) msi_free( transform );
1153 msi_free( xform_list );
1158 static BOOL ui_sequence_exists( MSIPACKAGE *package )
1163 static const WCHAR ExecSeqQuery [] =
1164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1165 '`','I','n','s','t','a','l','l',
1166 'U','I','S','e','q','u','e','n','c','e','`',
1167 ' ','W','H','E','R','E',' ',
1168 '`','S','e','q','u','e','n','c','e','`',' ',
1169 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1170 '`','S','e','q','u','e','n','c','e','`',0};
1172 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1173 if (rc == ERROR_SUCCESS)
1175 msiobj_release(&view->hdr);
1182 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
1184 LPWSTR source, check;
1186 if (msi_get_property_int( package->db, szInstalled, 0 ))
1190 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
1191 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
1192 RegCloseKey( hkey );
1199 db = msi_dup_property( package->db, szOriginalDatabase );
1201 return ERROR_OUTOFMEMORY;
1203 p = strrchrW( db, '\\' );
1206 p = strrchrW( db, '/' );
1210 return ERROR_SUCCESS;
1215 source = msi_alloc( len * sizeof(WCHAR) );
1216 lstrcpynW( source, db, len );
1220 check = msi_dup_property( package->db, cszSourceDir );
1221 if (!check || replace)
1223 UINT r = msi_set_property( package->db, cszSourceDir, source );
1224 if (r == ERROR_SUCCESS)
1225 msi_reset_folders( package, TRUE );
1229 check = msi_dup_property( package->db, cszSOURCEDIR );
1230 if (!check || replace)
1231 msi_set_property( package->db, cszSOURCEDIR, source );
1236 return ERROR_SUCCESS;
1239 static BOOL needs_ui_sequence(MSIPACKAGE *package)
1241 INT level = msi_get_property_int(package->db, szUILevel, 0);
1242 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
1245 UINT msi_set_context(MSIPACKAGE *package)
1249 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
1251 num = msi_get_property_int(package->db, szAllUsers, 0);
1252 if (num == 1 || num == 2)
1253 package->Context = MSIINSTALLCONTEXT_MACHINE;
1255 return ERROR_SUCCESS;
1258 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
1261 LPCWSTR cond, action;
1262 MSIPACKAGE *package = param;
1264 action = MSI_RecordGetString(row,1);
1267 ERR("Error is retrieving action name\n");
1268 return ERROR_FUNCTION_FAILED;
1271 /* check conditions */
1272 cond = MSI_RecordGetString(row,2);
1274 /* this is a hack to skip errors in the condition code */
1275 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1277 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
1278 return ERROR_SUCCESS;
1281 if (needs_ui_sequence(package))
1282 rc = ACTION_PerformUIAction(package, action, -1);
1284 rc = ACTION_PerformAction(package, action, -1);
1286 msi_dialog_check_messages( NULL );
1288 if (package->CurrentInstallState != ERROR_SUCCESS)
1289 rc = package->CurrentInstallState;
1291 if (rc == ERROR_FUNCTION_NOT_CALLED)
1294 if (rc != ERROR_SUCCESS)
1295 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
1300 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
1304 static const WCHAR query[] =
1305 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1307 ' ','W','H','E','R','E',' ',
1308 '`','S','e','q','u','e','n','c','e','`',' ',
1309 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1310 '`','S','e','q','u','e','n','c','e','`',0};
1312 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
1314 r = MSI_OpenQuery( package->db, &view, query, szTable );
1315 if (r == ERROR_SUCCESS)
1317 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
1318 msiobj_release(&view->hdr);
1324 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1328 static const WCHAR ExecSeqQuery[] =
1329 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1330 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1331 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1332 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1333 'O','R','D','E','R',' ', 'B','Y',' ',
1334 '`','S','e','q','u','e','n','c','e','`',0 };
1335 static const WCHAR IVQuery[] =
1336 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1337 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1338 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1339 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1340 ' ','\'', 'I','n','s','t','a','l','l',
1341 'V','a','l','i','d','a','t','e','\'', 0};
1344 if (package->script->ExecuteSequenceRun)
1346 TRACE("Execute Sequence already Run\n");
1347 return ERROR_SUCCESS;
1350 package->script->ExecuteSequenceRun = TRUE;
1352 /* get the sequence number */
1355 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
1357 return ERROR_FUNCTION_FAILED;
1358 seq = MSI_RecordGetInteger(row,1);
1359 msiobj_release(&row->hdr);
1362 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1363 if (rc == ERROR_SUCCESS)
1365 TRACE("Running the actions\n");
1367 msi_set_property(package->db, cszSourceDir, NULL);
1369 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1370 msiobj_release(&view->hdr);
1376 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1380 static const WCHAR ExecSeqQuery [] =
1381 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1382 '`','I','n','s','t','a','l','l',
1383 'U','I','S','e','q','u','e','n','c','e','`',
1384 ' ','W','H','E','R','E',' ',
1385 '`','S','e','q','u','e','n','c','e','`',' ',
1386 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1387 '`','S','e','q','u','e','n','c','e','`',0};
1389 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1390 if (rc == ERROR_SUCCESS)
1392 TRACE("Running the actions\n");
1394 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1395 msiobj_release(&view->hdr);
1401 /********************************************************
1402 * ACTION helper functions and functions that perform the actions
1403 *******************************************************/
1404 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1405 UINT* rc, UINT script, BOOL force )
1410 arc = ACTION_CustomAction(package, action, script, force);
1412 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1421 * Actual Action Handlers
1424 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1426 MSIPACKAGE *package = param;
1427 LPCWSTR dir, component;
1433 component = MSI_RecordGetString(row, 2);
1435 return ERROR_SUCCESS;
1437 comp = get_loaded_component(package, component);
1439 return ERROR_SUCCESS;
1443 TRACE("component is disabled\n");
1444 return ERROR_SUCCESS;
1447 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1449 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1450 comp->Action = comp->Installed;
1451 return ERROR_SUCCESS;
1453 comp->Action = INSTALLSTATE_LOCAL;
1455 dir = MSI_RecordGetString(row,1);
1458 ERR("Unable to get folder id\n");
1459 return ERROR_SUCCESS;
1462 uirow = MSI_CreateRecord(1);
1463 MSI_RecordSetStringW(uirow, 1, dir);
1464 ui_actiondata(package, szCreateFolders, uirow);
1465 msiobj_release(&uirow->hdr);
1467 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1470 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1471 return ERROR_SUCCESS;
1474 TRACE("Folder is %s\n",debugstr_w(full_path));
1476 if (folder->State == 0)
1477 create_full_pathW(full_path);
1481 msi_free(full_path);
1482 return ERROR_SUCCESS;
1485 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1487 static const WCHAR query[] =
1488 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1489 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1493 /* create all the empty folders specified in the CreateFolder table */
1494 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1495 if (rc != ERROR_SUCCESS)
1496 return ERROR_SUCCESS;
1498 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1499 msiobj_release(&view->hdr);
1504 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1506 MSIPACKAGE *package = param;
1507 LPCWSTR dir, component;
1513 component = MSI_RecordGetString(row, 2);
1515 return ERROR_SUCCESS;
1517 comp = get_loaded_component(package, component);
1519 return ERROR_SUCCESS;
1523 TRACE("component is disabled\n");
1524 return ERROR_SUCCESS;
1527 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1529 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1530 comp->Action = comp->Installed;
1531 return ERROR_SUCCESS;
1533 comp->Action = INSTALLSTATE_ABSENT;
1535 dir = MSI_RecordGetString( row, 1 );
1538 ERR("Unable to get folder id\n");
1539 return ERROR_SUCCESS;
1542 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1545 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1546 return ERROR_SUCCESS;
1549 TRACE("folder is %s\n", debugstr_w(full_path));
1551 uirow = MSI_CreateRecord( 1 );
1552 MSI_RecordSetStringW( uirow, 1, dir );
1553 ui_actiondata( package, szRemoveFolders, uirow );
1554 msiobj_release( &uirow->hdr );
1556 RemoveDirectoryW( full_path );
1559 msi_free( full_path );
1560 return ERROR_SUCCESS;
1563 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1565 static const WCHAR query[] =
1566 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1567 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1572 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1573 if (rc != ERROR_SUCCESS)
1574 return ERROR_SUCCESS;
1576 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1577 msiobj_release( &view->hdr );
1582 static UINT load_component( MSIRECORD *row, LPVOID param )
1584 MSIPACKAGE *package = param;
1587 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1589 return ERROR_FUNCTION_FAILED;
1591 list_add_tail( &package->components, &comp->entry );
1593 /* fill in the data */
1594 comp->Component = msi_dup_record_field( row, 1 );
1596 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1598 comp->ComponentId = msi_dup_record_field( row, 2 );
1599 comp->Directory = msi_dup_record_field( row, 3 );
1600 comp->Attributes = MSI_RecordGetInteger(row,4);
1601 comp->Condition = msi_dup_record_field( row, 5 );
1602 comp->KeyPath = msi_dup_record_field( row, 6 );
1604 comp->Installed = INSTALLSTATE_UNKNOWN;
1605 comp->Action = INSTALLSTATE_UNKNOWN;
1606 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1608 comp->assembly = load_assembly( package, comp );
1609 return ERROR_SUCCESS;
1612 static UINT load_all_components( MSIPACKAGE *package )
1614 static const WCHAR query[] = {
1615 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1616 '`','C','o','m','p','o','n','e','n','t','`',0 };
1620 if (!list_empty(&package->components))
1621 return ERROR_SUCCESS;
1623 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1624 if (r != ERROR_SUCCESS)
1627 r = MSI_IterateRecords(view, NULL, load_component, package);
1628 msiobj_release(&view->hdr);
1633 MSIPACKAGE *package;
1634 MSIFEATURE *feature;
1637 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1641 cl = msi_alloc( sizeof (*cl) );
1643 return ERROR_NOT_ENOUGH_MEMORY;
1644 cl->component = comp;
1645 list_add_tail( &feature->Components, &cl->entry );
1647 return ERROR_SUCCESS;
1650 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1654 fl = msi_alloc( sizeof(*fl) );
1656 return ERROR_NOT_ENOUGH_MEMORY;
1657 fl->feature = child;
1658 list_add_tail( &parent->Children, &fl->entry );
1660 return ERROR_SUCCESS;
1663 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1665 _ilfs* ilfs = param;
1669 component = MSI_RecordGetString(row,1);
1671 /* check to see if the component is already loaded */
1672 comp = get_loaded_component( ilfs->package, component );
1675 ERR("unknown component %s\n", debugstr_w(component));
1676 return ERROR_FUNCTION_FAILED;
1679 add_feature_component( ilfs->feature, comp );
1680 comp->Enabled = TRUE;
1682 return ERROR_SUCCESS;
1685 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1687 MSIFEATURE *feature;
1692 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1694 if ( !strcmpW( feature->Feature, name ) )
1701 static UINT load_feature(MSIRECORD * row, LPVOID param)
1703 MSIPACKAGE* package = param;
1704 MSIFEATURE* feature;
1705 static const WCHAR Query1[] =
1706 {'S','E','L','E','C','T',' ',
1707 '`','C','o','m','p','o','n','e','n','t','_','`',
1708 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1709 'C','o','m','p','o','n','e','n','t','s','`',' ',
1710 'W','H','E','R','E',' ',
1711 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1716 /* fill in the data */
1718 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1720 return ERROR_NOT_ENOUGH_MEMORY;
1722 list_init( &feature->Children );
1723 list_init( &feature->Components );
1725 feature->Feature = msi_dup_record_field( row, 1 );
1727 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1729 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1730 feature->Title = msi_dup_record_field( row, 3 );
1731 feature->Description = msi_dup_record_field( row, 4 );
1733 if (!MSI_RecordIsNull(row,5))
1734 feature->Display = MSI_RecordGetInteger(row,5);
1736 feature->Level= MSI_RecordGetInteger(row,6);
1737 feature->Directory = msi_dup_record_field( row, 7 );
1738 feature->Attributes = MSI_RecordGetInteger(row,8);
1740 feature->Installed = INSTALLSTATE_UNKNOWN;
1741 feature->Action = INSTALLSTATE_UNKNOWN;
1742 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1744 list_add_tail( &package->features, &feature->entry );
1746 /* load feature components */
1748 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1749 if (rc != ERROR_SUCCESS)
1750 return ERROR_SUCCESS;
1752 ilfs.package = package;
1753 ilfs.feature = feature;
1755 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1756 msiobj_release(&view->hdr);
1758 return ERROR_SUCCESS;
1761 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1763 MSIPACKAGE* package = param;
1764 MSIFEATURE *parent, *child;
1766 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1768 return ERROR_FUNCTION_FAILED;
1770 if (!child->Feature_Parent)
1771 return ERROR_SUCCESS;
1773 parent = find_feature_by_name( package, child->Feature_Parent );
1775 return ERROR_FUNCTION_FAILED;
1777 add_feature_child( parent, child );
1778 return ERROR_SUCCESS;
1781 static UINT load_all_features( MSIPACKAGE *package )
1783 static const WCHAR query[] = {
1784 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1785 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1786 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1790 if (!list_empty(&package->features))
1791 return ERROR_SUCCESS;
1793 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1794 if (r != ERROR_SUCCESS)
1797 r = MSI_IterateRecords( view, NULL, load_feature, package );
1798 if (r != ERROR_SUCCESS)
1801 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1802 msiobj_release( &view->hdr );
1807 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1818 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1820 static const WCHAR query[] = {
1821 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1822 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1823 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1824 MSIQUERY *view = NULL;
1825 MSIRECORD *row = NULL;
1828 TRACE("%s\n", debugstr_w(file->File));
1830 r = MSI_OpenQuery(package->db, &view, query, file->File);
1831 if (r != ERROR_SUCCESS)
1834 r = MSI_ViewExecute(view, NULL);
1835 if (r != ERROR_SUCCESS)
1838 r = MSI_ViewFetch(view, &row);
1839 if (r != ERROR_SUCCESS)
1842 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1843 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1844 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1845 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1846 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1849 if (view) msiobj_release(&view->hdr);
1850 if (row) msiobj_release(&row->hdr);
1854 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1857 static const WCHAR query[] = {
1858 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1859 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1860 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1862 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1865 WARN("query failed\n");
1866 return ERROR_FUNCTION_FAILED;
1869 file->disk_id = MSI_RecordGetInteger( row, 1 );
1870 msiobj_release( &row->hdr );
1871 return ERROR_SUCCESS;
1874 static UINT load_file(MSIRECORD *row, LPVOID param)
1876 MSIPACKAGE* package = param;
1880 /* fill in the data */
1882 file = msi_alloc_zero( sizeof (MSIFILE) );
1884 return ERROR_NOT_ENOUGH_MEMORY;
1886 file->File = msi_dup_record_field( row, 1 );
1888 component = MSI_RecordGetString( row, 2 );
1889 file->Component = get_loaded_component( package, component );
1891 if (!file->Component)
1893 WARN("Component not found: %s\n", debugstr_w(component));
1894 msi_free(file->File);
1896 return ERROR_SUCCESS;
1899 file->FileName = msi_dup_record_field( row, 3 );
1900 reduce_to_longfilename( file->FileName );
1902 file->ShortName = msi_dup_record_field( row, 3 );
1903 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1905 file->FileSize = MSI_RecordGetInteger( row, 4 );
1906 file->Version = msi_dup_record_field( row, 5 );
1907 file->Language = msi_dup_record_field( row, 6 );
1908 file->Attributes = MSI_RecordGetInteger( row, 7 );
1909 file->Sequence = MSI_RecordGetInteger( row, 8 );
1911 file->state = msifs_invalid;
1913 /* if the compressed bits are not set in the file attributes,
1914 * then read the information from the package word count property
1916 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1918 file->IsCompressed = FALSE;
1920 else if (file->Attributes &
1921 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1923 file->IsCompressed = TRUE;
1925 else if (file->Attributes & msidbFileAttributesNoncompressed)
1927 file->IsCompressed = FALSE;
1931 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1934 load_file_hash(package, file);
1935 load_file_disk_id(package, file);
1937 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1939 list_add_tail( &package->files, &file->entry );
1941 return ERROR_SUCCESS;
1944 static UINT load_all_files(MSIPACKAGE *package)
1948 static const WCHAR Query[] =
1949 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1950 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1951 '`','S','e','q','u','e','n','c','e','`', 0};
1953 if (!list_empty(&package->files))
1954 return ERROR_SUCCESS;
1956 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1957 if (rc != ERROR_SUCCESS)
1958 return ERROR_SUCCESS;
1960 rc = MSI_IterateRecords(view, NULL, load_file, package);
1961 msiobj_release(&view->hdr);
1963 return ERROR_SUCCESS;
1966 static UINT load_media( MSIRECORD *row, LPVOID param )
1968 MSIPACKAGE *package = param;
1969 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1970 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1972 /* FIXME: load external cabinets and directory sources too */
1973 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1974 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1975 return ERROR_SUCCESS;
1978 static UINT load_all_media( MSIPACKAGE *package )
1980 static const WCHAR query[] =
1981 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
1982 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
1986 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1987 if (r != ERROR_SUCCESS) return ERROR_SUCCESS;
1989 MSI_IterateRecords( view, NULL, load_media, package );
1990 msiobj_release( &view->hdr );
1991 return ERROR_SUCCESS;
1994 static UINT load_patch(MSIRECORD *row, LPVOID param)
1996 MSIPACKAGE *package = param;
1997 MSIFILEPATCH *patch;
2000 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
2002 return ERROR_NOT_ENOUGH_MEMORY;
2004 file_key = msi_dup_record_field( row, 1 );
2005 patch->File = get_loaded_file( package, file_key );
2010 ERR("Failed to find target for patch in File table\n");
2012 return ERROR_FUNCTION_FAILED;
2015 patch->Sequence = MSI_RecordGetInteger( row, 2 );
2017 /* FIXME: The database should be properly transformed */
2018 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
2020 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
2021 patch->Attributes = MSI_RecordGetInteger( row, 4 );
2022 patch->IsApplied = FALSE;
2025 * Header field - for patch validation.
2026 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
2029 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
2031 list_add_tail( &package->filepatches, &patch->entry );
2033 return ERROR_SUCCESS;
2036 static UINT load_all_patches(MSIPACKAGE *package)
2040 static const WCHAR Query[] =
2041 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2042 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
2043 '`','S','e','q','u','e','n','c','e','`',0};
2045 if (!list_empty(&package->filepatches))
2046 return ERROR_SUCCESS;
2048 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2049 if (rc != ERROR_SUCCESS)
2050 return ERROR_SUCCESS;
2052 rc = MSI_IterateRecords(view, NULL, load_patch, package);
2053 msiobj_release(&view->hdr);
2055 return ERROR_SUCCESS;
2058 static UINT load_folder( MSIRECORD *row, LPVOID param )
2060 MSIPACKAGE *package = param;
2061 static WCHAR szEmpty[] = { 0 };
2062 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
2065 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
2067 return ERROR_NOT_ENOUGH_MEMORY;
2069 folder->Directory = msi_dup_record_field( row, 1 );
2071 TRACE("%s\n", debugstr_w(folder->Directory));
2073 p = msi_dup_record_field(row, 3);
2075 /* split src and target dir */
2077 src_short = folder_split_path( p, ':' );
2079 /* split the long and short paths */
2080 tgt_long = folder_split_path( tgt_short, '|' );
2081 src_long = folder_split_path( src_short, '|' );
2083 /* check for no-op dirs */
2084 if (tgt_short && !strcmpW( szDot, tgt_short ))
2085 tgt_short = szEmpty;
2086 if (src_short && !strcmpW( szDot, src_short ))
2087 src_short = szEmpty;
2090 tgt_long = tgt_short;
2093 src_short = tgt_short;
2094 src_long = tgt_long;
2098 src_long = src_short;
2100 /* FIXME: use the target short path too */
2101 folder->TargetDefault = strdupW(tgt_long);
2102 folder->SourceShortPath = strdupW(src_short);
2103 folder->SourceLongPath = strdupW(src_long);
2106 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
2107 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
2108 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
2110 folder->Parent = msi_dup_record_field( row, 2 );
2112 folder->Property = msi_dup_property( package->db, folder->Directory );
2114 list_add_tail( &package->folders, &folder->entry );
2116 TRACE("returning %p\n", folder);
2118 return ERROR_SUCCESS;
2121 static UINT load_all_folders( MSIPACKAGE *package )
2123 static const WCHAR query[] = {
2124 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
2125 '`','D','i','r','e','c','t','o','r','y','`',0 };
2129 if (!list_empty(&package->folders))
2130 return ERROR_SUCCESS;
2132 r = MSI_DatabaseOpenViewW( package->db, query, &view );
2133 if (r != ERROR_SUCCESS)
2136 r = MSI_IterateRecords(view, NULL, load_folder, package);
2137 msiobj_release(&view->hdr);
2142 * I am not doing any of the costing functionality yet.
2143 * Mostly looking at doing the Component and Feature loading
2145 * The native MSI does A LOT of modification to tables here. Mostly adding
2146 * a lot of temporary columns to the Feature and Component tables.
2148 * note: Native msi also tracks the short filename. But I am only going to
2149 * track the long ones. Also looking at this directory table
2150 * it appears that the directory table does not get the parents
2151 * resolved base on property only based on their entries in the
2154 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
2156 msi_set_property( package->db, szCostingComplete, szZero );
2157 msi_set_property( package->db, cszRootDrive, c_colon );
2159 load_all_folders( package );
2160 load_all_components( package );
2161 load_all_features( package );
2162 load_all_files( package );
2163 load_all_patches( package );
2164 load_all_media( package );
2166 return ERROR_SUCCESS;
2169 static UINT execute_script(MSIPACKAGE *package, UINT script )
2172 UINT rc = ERROR_SUCCESS;
2174 TRACE("Executing Script %i\n",script);
2176 if (!package->script)
2178 ERR("no script!\n");
2179 return ERROR_FUNCTION_FAILED;
2182 for (i = 0; i < package->script->ActionCount[script]; i++)
2185 action = package->script->Actions[script][i];
2186 ui_actionstart(package, action);
2187 TRACE("Executing Action (%s)\n",debugstr_w(action));
2188 rc = ACTION_PerformAction(package, action, script);
2189 if (rc != ERROR_SUCCESS)
2192 msi_free_action_script(package, script);
2196 static UINT ACTION_FileCost(MSIPACKAGE *package)
2198 return ERROR_SUCCESS;
2201 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
2206 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
2208 if (!comp->ComponentId) continue;
2210 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2211 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
2213 if (r != ERROR_SUCCESS)
2214 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2215 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
2217 if (r != ERROR_SUCCESS)
2218 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2219 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
2221 if (r != ERROR_SUCCESS)
2222 comp->Installed = INSTALLSTATE_ABSENT;
2226 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
2228 MSIFEATURE *feature;
2230 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2232 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
2234 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
2235 feature->Installed = INSTALLSTATE_ABSENT;
2237 feature->Installed = state;
2241 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
2243 return (feature->Level > 0 && feature->Level <= level);
2246 static BOOL process_state_property(MSIPACKAGE* package, int level,
2247 LPCWSTR property, INSTALLSTATE state)
2250 MSIFEATURE *feature;
2252 override = msi_dup_property( package->db, property );
2256 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2258 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
2261 if (!strcmpW(property, szReinstall)) state = feature->Installed;
2263 if (!strcmpiW( override, szAll ))
2265 if (feature->Installed != state)
2267 feature->Action = state;
2268 feature->ActionRequest = state;
2273 LPWSTR ptr = override;
2274 LPWSTR ptr2 = strchrW(override,',');
2278 int len = ptr2 - ptr;
2280 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
2281 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
2283 if (feature->Installed != state)
2285 feature->Action = state;
2286 feature->ActionRequest = state;
2293 ptr2 = strchrW(ptr,',');
2304 static BOOL process_overrides( MSIPACKAGE *package, int level )
2306 static const WCHAR szAddLocal[] =
2307 {'A','D','D','L','O','C','A','L',0};
2308 static const WCHAR szAddSource[] =
2309 {'A','D','D','S','O','U','R','C','E',0};
2310 static const WCHAR szAdvertise[] =
2311 {'A','D','V','E','R','T','I','S','E',0};
2314 /* all these activation/deactivation things happen in order and things
2315 * later on the list override things earlier on the list.
2317 * 0 INSTALLLEVEL processing
2330 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
2331 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
2332 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
2333 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
2334 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
2337 msi_set_property( package->db, szPreselected, szOne );
2342 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
2345 static const WCHAR szlevel[] =
2346 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2347 MSICOMPONENT* component;
2348 MSIFEATURE *feature;
2350 TRACE("Checking Install Level\n");
2352 level = msi_get_property_int(package->db, szlevel, 1);
2354 if (!msi_get_property_int( package->db, szPreselected, 0 ))
2356 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2358 if (!is_feature_selected( feature, level )) continue;
2360 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2362 if (feature->Attributes & msidbFeatureAttributesFavorSource)
2364 feature->Action = INSTALLSTATE_SOURCE;
2365 feature->ActionRequest = INSTALLSTATE_SOURCE;
2367 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2369 feature->Action = INSTALLSTATE_ADVERTISED;
2370 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
2374 feature->Action = INSTALLSTATE_LOCAL;
2375 feature->ActionRequest = INSTALLSTATE_LOCAL;
2379 /* disable child features of unselected parent or follow parent */
2380 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2384 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
2386 if (!is_feature_selected( feature, level ))
2388 fl->feature->Action = INSTALLSTATE_UNKNOWN;
2389 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
2391 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
2393 fl->feature->Action = feature->Action;
2394 fl->feature->ActionRequest = feature->ActionRequest;
2399 else /* preselected */
2401 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2403 if (!is_feature_selected( feature, level )) continue;
2405 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2407 if (feature->Installed == INSTALLSTATE_ABSENT)
2409 feature->Action = INSTALLSTATE_UNKNOWN;
2410 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
2414 feature->Action = feature->Installed;
2415 feature->ActionRequest = feature->Installed;
2419 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2423 if (!is_feature_selected( feature, level )) continue;
2425 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
2427 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
2429 fl->feature->Action = feature->Action;
2430 fl->feature->ActionRequest = feature->ActionRequest;
2436 /* now we want to set component state based based on feature state */
2437 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2441 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
2442 debugstr_w(feature->Feature), feature->Level, feature->Installed,
2443 feature->ActionRequest, feature->Action);
2445 if (!is_feature_selected( feature, level )) continue;
2447 /* features with components that have compressed files are made local */
2448 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2450 if (cl->component->ForceLocalState &&
2451 feature->ActionRequest == INSTALLSTATE_SOURCE)
2453 feature->Action = INSTALLSTATE_LOCAL;
2454 feature->ActionRequest = INSTALLSTATE_LOCAL;
2459 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2461 component = cl->component;
2463 switch (feature->ActionRequest)
2465 case INSTALLSTATE_ABSENT:
2466 component->anyAbsent = 1;
2468 case INSTALLSTATE_ADVERTISED:
2469 component->hasAdvertiseFeature = 1;
2471 case INSTALLSTATE_SOURCE:
2472 component->hasSourceFeature = 1;
2474 case INSTALLSTATE_LOCAL:
2475 component->hasLocalFeature = 1;
2477 case INSTALLSTATE_DEFAULT:
2478 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2479 component->hasAdvertiseFeature = 1;
2480 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2481 component->hasSourceFeature = 1;
2483 component->hasLocalFeature = 1;
2491 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2493 /* check if it's local or source */
2494 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2495 (component->hasLocalFeature || component->hasSourceFeature))
2497 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2498 !component->ForceLocalState)
2500 component->Action = INSTALLSTATE_SOURCE;
2501 component->ActionRequest = INSTALLSTATE_SOURCE;
2505 component->Action = INSTALLSTATE_LOCAL;
2506 component->ActionRequest = INSTALLSTATE_LOCAL;
2511 /* if any feature is local, the component must be local too */
2512 if (component->hasLocalFeature)
2514 component->Action = INSTALLSTATE_LOCAL;
2515 component->ActionRequest = INSTALLSTATE_LOCAL;
2518 if (component->hasSourceFeature)
2520 component->Action = INSTALLSTATE_SOURCE;
2521 component->ActionRequest = INSTALLSTATE_SOURCE;
2524 if (component->hasAdvertiseFeature)
2526 component->Action = INSTALLSTATE_ADVERTISED;
2527 component->ActionRequest = INSTALLSTATE_ADVERTISED;
2530 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2531 if (component->anyAbsent &&
2532 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
2534 component->Action = INSTALLSTATE_ABSENT;
2535 component->ActionRequest = INSTALLSTATE_ABSENT;
2539 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2541 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2543 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2544 component->Action = INSTALLSTATE_LOCAL;
2545 component->ActionRequest = INSTALLSTATE_LOCAL;
2548 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2549 component->Installed == INSTALLSTATE_SOURCE &&
2550 component->hasSourceFeature)
2552 component->Action = INSTALLSTATE_UNKNOWN;
2553 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2556 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2557 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2560 return ERROR_SUCCESS;
2563 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2565 MSIPACKAGE *package = param;
2570 name = MSI_RecordGetString(row,1);
2572 f = get_loaded_folder(package, name);
2573 if (!f) return ERROR_SUCCESS;
2575 /* reset the ResolvedTarget */
2576 msi_free(f->ResolvedTarget);
2577 f->ResolvedTarget = NULL;
2579 TRACE("directory %s ...\n", debugstr_w(name));
2580 path = resolve_target_folder( package, name, TRUE, TRUE, NULL );
2581 TRACE("resolves to %s\n", debugstr_w(path));
2584 return ERROR_SUCCESS;
2587 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2589 MSIPACKAGE *package = param;
2591 MSIFEATURE *feature;
2593 name = MSI_RecordGetString( row, 1 );
2595 feature = get_loaded_feature( package, name );
2597 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2601 Condition = MSI_RecordGetString(row,3);
2603 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2605 int level = MSI_RecordGetInteger(row,2);
2606 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2607 feature->Level = level;
2610 return ERROR_SUCCESS;
2613 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2615 static const WCHAR name[] = {'\\',0};
2616 VS_FIXEDFILEINFO *ptr, *ret;
2618 DWORD versize, handle;
2621 TRACE("%s\n", debugstr_w(filename));
2623 versize = GetFileVersionInfoSizeW( filename, &handle );
2627 version = msi_alloc( versize );
2631 GetFileVersionInfoW( filename, 0, versize, version );
2633 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2635 msi_free( version );
2639 ret = msi_alloc( sz );
2640 memcpy( ret, ptr, sz );
2642 msi_free( version );
2646 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2650 msi_parse_version_string( version, &ms, &ls );
2652 if (fi->dwFileVersionMS > ms) return 1;
2653 else if (fi->dwFileVersionMS < ms) return -1;
2654 else if (fi->dwFileVersionLS > ls) return 1;
2655 else if (fi->dwFileVersionLS < ls) return -1;
2659 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2663 msi_parse_version_string( ver1, &ms1, NULL );
2664 msi_parse_version_string( ver2, &ms2, NULL );
2666 if (ms1 > ms2) return 1;
2667 else if (ms1 < ms2) return -1;
2671 DWORD msi_get_disk_file_size( LPCWSTR filename )
2676 TRACE("%s\n", debugstr_w(filename));
2678 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2679 if (file == INVALID_HANDLE_VALUE)
2680 return INVALID_FILE_SIZE;
2682 size = GetFileSize( file, NULL );
2683 CloseHandle( file );
2687 BOOL msi_file_hash_matches( MSIFILE *file )
2690 MSIFILEHASHINFO hash;
2692 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2693 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2694 if (r != ERROR_SUCCESS)
2697 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2700 static WCHAR *get_temp_dir( void )
2703 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2705 GetTempPathW( MAX_PATH, tmp );
2708 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2709 if (CreateDirectoryW( dir, NULL )) break;
2711 return strdupW( dir );
2714 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2716 MSIASSEMBLY *assembly = file->Component->assembly;
2718 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2720 msi_free( file->TargetPath );
2721 if (assembly && !assembly->application)
2723 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2724 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2725 track_tempfile( package, file->TargetPath );
2729 WCHAR *dir = resolve_target_folder( package, file->Component->Directory, FALSE, TRUE, NULL );
2730 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2734 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2737 static UINT calculate_file_cost( MSIPACKAGE *package )
2739 VS_FIXEDFILEINFO *file_version;
2740 WCHAR *font_version;
2743 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2745 MSICOMPONENT *comp = file->Component;
2748 if (!comp->Enabled) continue;
2750 if (file->IsCompressed)
2751 comp->ForceLocalState = TRUE;
2753 set_target_path( package, file );
2755 if ((comp->assembly && !comp->assembly->installed) ||
2756 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2758 comp->Cost += file->FileSize;
2761 file_size = msi_get_disk_file_size( file->TargetPath );
2765 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2767 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2769 comp->Cost += file->FileSize - file_size;
2771 msi_free( file_version );
2774 else if ((font_version = font_version_from_file( file->TargetPath )))
2776 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2778 comp->Cost += file->FileSize - file_size;
2780 msi_free( font_version );
2784 if (file_size != file->FileSize)
2786 comp->Cost += file->FileSize - file_size;
2789 return ERROR_SUCCESS;
2793 * A lot is done in this function aside from just the costing.
2794 * The costing needs to be implemented at some point but for now I am going
2795 * to focus on the directory building
2798 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2800 static const WCHAR ExecSeqQuery[] =
2801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2802 '`','D','i','r','e','c','t','o','r','y','`',0};
2803 static const WCHAR ConditionQuery[] =
2804 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2805 '`','C','o','n','d','i','t','i','o','n','`',0};
2806 static const WCHAR szlevel[] =
2807 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2808 static const WCHAR szOutOfDiskSpace[] =
2809 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2811 UINT rc = ERROR_SUCCESS;
2815 TRACE("Building Directory properties\n");
2817 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2818 if (rc == ERROR_SUCCESS)
2820 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2822 msiobj_release(&view->hdr);
2825 TRACE("Evaluating component conditions\n");
2826 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2828 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2830 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2831 comp->Enabled = FALSE;
2834 comp->Enabled = TRUE;
2837 /* read components states from the registry */
2838 ACTION_GetComponentInstallStates(package);
2839 ACTION_GetFeatureInstallStates(package);
2841 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2843 TRACE("Evaluating feature conditions\n");
2845 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2846 if (rc == ERROR_SUCCESS)
2848 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2849 msiobj_release( &view->hdr );
2853 TRACE("Calculating file cost\n");
2854 calculate_file_cost( package );
2856 msi_set_property( package->db, szCostingComplete, szOne );
2857 /* set default run level if not set */
2858 level = msi_dup_property( package->db, szlevel );
2860 msi_set_property( package->db, szlevel, szOne );
2863 /* FIXME: check volume disk space */
2864 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2866 return MSI_SetFeatureStates(package);
2869 /* OK this value is "interpreted" and then formatted based on the
2870 first few characters */
2871 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2876 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2882 LPWSTR deformated = NULL;
2885 deformat_string(package, &value[2], &deformated);
2887 /* binary value type */
2891 *size = (strlenW(ptr)/2)+1;
2893 *size = strlenW(ptr)/2;
2895 data = msi_alloc(*size);
2901 /* if uneven pad with a zero in front */
2907 data[count] = (BYTE)strtol(byte,NULL,0);
2909 TRACE("Uneven byte count\n");
2917 data[count] = (BYTE)strtol(byte,NULL,0);
2920 msi_free(deformated);
2922 TRACE("Data %i bytes(%i)\n",*size,count);
2929 deformat_string(package, &value[1], &deformated);
2932 *size = sizeof(DWORD);
2933 data = msi_alloc(*size);
2939 if ( (*p < '0') || (*p > '9') )
2945 if (deformated[0] == '-')
2948 TRACE("DWORD %i\n",*(LPDWORD)data);
2950 msi_free(deformated);
2955 static const WCHAR szMulti[] = {'[','~',']',0};
2964 *type=REG_EXPAND_SZ;
2972 if (strstrW(value, szMulti))
2973 *type = REG_MULTI_SZ;
2975 /* remove initial delimiter */
2976 if (!strncmpW(value, szMulti, 3))
2979 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2981 /* add double NULL terminator */
2982 if (*type == REG_MULTI_SZ)
2984 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2985 data = msi_realloc_zero(data, *size);
2991 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2998 if (msi_get_property_int( package->db, szAllUsers, 0 ))
3000 *root_key = HKEY_LOCAL_MACHINE;
3005 *root_key = HKEY_CURRENT_USER;
3010 *root_key = HKEY_CLASSES_ROOT;
3014 *root_key = HKEY_CURRENT_USER;
3018 *root_key = HKEY_LOCAL_MACHINE;
3022 *root_key = HKEY_USERS;
3026 ERR("Unknown root %i\n", root);
3033 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
3035 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
3036 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
3038 if (is_64bit && package->platform == PLATFORM_INTEL &&
3039 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
3044 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
3045 if (!(path_32node = msi_alloc( size ))) return NULL;
3047 memcpy( path_32node, path, len * sizeof(WCHAR) );
3048 strcpyW( path_32node + len, szWow6432Node );
3049 strcatW( path_32node, szBackSlash );
3050 strcatW( path_32node, path + len );
3054 return strdupW( path );
3057 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
3059 MSIPACKAGE *package = param;
3060 LPSTR value_data = NULL;
3061 HKEY root_key, hkey;
3063 LPWSTR deformated, uikey, keypath;
3064 LPCWSTR szRoot, component, name, key, value;
3068 BOOL check_first = FALSE;
3071 ui_progress(package,2,0,0,0);
3073 component = MSI_RecordGetString(row, 6);
3074 comp = get_loaded_component(package,component);
3076 return ERROR_SUCCESS;
3080 TRACE("component is disabled\n");
3081 return ERROR_SUCCESS;
3084 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3086 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3087 comp->Action = comp->Installed;
3088 return ERROR_SUCCESS;
3090 comp->Action = INSTALLSTATE_LOCAL;
3092 name = MSI_RecordGetString(row, 4);
3093 if( MSI_RecordIsNull(row,5) && name )
3095 /* null values can have special meanings */
3096 if (name[0]=='-' && name[1] == 0)
3097 return ERROR_SUCCESS;
3098 else if ((name[0]=='+' && name[1] == 0) ||
3099 (name[0] == '*' && name[1] == 0))
3104 root = MSI_RecordGetInteger(row,2);
3105 key = MSI_RecordGetString(row, 3);
3107 szRoot = get_root_key( package, root, &root_key );
3109 return ERROR_SUCCESS;
3111 deformat_string(package, key , &deformated);
3112 size = strlenW(deformated) + strlenW(szRoot) + 1;
3113 uikey = msi_alloc(size*sizeof(WCHAR));
3114 strcpyW(uikey,szRoot);
3115 strcatW(uikey,deformated);
3117 keypath = get_keypath( package, root_key, deformated );
3118 msi_free( deformated );
3119 if (RegCreateKeyW( root_key, keypath, &hkey ))
3121 ERR("Could not create key %s\n", debugstr_w(keypath));
3124 return ERROR_SUCCESS;
3127 value = MSI_RecordGetString(row,5);
3129 value_data = parse_value(package, value, &type, &size);
3132 value_data = (LPSTR)strdupW(szEmpty);
3133 size = sizeof(szEmpty);
3137 deformat_string(package, name, &deformated);
3141 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
3143 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
3148 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
3149 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
3151 TRACE("value %s of %s checked already exists\n",
3152 debugstr_w(deformated), debugstr_w(uikey));
3156 TRACE("Checked and setting value %s of %s\n",
3157 debugstr_w(deformated), debugstr_w(uikey));
3158 if (deformated || size)
3159 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
3164 uirow = MSI_CreateRecord(3);
3165 MSI_RecordSetStringW(uirow,2,deformated);
3166 MSI_RecordSetStringW(uirow,1,uikey);
3167 if (type == REG_SZ || type == REG_EXPAND_SZ)
3168 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3169 ui_actiondata(package,szWriteRegistryValues,uirow);
3170 msiobj_release( &uirow->hdr );
3172 msi_free(value_data);
3173 msi_free(deformated);
3177 return ERROR_SUCCESS;
3180 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3184 static const WCHAR ExecSeqQuery[] =
3185 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3186 '`','R','e','g','i','s','t','r','y','`',0 };
3188 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3189 if (rc != ERROR_SUCCESS)
3190 return ERROR_SUCCESS;
3192 /* increment progress bar each time action data is sent */
3193 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3195 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
3197 msiobj_release(&view->hdr);
3201 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
3205 DWORD num_subkeys, num_values;
3209 if ((res = RegDeleteTreeW( hkey_root, key )))
3211 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
3216 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
3218 if ((res = RegDeleteValueW( hkey, value )))
3220 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
3222 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
3223 NULL, NULL, NULL, NULL );
3224 RegCloseKey( hkey );
3225 if (!res && !num_subkeys && !num_values)
3227 TRACE("Removing empty key %s\n", debugstr_w(key));
3228 RegDeleteKeyW( hkey_root, key );
3232 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
3236 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
3238 MSIPACKAGE *package = param;
3239 LPCWSTR component, name, key_str, root_key_str;
3240 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3243 BOOL delete_key = FALSE;
3248 ui_progress( package, 2, 0, 0, 0 );
3250 component = MSI_RecordGetString( row, 6 );
3251 comp = get_loaded_component( package, component );
3253 return ERROR_SUCCESS;
3257 TRACE("component is disabled\n");
3258 return ERROR_SUCCESS;
3261 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3263 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
3264 comp->Action = comp->Installed;
3265 return ERROR_SUCCESS;
3267 comp->Action = INSTALLSTATE_ABSENT;
3269 name = MSI_RecordGetString( row, 4 );
3270 if (MSI_RecordIsNull( row, 5 ) && name )
3272 if (name[0] == '+' && !name[1])
3273 return ERROR_SUCCESS;
3274 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
3281 root = MSI_RecordGetInteger( row, 2 );
3282 key_str = MSI_RecordGetString( row, 3 );
3284 root_key_str = get_root_key( package, root, &hkey_root );
3286 return ERROR_SUCCESS;
3288 deformat_string( package, key_str, &deformated_key );
3289 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3290 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3291 strcpyW( ui_key_str, root_key_str );
3292 strcatW( ui_key_str, deformated_key );
3294 deformat_string( package, name, &deformated_name );
3296 keypath = get_keypath( package, hkey_root, deformated_key );
3297 msi_free( deformated_key );
3298 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
3299 msi_free( keypath );
3301 uirow = MSI_CreateRecord( 2 );
3302 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3303 MSI_RecordSetStringW( uirow, 2, deformated_name );
3305 ui_actiondata( package, szRemoveRegistryValues, uirow );
3306 msiobj_release( &uirow->hdr );
3308 msi_free( ui_key_str );
3309 msi_free( deformated_name );
3310 return ERROR_SUCCESS;
3313 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
3315 MSIPACKAGE *package = param;
3316 LPCWSTR component, name, key_str, root_key_str;
3317 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3320 BOOL delete_key = FALSE;
3325 ui_progress( package, 2, 0, 0, 0 );
3327 component = MSI_RecordGetString( row, 5 );
3328 comp = get_loaded_component( package, component );
3330 return ERROR_SUCCESS;
3334 TRACE("component is disabled\n");
3335 return ERROR_SUCCESS;
3338 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3340 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3341 comp->Action = comp->Installed;
3342 return ERROR_SUCCESS;
3344 comp->Action = INSTALLSTATE_LOCAL;
3346 if ((name = MSI_RecordGetString( row, 4 )))
3348 if (name[0] == '-' && !name[1])
3355 root = MSI_RecordGetInteger( row, 2 );
3356 key_str = MSI_RecordGetString( row, 3 );
3358 root_key_str = get_root_key( package, root, &hkey_root );
3360 return ERROR_SUCCESS;
3362 deformat_string( package, key_str, &deformated_key );
3363 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3364 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3365 strcpyW( ui_key_str, root_key_str );
3366 strcatW( ui_key_str, deformated_key );
3368 deformat_string( package, name, &deformated_name );
3370 keypath = get_keypath( package, hkey_root, deformated_key );
3371 msi_free( deformated_key );
3372 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
3373 msi_free( keypath );
3375 uirow = MSI_CreateRecord( 2 );
3376 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3377 MSI_RecordSetStringW( uirow, 2, deformated_name );
3379 ui_actiondata( package, szRemoveRegistryValues, uirow );
3380 msiobj_release( &uirow->hdr );
3382 msi_free( ui_key_str );
3383 msi_free( deformated_name );
3384 return ERROR_SUCCESS;
3387 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3391 static const WCHAR registry_query[] =
3392 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3393 '`','R','e','g','i','s','t','r','y','`',0 };
3394 static const WCHAR remove_registry_query[] =
3395 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3396 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
3398 /* increment progress bar each time action data is sent */
3399 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
3401 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3402 if (rc == ERROR_SUCCESS)
3404 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3405 msiobj_release( &view->hdr );
3406 if (rc != ERROR_SUCCESS)
3410 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3411 if (rc == ERROR_SUCCESS)
3413 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3414 msiobj_release( &view->hdr );
3415 if (rc != ERROR_SUCCESS)
3419 return ERROR_SUCCESS;
3422 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3424 package->script->CurrentlyScripting = TRUE;
3426 return ERROR_SUCCESS;
3430 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3435 static const WCHAR q1[]=
3436 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3437 '`','R','e','g','i','s','t','r','y','`',0};
3440 MSIFEATURE *feature;
3443 TRACE("InstallValidate\n");
3445 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3446 if (rc == ERROR_SUCCESS)
3448 MSI_IterateRecords( view, &progress, NULL, package );
3449 msiobj_release( &view->hdr );
3450 total += progress * REG_PROGRESS_VALUE;
3453 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3454 total += COMPONENT_PROGRESS_VALUE;
3456 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3457 total += file->FileSize;
3459 ui_progress(package,0,total,0,0);
3461 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3463 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3464 debugstr_w(feature->Feature), feature->Installed,
3465 feature->ActionRequest, feature->Action);
3468 return ERROR_SUCCESS;
3471 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3473 MSIPACKAGE* package = param;
3474 LPCWSTR cond = NULL;
3475 LPCWSTR message = NULL;
3478 static const WCHAR title[]=
3479 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3481 cond = MSI_RecordGetString(row,1);
3483 r = MSI_EvaluateConditionW(package,cond);
3484 if (r == MSICONDITION_FALSE)
3486 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3489 message = MSI_RecordGetString(row,2);
3490 deformat_string(package,message,&deformated);
3491 MessageBoxW(NULL,deformated,title,MB_OK);
3492 msi_free(deformated);
3495 return ERROR_INSTALL_FAILURE;
3498 return ERROR_SUCCESS;
3501 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3504 MSIQUERY * view = NULL;
3505 static const WCHAR ExecSeqQuery[] =
3506 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3507 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3509 TRACE("Checking launch conditions\n");
3511 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3512 if (rc != ERROR_SUCCESS)
3513 return ERROR_SUCCESS;
3515 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3516 msiobj_release(&view->hdr);
3521 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3525 return resolve_target_folder( package, cmp->Directory, FALSE, TRUE, NULL );
3527 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3529 MSIRECORD * row = 0;
3531 LPWSTR deformated,buffer,deformated_name;
3533 static const WCHAR ExecSeqQuery[] =
3534 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3535 '`','R','e','g','i','s','t','r','y','`',' ',
3536 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3537 ' ','=',' ' ,'\'','%','s','\'',0 };
3538 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3539 static const WCHAR fmt2[]=
3540 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3542 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3546 root = MSI_RecordGetInteger(row,2);
3547 key = MSI_RecordGetString(row, 3);
3548 name = MSI_RecordGetString(row, 4);
3549 deformat_string(package, key , &deformated);
3550 deformat_string(package, name, &deformated_name);
3552 len = strlenW(deformated) + 6;
3553 if (deformated_name)
3554 len+=strlenW(deformated_name);
3556 buffer = msi_alloc( len *sizeof(WCHAR));
3558 if (deformated_name)
3559 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3561 sprintfW(buffer,fmt,root,deformated);
3563 msi_free(deformated);
3564 msi_free(deformated_name);
3565 msiobj_release(&row->hdr);
3569 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3571 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3576 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3579 return strdupW( file->TargetPath );
3584 static HKEY openSharedDLLsKey(void)
3587 static const WCHAR path[] =
3588 {'S','o','f','t','w','a','r','e','\\',
3589 'M','i','c','r','o','s','o','f','t','\\',
3590 'W','i','n','d','o','w','s','\\',
3591 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3592 'S','h','a','r','e','d','D','L','L','s',0};
3594 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3598 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3603 DWORD sz = sizeof(count);
3606 hkey = openSharedDLLsKey();
3607 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3608 if (rc != ERROR_SUCCESS)
3614 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3618 hkey = openSharedDLLsKey();
3620 msi_reg_set_val_dword( hkey, path, count );
3622 RegDeleteValueW(hkey,path);
3627 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3629 MSIFEATURE *feature;
3633 /* only refcount DLLs */
3634 if (comp->KeyPath == NULL ||
3636 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3637 comp->Attributes & msidbComponentAttributesODBCDataSource)
3641 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3642 write = (count > 0);
3644 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3648 /* increment counts */
3649 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3653 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3656 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3658 if ( cl->component == comp )
3663 /* decrement counts */
3664 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3668 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3671 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3673 if ( cl->component == comp )
3678 /* ref count all the files in the component */
3683 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3685 if (file->Component == comp)
3686 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3690 /* add a count for permanent */
3691 if (comp->Attributes & msidbComponentAttributesPermanent)
3694 comp->RefCount = count;
3697 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3700 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3702 WCHAR squished_pc[GUID_SIZE];
3703 WCHAR squished_cc[GUID_SIZE];
3710 squash_guid(package->ProductCode,squished_pc);
3711 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3713 msi_set_sourcedir_props(package, FALSE);
3715 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3719 ui_progress(package,2,0,0,0);
3720 if (!comp->ComponentId)
3723 squash_guid(comp->ComponentId,squished_cc);
3725 msi_free(comp->FullKeypath);
3728 const WCHAR prefixW[] = {'<','\\',0};
3729 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3731 comp->FullKeypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3732 if (comp->FullKeypath)
3734 strcpyW( comp->FullKeypath, prefixW );
3735 strcatW( comp->FullKeypath, comp->assembly->display_name );
3738 else comp->FullKeypath = resolve_keypath( package, comp );
3740 ACTION_RefCountComponent( package, comp );
3742 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3743 debugstr_w(comp->Component),
3744 debugstr_w(squished_cc),
3745 debugstr_w(comp->FullKeypath),
3747 comp->ActionRequest);
3749 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3750 comp->ActionRequest == INSTALLSTATE_SOURCE)
3752 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3753 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3755 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3757 if (rc != ERROR_SUCCESS)
3760 if (comp->Attributes & msidbComponentAttributesPermanent)
3762 static const WCHAR szPermKey[] =
3763 { '0','0','0','0','0','0','0','0','0','0','0','0',
3764 '0','0','0','0','0','0','0','0','0','0','0','0',
3765 '0','0','0','0','0','0','0','0',0 };
3767 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3770 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3771 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3777 WCHAR source[MAX_PATH];
3778 WCHAR base[MAX_PATH];
3781 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3782 static const WCHAR query[] = {
3783 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3784 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3785 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3786 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3787 '`','D','i','s','k','I','d','`',0};
3789 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3792 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3793 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3794 ptr2 = strrchrW(source, '\\') + 1;
3795 msiobj_release(&row->hdr);
3797 lstrcpyW(base, package->PackagePath);
3798 ptr = strrchrW(base, '\\');
3801 sourcepath = resolve_file_source(package, file);
3802 ptr = sourcepath + lstrlenW(base);
3803 lstrcpyW(ptr2, ptr);
3804 msi_free(sourcepath);
3806 msi_reg_set_val_str(hkey, squished_pc, source);
3810 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3812 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3813 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3815 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3817 comp->Action = comp->ActionRequest;
3820 uirow = MSI_CreateRecord(3);
3821 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3822 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3823 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3824 ui_actiondata(package,szProcessComponents,uirow);
3825 msiobj_release( &uirow->hdr );
3828 return ERROR_SUCCESS;
3839 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3840 LPWSTR lpszName, LONG_PTR lParam)
3843 typelib_struct *tl_struct = (typelib_struct*) lParam;
3844 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3848 if (!IS_INTRESOURCE(lpszName))
3850 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3854 sz = strlenW(tl_struct->source)+4;
3855 sz *= sizeof(WCHAR);
3857 if ((INT_PTR)lpszName == 1)
3858 tl_struct->path = strdupW(tl_struct->source);
3861 tl_struct->path = msi_alloc(sz);
3862 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3865 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3866 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3869 msi_free(tl_struct->path);
3870 tl_struct->path = NULL;
3875 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3876 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3878 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3882 msi_free(tl_struct->path);
3883 tl_struct->path = NULL;
3885 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3886 ITypeLib_Release(tl_struct->ptLib);
3891 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3893 MSIPACKAGE* package = param;
3897 typelib_struct tl_struct;
3902 component = MSI_RecordGetString(row,3);
3903 comp = get_loaded_component(package,component);
3905 return ERROR_SUCCESS;
3909 TRACE("component is disabled\n");
3910 return ERROR_SUCCESS;
3913 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3915 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3916 comp->Action = comp->Installed;
3917 return ERROR_SUCCESS;
3919 comp->Action = INSTALLSTATE_LOCAL;
3921 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3923 TRACE("component has no key path\n");
3924 return ERROR_SUCCESS;
3926 ui_actiondata( package, szRegisterTypeLibraries, row );
3928 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3932 guid = MSI_RecordGetString(row,1);
3933 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3934 tl_struct.source = strdupW( file->TargetPath );
3935 tl_struct.path = NULL;
3937 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3938 (LONG_PTR)&tl_struct);
3946 helpid = MSI_RecordGetString(row,6);
3948 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3949 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3953 ERR("Failed to register type library %s\n",
3954 debugstr_w(tl_struct.path));
3956 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3958 ITypeLib_Release(tl_struct.ptLib);
3959 msi_free(tl_struct.path);
3962 ERR("Failed to load type library %s\n",
3963 debugstr_w(tl_struct.source));
3965 FreeLibrary(module);
3966 msi_free(tl_struct.source);
3970 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3973 ERR("Failed to load type library: %08x\n", hr);
3974 return ERROR_INSTALL_FAILURE;
3977 ITypeLib_Release(tlib);
3980 return ERROR_SUCCESS;
3983 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3986 * OK this is a bit confusing.. I am given a _Component key and I believe
3987 * that the file that is being registered as a type library is the "key file
3988 * of that component" which I interpret to mean "The file in the KeyPath of
3993 static const WCHAR Query[] =
3994 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3995 '`','T','y','p','e','L','i','b','`',0};
3997 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3998 if (rc != ERROR_SUCCESS)
3999 return ERROR_SUCCESS;
4001 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
4002 msiobj_release(&view->hdr);
4006 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
4008 MSIPACKAGE *package = param;
4009 LPCWSTR component, guid;
4017 component = MSI_RecordGetString( row, 3 );
4018 comp = get_loaded_component( package, component );
4020 return ERROR_SUCCESS;
4024 TRACE("component is disabled\n");
4025 return ERROR_SUCCESS;
4028 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4030 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4031 comp->Action = comp->Installed;
4032 return ERROR_SUCCESS;
4034 comp->Action = INSTALLSTATE_ABSENT;
4036 ui_actiondata( package, szUnregisterTypeLibraries, row );
4038 guid = MSI_RecordGetString( row, 1 );
4039 CLSIDFromString( (LPCWSTR)guid, &libid );
4040 version = MSI_RecordGetInteger( row, 4 );
4041 language = MSI_RecordGetInteger( row, 2 );
4044 syskind = SYS_WIN64;
4046 syskind = SYS_WIN32;
4049 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
4052 WARN("Failed to unregister typelib: %08x\n", hr);
4055 return ERROR_SUCCESS;
4058 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
4062 static const WCHAR query[] =
4063 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4064 '`','T','y','p','e','L','i','b','`',0};
4066 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4067 if (rc != ERROR_SUCCESS)
4068 return ERROR_SUCCESS;
4070 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
4071 msiobj_release( &view->hdr );
4075 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
4077 static const WCHAR szlnk[] = {'.','l','n','k',0};
4078 LPCWSTR directory, extension;
4079 LPWSTR link_folder, link_file, filename;
4081 directory = MSI_RecordGetString( row, 2 );
4082 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
4084 /* may be needed because of a bug somewhere else */
4085 create_full_pathW( link_folder );
4087 filename = msi_dup_record_field( row, 3 );
4088 reduce_to_longfilename( filename );
4090 extension = strchrW( filename, '.' );
4091 if (!extension || strcmpiW( extension, szlnk ))
4093 int len = strlenW( filename );
4094 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
4095 memcpy( filename + len, szlnk, sizeof(szlnk) );
4097 link_file = build_directory_name( 2, link_folder, filename );
4098 msi_free( link_folder );
4099 msi_free( filename );
4104 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
4106 MSIPACKAGE *package = param;
4107 LPWSTR link_file, deformated, path;
4108 LPCWSTR component, target;
4110 IShellLinkW *sl = NULL;
4111 IPersistFile *pf = NULL;
4114 component = MSI_RecordGetString(row, 4);
4115 comp = get_loaded_component(package, component);
4117 return ERROR_SUCCESS;
4121 TRACE("component is disabled\n");
4122 return ERROR_SUCCESS;
4125 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4127 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4128 comp->Action = comp->Installed;
4129 return ERROR_SUCCESS;
4131 comp->Action = INSTALLSTATE_LOCAL;
4133 ui_actiondata(package,szCreateShortcuts,row);
4135 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
4136 &IID_IShellLinkW, (LPVOID *) &sl );
4140 ERR("CLSID_ShellLink not available\n");
4144 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
4147 ERR("QueryInterface(IID_IPersistFile) failed\n");
4151 target = MSI_RecordGetString(row, 5);
4152 if (strchrW(target, '['))
4154 deformat_string(package, target, &deformated);
4155 IShellLinkW_SetPath(sl,deformated);
4156 msi_free(deformated);
4160 FIXME("poorly handled shortcut format, advertised shortcut\n");
4161 IShellLinkW_SetPath(sl,comp->FullKeypath);
4164 if (!MSI_RecordIsNull(row,6))
4166 LPCWSTR arguments = MSI_RecordGetString(row, 6);
4167 deformat_string(package, arguments, &deformated);
4168 IShellLinkW_SetArguments(sl,deformated);
4169 msi_free(deformated);
4172 if (!MSI_RecordIsNull(row,7))
4174 LPCWSTR description = MSI_RecordGetString(row, 7);
4175 IShellLinkW_SetDescription(sl, description);
4178 if (!MSI_RecordIsNull(row,8))
4179 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4181 if (!MSI_RecordIsNull(row,9))
4184 LPCWSTR icon = MSI_RecordGetString(row, 9);
4186 path = build_icon_path(package, icon);
4187 index = MSI_RecordGetInteger(row,10);
4189 /* no value means 0 */
4190 if (index == MSI_NULL_INTEGER)
4193 IShellLinkW_SetIconLocation(sl, path, index);
4197 if (!MSI_RecordIsNull(row,11))
4198 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4200 if (!MSI_RecordIsNull(row,12))
4202 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
4203 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
4205 IShellLinkW_SetWorkingDirectory(sl, path);
4209 link_file = get_link_file(package, row);
4211 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
4212 IPersistFile_Save(pf, link_file, FALSE);
4214 msi_free(link_file);
4218 IPersistFile_Release( pf );
4220 IShellLinkW_Release( sl );
4222 return ERROR_SUCCESS;
4225 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
4230 static const WCHAR Query[] =
4231 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4232 '`','S','h','o','r','t','c','u','t','`',0};
4234 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4235 if (rc != ERROR_SUCCESS)
4236 return ERROR_SUCCESS;
4238 res = CoInitialize( NULL );
4240 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
4241 msiobj_release(&view->hdr);
4249 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
4251 MSIPACKAGE *package = param;
4256 component = MSI_RecordGetString( row, 4 );
4257 comp = get_loaded_component( package, component );
4259 return ERROR_SUCCESS;
4263 TRACE("component is disabled\n");
4264 return ERROR_SUCCESS;
4267 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4269 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4270 comp->Action = comp->Installed;
4271 return ERROR_SUCCESS;
4273 comp->Action = INSTALLSTATE_ABSENT;
4275 ui_actiondata( package, szRemoveShortcuts, row );
4277 link_file = get_link_file( package, row );
4279 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
4280 if (!DeleteFileW( link_file ))
4282 WARN("Failed to remove shortcut file %u\n", GetLastError());
4284 msi_free( link_file );
4286 return ERROR_SUCCESS;
4289 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4293 static const WCHAR query[] =
4294 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4295 '`','S','h','o','r','t','c','u','t','`',0};
4297 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4298 if (rc != ERROR_SUCCESS)
4299 return ERROR_SUCCESS;
4301 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
4302 msiobj_release( &view->hdr );
4307 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
4309 MSIPACKAGE* package = param;
4317 FileName = MSI_RecordGetString(row,1);
4320 ERR("Unable to get FileName\n");
4321 return ERROR_SUCCESS;
4324 FilePath = build_icon_path(package,FileName);
4326 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4328 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4329 FILE_ATTRIBUTE_NORMAL, NULL);
4331 if (the_file == INVALID_HANDLE_VALUE)
4333 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4335 return ERROR_SUCCESS;
4342 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4343 if (rc != ERROR_SUCCESS)
4345 ERR("Failed to get stream\n");
4346 CloseHandle(the_file);
4347 DeleteFileW(FilePath);
4350 WriteFile(the_file,buffer,sz,&write,NULL);
4351 } while (sz == 1024);
4354 CloseHandle(the_file);
4356 return ERROR_SUCCESS;
4359 static UINT msi_publish_icons(MSIPACKAGE *package)
4364 static const WCHAR query[]= {
4365 'S','E','L','E','C','T',' ','*',' ',
4366 'F','R','O','M',' ','`','I','c','o','n','`',0};
4368 r = MSI_DatabaseOpenViewW(package->db, query, &view);
4369 if (r == ERROR_SUCCESS)
4371 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
4372 msiobj_release(&view->hdr);
4375 return ERROR_SUCCESS;
4378 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
4384 MSISOURCELISTINFO *info;
4386 r = RegCreateKeyW(hkey, szSourceList, &source);
4387 if (r != ERROR_SUCCESS)
4390 RegCloseKey(source);
4392 buffer = strrchrW(package->PackagePath, '\\') + 1;
4393 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4394 package->Context, MSICODE_PRODUCT,
4395 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4396 if (r != ERROR_SUCCESS)
4399 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4400 package->Context, MSICODE_PRODUCT,
4401 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4402 if (r != ERROR_SUCCESS)
4405 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4406 package->Context, MSICODE_PRODUCT,
4407 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4408 if (r != ERROR_SUCCESS)
4411 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4413 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4414 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4415 info->options, info->value);
4417 MsiSourceListSetInfoW(package->ProductCode, NULL,
4418 info->context, info->options,
4419 info->property, info->value);
4422 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4424 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4425 disk->context, disk->options,
4426 disk->disk_id, disk->volume_label, disk->disk_prompt);
4429 return ERROR_SUCCESS;
4432 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4434 MSIHANDLE hdb, suminfo;
4435 WCHAR guids[MAX_PATH];
4436 WCHAR packcode[SQUISH_GUID_SIZE];
4443 static const WCHAR szProductLanguage[] =
4444 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4445 static const WCHAR szARPProductIcon[] =
4446 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4447 static const WCHAR szProductVersion[] =
4448 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4449 static const WCHAR szAssignment[] =
4450 {'A','s','s','i','g','n','m','e','n','t',0};
4451 static const WCHAR szAdvertiseFlags[] =
4452 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4453 static const WCHAR szClients[] =
4454 {'C','l','i','e','n','t','s',0};
4455 static const WCHAR szColon[] = {':',0};
4457 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4458 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4461 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4462 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4465 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4467 buffer = msi_dup_property(package->db, szARPProductIcon);
4470 LPWSTR path = build_icon_path(package,buffer);
4471 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4476 buffer = msi_dup_property(package->db, szProductVersion);
4479 DWORD verdword = msi_version_str_to_dword(buffer);
4480 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4484 msi_reg_set_val_dword(hkey, szAssignment, 0);
4485 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4486 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4487 msi_reg_set_val_str(hkey, szClients, szColon);
4489 hdb = alloc_msihandle(&package->db->hdr);
4491 return ERROR_NOT_ENOUGH_MEMORY;
4493 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4494 MsiCloseHandle(hdb);
4495 if (r != ERROR_SUCCESS)
4499 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4500 NULL, guids, &size);
4501 if (r != ERROR_SUCCESS)
4504 ptr = strchrW(guids, ';');
4506 squash_guid(guids, packcode);
4507 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4510 MsiCloseHandle(suminfo);
4511 return ERROR_SUCCESS;
4514 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4519 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4521 upgrade = msi_dup_property(package->db, szUpgradeCode);
4523 return ERROR_SUCCESS;
4525 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4526 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4528 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4530 if (r != ERROR_SUCCESS)
4532 WARN("failed to open upgrade code key\n");
4534 return ERROR_SUCCESS;
4536 squash_guid(package->ProductCode, squashed_pc);
4537 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4540 return ERROR_SUCCESS;
4543 static BOOL msi_check_publish(MSIPACKAGE *package)
4545 MSIFEATURE *feature;
4547 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4549 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4556 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4558 MSIFEATURE *feature;
4560 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4562 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4569 static UINT msi_publish_patches( MSIPACKAGE *package )
4571 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4572 WCHAR patch_squashed[GUID_SIZE];
4573 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4575 MSIPATCHINFO *patch;
4577 WCHAR *p, *all_patches = NULL;
4580 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4581 if (r != ERROR_SUCCESS)
4582 return ERROR_FUNCTION_FAILED;
4584 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4585 if (res != ERROR_SUCCESS)
4587 r = ERROR_FUNCTION_FAILED;
4591 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4592 if (r != ERROR_SUCCESS)
4595 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4597 squash_guid( patch->patchcode, patch_squashed );
4598 len += strlenW( patch_squashed ) + 1;
4601 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4605 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4609 squash_guid( patch->patchcode, p );
4610 p += strlenW( p ) + 1;
4612 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4613 (const BYTE *)patch->transforms,
4614 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4615 if (res != ERROR_SUCCESS)
4618 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4619 if (r != ERROR_SUCCESS)
4622 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4623 (const BYTE *)patch->localfile,
4624 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4625 RegCloseKey( patch_key );
4626 if (res != ERROR_SUCCESS)
4629 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4630 if (res != ERROR_SUCCESS)
4633 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4634 RegCloseKey( patch_key );
4635 if (res != ERROR_SUCCESS)
4639 all_patches[len] = 0;
4640 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4641 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4642 if (res != ERROR_SUCCESS)
4645 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4646 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4647 if (res != ERROR_SUCCESS)
4648 r = ERROR_FUNCTION_FAILED;
4651 RegCloseKey( product_patches_key );
4652 RegCloseKey( patches_key );
4653 RegCloseKey( product_key );
4654 msi_free( all_patches );
4659 * 99% of the work done here is only done for
4660 * advertised installs. However this is where the
4661 * Icon table is processed and written out
4662 * so that is what I am going to do here.
4664 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4667 HKEY hukey = NULL, hudkey = NULL;
4670 if (!list_empty(&package->patches))
4672 rc = msi_publish_patches(package);
4673 if (rc != ERROR_SUCCESS)
4677 /* FIXME: also need to publish if the product is in advertise mode */
4678 if (!msi_check_publish(package))
4679 return ERROR_SUCCESS;
4681 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4683 if (rc != ERROR_SUCCESS)
4686 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4687 NULL, &hudkey, TRUE);
4688 if (rc != ERROR_SUCCESS)
4691 rc = msi_publish_upgrade_code(package);
4692 if (rc != ERROR_SUCCESS)
4695 rc = msi_publish_product_properties(package, hukey);
4696 if (rc != ERROR_SUCCESS)
4699 rc = msi_publish_sourcelist(package, hukey);
4700 if (rc != ERROR_SUCCESS)
4703 rc = msi_publish_icons(package);
4706 uirow = MSI_CreateRecord( 1 );
4707 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4708 ui_actiondata( package, szPublishProduct, uirow );
4709 msiobj_release( &uirow->hdr );
4712 RegCloseKey(hudkey);
4717 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4719 WCHAR *filename, *ptr, *folder, *ret;
4720 const WCHAR *dirprop;
4722 filename = msi_dup_record_field( row, 2 );
4723 if (filename && (ptr = strchrW( filename, '|' )))
4728 dirprop = MSI_RecordGetString( row, 3 );
4731 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4733 folder = msi_dup_property( package->db, dirprop );
4736 folder = msi_dup_property( package->db, szWindowsFolder );
4740 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4741 msi_free( filename );
4745 ret = build_directory_name( 2, folder, ptr );
4747 msi_free( filename );
4752 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4754 MSIPACKAGE *package = param;
4755 LPCWSTR component, section, key, value, identifier;
4756 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4761 component = MSI_RecordGetString(row, 8);
4762 comp = get_loaded_component(package,component);
4764 return ERROR_SUCCESS;
4768 TRACE("component is disabled\n");
4769 return ERROR_SUCCESS;
4772 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4774 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4775 comp->Action = comp->Installed;
4776 return ERROR_SUCCESS;
4778 comp->Action = INSTALLSTATE_LOCAL;
4780 identifier = MSI_RecordGetString(row,1);
4781 section = MSI_RecordGetString(row,4);
4782 key = MSI_RecordGetString(row,5);
4783 value = MSI_RecordGetString(row,6);
4784 action = MSI_RecordGetInteger(row,7);
4786 deformat_string(package,section,&deformated_section);
4787 deformat_string(package,key,&deformated_key);
4788 deformat_string(package,value,&deformated_value);
4790 fullname = get_ini_file_name(package, row);
4794 TRACE("Adding value %s to section %s in %s\n",
4795 debugstr_w(deformated_key), debugstr_w(deformated_section),
4796 debugstr_w(fullname));
4797 WritePrivateProfileStringW(deformated_section, deformated_key,
4798 deformated_value, fullname);
4800 else if (action == 1)
4803 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4804 returned, 10, fullname);
4805 if (returned[0] == 0)
4807 TRACE("Adding value %s to section %s in %s\n",
4808 debugstr_w(deformated_key), debugstr_w(deformated_section),
4809 debugstr_w(fullname));
4811 WritePrivateProfileStringW(deformated_section, deformated_key,
4812 deformated_value, fullname);
4815 else if (action == 3)
4816 FIXME("Append to existing section not yet implemented\n");
4818 uirow = MSI_CreateRecord(4);
4819 MSI_RecordSetStringW(uirow,1,identifier);
4820 MSI_RecordSetStringW(uirow,2,deformated_section);
4821 MSI_RecordSetStringW(uirow,3,deformated_key);
4822 MSI_RecordSetStringW(uirow,4,deformated_value);
4823 ui_actiondata(package,szWriteIniValues,uirow);
4824 msiobj_release( &uirow->hdr );
4827 msi_free(deformated_key);
4828 msi_free(deformated_value);
4829 msi_free(deformated_section);
4830 return ERROR_SUCCESS;
4833 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4837 static const WCHAR ExecSeqQuery[] =
4838 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4839 '`','I','n','i','F','i','l','e','`',0};
4841 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4842 if (rc != ERROR_SUCCESS)
4844 TRACE("no IniFile table\n");
4845 return ERROR_SUCCESS;
4848 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4849 msiobj_release(&view->hdr);
4853 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4855 MSIPACKAGE *package = param;
4856 LPCWSTR component, section, key, value, identifier;
4857 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4862 component = MSI_RecordGetString( row, 8 );
4863 comp = get_loaded_component( package, component );
4865 return ERROR_SUCCESS;
4869 TRACE("component is disabled\n");
4870 return ERROR_SUCCESS;
4873 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4875 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4876 comp->Action = comp->Installed;
4877 return ERROR_SUCCESS;
4879 comp->Action = INSTALLSTATE_ABSENT;
4881 identifier = MSI_RecordGetString( row, 1 );
4882 section = MSI_RecordGetString( row, 4 );
4883 key = MSI_RecordGetString( row, 5 );
4884 value = MSI_RecordGetString( row, 6 );
4885 action = MSI_RecordGetInteger( row, 7 );
4887 deformat_string( package, section, &deformated_section );
4888 deformat_string( package, key, &deformated_key );
4889 deformat_string( package, value, &deformated_value );
4891 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4893 filename = get_ini_file_name( package, row );
4895 TRACE("Removing key %s from section %s in %s\n",
4896 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4898 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4900 WARN("Unable to remove key %u\n", GetLastError());
4902 msi_free( filename );
4905 FIXME("Unsupported action %d\n", action);
4908 uirow = MSI_CreateRecord( 4 );
4909 MSI_RecordSetStringW( uirow, 1, identifier );
4910 MSI_RecordSetStringW( uirow, 2, deformated_section );
4911 MSI_RecordSetStringW( uirow, 3, deformated_key );
4912 MSI_RecordSetStringW( uirow, 4, deformated_value );
4913 ui_actiondata( package, szRemoveIniValues, uirow );
4914 msiobj_release( &uirow->hdr );
4916 msi_free( deformated_key );
4917 msi_free( deformated_value );
4918 msi_free( deformated_section );
4919 return ERROR_SUCCESS;
4922 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4924 MSIPACKAGE *package = param;
4925 LPCWSTR component, section, key, value, identifier;
4926 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4931 component = MSI_RecordGetString( row, 8 );
4932 comp = get_loaded_component( package, component );
4934 return ERROR_SUCCESS;
4938 TRACE("component is disabled\n");
4939 return ERROR_SUCCESS;
4942 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4944 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4945 comp->Action = comp->Installed;
4946 return ERROR_SUCCESS;
4948 comp->Action = INSTALLSTATE_LOCAL;
4950 identifier = MSI_RecordGetString( row, 1 );
4951 section = MSI_RecordGetString( row, 4 );
4952 key = MSI_RecordGetString( row, 5 );
4953 value = MSI_RecordGetString( row, 6 );
4954 action = MSI_RecordGetInteger( row, 7 );
4956 deformat_string( package, section, &deformated_section );
4957 deformat_string( package, key, &deformated_key );
4958 deformat_string( package, value, &deformated_value );
4960 if (action == msidbIniFileActionRemoveLine)
4962 filename = get_ini_file_name( package, row );
4964 TRACE("Removing key %s from section %s in %s\n",
4965 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4967 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4969 WARN("Unable to remove key %u\n", GetLastError());
4971 msi_free( filename );
4974 FIXME("Unsupported action %d\n", action);
4976 uirow = MSI_CreateRecord( 4 );
4977 MSI_RecordSetStringW( uirow, 1, identifier );
4978 MSI_RecordSetStringW( uirow, 2, deformated_section );
4979 MSI_RecordSetStringW( uirow, 3, deformated_key );
4980 MSI_RecordSetStringW( uirow, 4, deformated_value );
4981 ui_actiondata( package, szRemoveIniValues, uirow );
4982 msiobj_release( &uirow->hdr );
4984 msi_free( deformated_key );
4985 msi_free( deformated_value );
4986 msi_free( deformated_section );
4987 return ERROR_SUCCESS;
4990 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4994 static const WCHAR query[] =
4995 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4996 '`','I','n','i','F','i','l','e','`',0};
4997 static const WCHAR remove_query[] =
4998 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4999 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
5001 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5002 if (rc == ERROR_SUCCESS)
5004 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
5005 msiobj_release( &view->hdr );
5006 if (rc != ERROR_SUCCESS)
5010 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
5011 if (rc == ERROR_SUCCESS)
5013 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
5014 msiobj_release( &view->hdr );
5015 if (rc != ERROR_SUCCESS)
5019 return ERROR_SUCCESS;
5022 static void register_dll( const WCHAR *dll, BOOL unregister )
5026 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
5029 HRESULT (WINAPI *func_ptr)( void );
5030 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
5032 func_ptr = (void *)GetProcAddress( hmod, func );
5035 HRESULT hr = func_ptr();
5037 WARN("failed to register dll 0x%08x\n", hr);
5040 WARN("entry point %s not found\n", func);
5041 FreeLibrary( hmod );
5044 WARN("failed to load library %u\n", GetLastError());
5047 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
5049 MSIPACKAGE *package = param;
5054 filename = MSI_RecordGetString(row,1);
5055 file = get_loaded_file( package, filename );
5059 ERR("Unable to find file id %s\n",debugstr_w(filename));
5060 return ERROR_SUCCESS;
5063 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
5065 register_dll( file->TargetPath, FALSE );
5067 uirow = MSI_CreateRecord( 2 );
5068 MSI_RecordSetStringW( uirow, 1, filename );
5069 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
5070 ui_actiondata( package, szSelfRegModules, uirow );
5071 msiobj_release( &uirow->hdr );
5073 return ERROR_SUCCESS;
5076 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
5080 static const WCHAR ExecSeqQuery[] =
5081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5082 '`','S','e','l','f','R','e','g','`',0};
5084 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5085 if (rc != ERROR_SUCCESS)
5087 TRACE("no SelfReg table\n");
5088 return ERROR_SUCCESS;
5091 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
5092 msiobj_release(&view->hdr);
5094 return ERROR_SUCCESS;
5097 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
5099 MSIPACKAGE *package = param;
5104 filename = MSI_RecordGetString( row, 1 );
5105 file = get_loaded_file( package, filename );
5109 ERR("Unable to find file id %s\n", debugstr_w(filename));
5110 return ERROR_SUCCESS;
5113 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
5115 register_dll( file->TargetPath, TRUE );
5117 uirow = MSI_CreateRecord( 2 );
5118 MSI_RecordSetStringW( uirow, 1, filename );
5119 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
5120 ui_actiondata( package, szSelfUnregModules, uirow );
5121 msiobj_release( &uirow->hdr );
5123 return ERROR_SUCCESS;
5126 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5130 static const WCHAR query[] =
5131 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5132 '`','S','e','l','f','R','e','g','`',0};
5134 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5135 if (rc != ERROR_SUCCESS)
5137 TRACE("no SelfReg table\n");
5138 return ERROR_SUCCESS;
5141 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
5142 msiobj_release( &view->hdr );
5144 return ERROR_SUCCESS;
5147 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
5149 MSIFEATURE *feature;
5151 HKEY hkey = NULL, userdata = NULL;
5153 if (!msi_check_publish(package))
5154 return ERROR_SUCCESS;
5156 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
5158 if (rc != ERROR_SUCCESS)
5161 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
5163 if (rc != ERROR_SUCCESS)
5166 /* here the guids are base 85 encoded */
5167 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5173 BOOL absent = FALSE;
5176 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
5177 feature->ActionRequest != INSTALLSTATE_SOURCE &&
5178 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
5181 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
5185 if (feature->Feature_Parent)
5186 size += strlenW( feature->Feature_Parent )+2;
5188 data = msi_alloc(size * sizeof(WCHAR));
5191 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
5193 MSICOMPONENT* component = cl->component;
5197 if (component->ComponentId)
5199 TRACE("From %s\n",debugstr_w(component->ComponentId));
5200 CLSIDFromString(component->ComponentId, &clsid);
5201 encode_base85_guid(&clsid,buf);
5202 TRACE("to %s\n",debugstr_w(buf));
5207 if (feature->Feature_Parent)
5209 static const WCHAR sep[] = {'\2',0};
5211 strcatW(data,feature->Feature_Parent);
5214 msi_reg_set_val_str( userdata, feature->Feature, data );
5218 if (feature->Feature_Parent)
5219 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
5222 size += sizeof(WCHAR);
5223 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
5224 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
5228 size += 2*sizeof(WCHAR);
5229 data = msi_alloc(size);
5232 if (feature->Feature_Parent)
5233 strcpyW( &data[1], feature->Feature_Parent );
5234 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
5240 uirow = MSI_CreateRecord( 1 );
5241 MSI_RecordSetStringW( uirow, 1, feature->Feature );
5242 ui_actiondata( package, szPublishFeatures, uirow);
5243 msiobj_release( &uirow->hdr );
5244 /* FIXME: call ui_progress? */
5249 RegCloseKey(userdata);
5253 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
5259 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
5261 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
5263 if (r == ERROR_SUCCESS)
5265 RegDeleteValueW(hkey, feature->Feature);
5269 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
5271 if (r == ERROR_SUCCESS)
5273 RegDeleteValueW(hkey, feature->Feature);
5277 uirow = MSI_CreateRecord( 1 );
5278 MSI_RecordSetStringW( uirow, 1, feature->Feature );
5279 ui_actiondata( package, szUnpublishFeatures, uirow );
5280 msiobj_release( &uirow->hdr );
5282 return ERROR_SUCCESS;
5285 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
5287 MSIFEATURE *feature;
5289 if (!msi_check_unpublish(package))
5290 return ERROR_SUCCESS;
5292 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5294 msi_unpublish_feature(package, feature);
5297 return ERROR_SUCCESS;
5300 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
5304 WCHAR date[9], *val, *buffer;
5305 const WCHAR *prop, *key;
5307 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
5308 static const WCHAR szWindowsInstaller[] =
5309 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
5310 static const WCHAR modpath_fmt[] =
5311 {'M','s','i','E','x','e','c','.','e','x','e',' ',
5312 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
5313 static const WCHAR szModifyPath[] =
5314 {'M','o','d','i','f','y','P','a','t','h',0};
5315 static const WCHAR szUninstallString[] =
5316 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5317 static const WCHAR szEstimatedSize[] =
5318 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5319 static const WCHAR szProductLanguage[] =
5320 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
5321 static const WCHAR szProductVersion[] =
5322 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
5323 static const WCHAR szDisplayVersion[] =
5324 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5325 static const WCHAR szInstallSource[] =
5326 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5327 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
5328 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5329 static const WCHAR szAuthorizedCDFPrefix[] =
5330 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5331 static const WCHAR szARPCONTACT[] =
5332 {'A','R','P','C','O','N','T','A','C','T',0};
5333 static const WCHAR szContact[] =
5334 {'C','o','n','t','a','c','t',0};
5335 static const WCHAR szARPCOMMENTS[] =
5336 {'A','R','P','C','O','M','M','E','N','T','S',0};
5337 static const WCHAR szComments[] =
5338 {'C','o','m','m','e','n','t','s',0};
5339 static const WCHAR szProductName[] =
5340 {'P','r','o','d','u','c','t','N','a','m','e',0};
5341 static const WCHAR szDisplayName[] =
5342 {'D','i','s','p','l','a','y','N','a','m','e',0};
5343 static const WCHAR szARPHELPLINK[] =
5344 {'A','R','P','H','E','L','P','L','I','N','K',0};
5345 static const WCHAR szHelpLink[] =
5346 {'H','e','l','p','L','i','n','k',0};
5347 static const WCHAR szARPHELPTELEPHONE[] =
5348 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5349 static const WCHAR szHelpTelephone[] =
5350 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5351 static const WCHAR szARPINSTALLLOCATION[] =
5352 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5353 static const WCHAR szInstallLocation[] =
5354 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
5355 static const WCHAR szManufacturer[] =
5356 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5357 static const WCHAR szPublisher[] =
5358 {'P','u','b','l','i','s','h','e','r',0};
5359 static const WCHAR szARPREADME[] =
5360 {'A','R','P','R','E','A','D','M','E',0};
5361 static const WCHAR szReadme[] =
5362 {'R','e','a','d','M','e',0};
5363 static const WCHAR szARPSIZE[] =
5364 {'A','R','P','S','I','Z','E',0};
5365 static const WCHAR szSize[] =
5366 {'S','i','z','e',0};
5367 static const WCHAR szARPURLINFOABOUT[] =
5368 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5369 static const WCHAR szURLInfoAbout[] =
5370 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5371 static const WCHAR szARPURLUPDATEINFO[] =
5372 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5373 static const WCHAR szURLUpdateInfo[] =
5374 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5376 static const WCHAR *propval[] = {
5377 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
5378 szARPCONTACT, szContact,
5379 szARPCOMMENTS, szComments,
5380 szProductName, szDisplayName,
5381 szARPHELPLINK, szHelpLink,
5382 szARPHELPTELEPHONE, szHelpTelephone,
5383 szARPINSTALLLOCATION, szInstallLocation,
5384 cszSourceDir, szInstallSource,
5385 szManufacturer, szPublisher,
5386 szARPREADME, szReadme,
5388 szARPURLINFOABOUT, szURLInfoAbout,
5389 szARPURLUPDATEINFO, szURLUpdateInfo,
5392 const WCHAR **p = propval;
5398 val = msi_dup_property(package->db, prop);
5399 msi_reg_set_val_str(hkey, key, val);
5403 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5405 size = deformat_string(package, modpath_fmt, &buffer);
5406 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5407 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5410 /* FIXME: Write real Estimated Size when we have it */
5411 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5413 GetLocalTime(&systime);
5414 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5415 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5417 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5418 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5420 buffer = msi_dup_property(package->db, szProductVersion);
5421 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5424 DWORD verdword = msi_version_str_to_dword(buffer);
5426 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5427 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5428 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5432 return ERROR_SUCCESS;
5435 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5437 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5439 LPWSTR upgrade_code;
5440 HKEY hkey, props, upgrade_key;
5443 /* FIXME: also need to publish if the product is in advertise mode */
5444 if (!msi_check_publish(package))
5445 return ERROR_SUCCESS;
5447 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
5448 if (rc != ERROR_SUCCESS)
5451 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5452 NULL, &props, TRUE);
5453 if (rc != ERROR_SUCCESS)
5456 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5457 msi_free( package->db->localfile );
5458 package->db->localfile = NULL;
5460 rc = msi_publish_install_properties(package, hkey);
5461 if (rc != ERROR_SUCCESS)
5464 rc = msi_publish_install_properties(package, props);
5465 if (rc != ERROR_SUCCESS)
5468 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5471 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
5472 if (rc == ERROR_SUCCESS)
5474 squash_guid( package->ProductCode, squashed_pc );
5475 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
5476 RegCloseKey( upgrade_key );
5478 msi_free( upgrade_code );
5482 uirow = MSI_CreateRecord( 1 );
5483 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5484 ui_actiondata( package, szRegisterProduct, uirow );
5485 msiobj_release( &uirow->hdr );
5488 return ERROR_SUCCESS;
5491 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5493 return execute_script(package,INSTALL_SCRIPT);
5496 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5498 WCHAR *upgrade, **features;
5499 BOOL full_uninstall = TRUE;
5500 MSIFEATURE *feature;
5501 MSIPATCHINFO *patch;
5503 static const WCHAR szUpgradeCode[] =
5504 {'U','p','g','r','a','d','e','C','o','d','e',0};
5506 features = msi_split_string(remove, ',');
5509 ERR("REMOVE feature list is empty!\n");
5510 return ERROR_FUNCTION_FAILED;
5513 if (!strcmpW( features[0], szAll ))
5514 full_uninstall = TRUE;
5517 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5519 if (feature->Action != INSTALLSTATE_ABSENT)
5520 full_uninstall = FALSE;
5525 if (!full_uninstall)
5526 return ERROR_SUCCESS;
5528 MSIREG_DeleteProductKey(package->ProductCode);
5529 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5530 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5532 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5533 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5534 MSIREG_DeleteUserProductKey(package->ProductCode);
5535 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5537 upgrade = msi_dup_property(package->db, szUpgradeCode);
5540 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5541 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5545 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5547 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5550 return ERROR_SUCCESS;
5553 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5558 /* turn off scheduling */
5559 package->script->CurrentlyScripting= FALSE;
5561 /* first do the same as an InstallExecute */
5562 rc = ACTION_InstallExecute(package);
5563 if (rc != ERROR_SUCCESS)
5566 /* then handle Commit Actions */
5567 rc = execute_script(package,COMMIT_SCRIPT);
5568 if (rc != ERROR_SUCCESS)
5571 remove = msi_dup_property(package->db, szRemove);
5573 rc = msi_unpublish_product(package, remove);
5579 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5581 static const WCHAR RunOnce[] = {
5582 'S','o','f','t','w','a','r','e','\\',
5583 'M','i','c','r','o','s','o','f','t','\\',
5584 'W','i','n','d','o','w','s','\\',
5585 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5586 'R','u','n','O','n','c','e',0};
5587 static const WCHAR InstallRunOnce[] = {
5588 'S','o','f','t','w','a','r','e','\\',
5589 'M','i','c','r','o','s','o','f','t','\\',
5590 'W','i','n','d','o','w','s','\\',
5591 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5592 'I','n','s','t','a','l','l','e','r','\\',
5593 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5595 static const WCHAR msiexec_fmt[] = {
5597 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5598 '\"','%','s','\"',0};
5599 static const WCHAR install_fmt[] = {
5600 '/','I',' ','\"','%','s','\"',' ',
5601 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5602 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5603 WCHAR buffer[256], sysdir[MAX_PATH];
5605 WCHAR squished_pc[100];
5607 squash_guid(package->ProductCode,squished_pc);
5609 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5610 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5611 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5614 msi_reg_set_val_str( hkey, squished_pc, buffer );
5617 TRACE("Reboot command %s\n",debugstr_w(buffer));
5619 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5620 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5622 msi_reg_set_val_str( hkey, squished_pc, buffer );
5625 return ERROR_INSTALL_SUSPEND;
5628 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5634 * We are currently doing what should be done here in the top level Install
5635 * however for Administrative and uninstalls this step will be needed
5637 if (!package->PackagePath)
5638 return ERROR_SUCCESS;
5640 msi_set_sourcedir_props(package, TRUE);
5642 attrib = GetFileAttributesW(package->db->path);
5643 if (attrib == INVALID_FILE_ATTRIBUTES)
5649 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5650 package->Context, MSICODE_PRODUCT,
5651 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5652 if (rc == ERROR_MORE_DATA)
5654 prompt = msi_alloc(size * sizeof(WCHAR));
5655 MsiSourceListGetInfoW(package->ProductCode, NULL,
5656 package->Context, MSICODE_PRODUCT,
5657 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5660 prompt = strdupW(package->db->path);
5662 msg = generate_error_string(package,1302,1,prompt);
5663 while(attrib == INVALID_FILE_ATTRIBUTES)
5665 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5668 rc = ERROR_INSTALL_USEREXIT;
5671 attrib = GetFileAttributesW(package->db->path);
5677 return ERROR_SUCCESS;
5682 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5685 LPWSTR buffer, productid = NULL;
5686 UINT i, rc = ERROR_SUCCESS;
5689 static const WCHAR szPropKeys[][80] =
5691 {'P','r','o','d','u','c','t','I','D',0},
5692 {'U','S','E','R','N','A','M','E',0},
5693 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5697 static const WCHAR szRegKeys[][80] =
5699 {'P','r','o','d','u','c','t','I','D',0},
5700 {'R','e','g','O','w','n','e','r',0},
5701 {'R','e','g','C','o','m','p','a','n','y',0},
5705 if (msi_check_unpublish(package))
5707 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5711 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5715 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5717 if (rc != ERROR_SUCCESS)
5720 for( i = 0; szPropKeys[i][0]; i++ )
5722 buffer = msi_dup_property( package->db, szPropKeys[i] );
5723 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5728 uirow = MSI_CreateRecord( 1 );
5729 MSI_RecordSetStringW( uirow, 1, productid );
5730 ui_actiondata( package, szRegisterUser, uirow );
5731 msiobj_release( &uirow->hdr );
5733 msi_free(productid);
5739 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5743 package->script->InWhatSequence |= SEQUENCE_EXEC;
5744 rc = ACTION_ProcessExecSequence(package,FALSE);
5749 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5751 MSIPACKAGE *package = param;
5752 LPCWSTR compgroupid, component, feature, qualifier, text;
5753 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5762 feature = MSI_RecordGetString(rec, 5);
5763 feat = get_loaded_feature(package, feature);
5765 return ERROR_SUCCESS;
5767 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5768 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5769 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5771 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5772 feat->Action = feat->Installed;
5773 return ERROR_SUCCESS;
5776 component = MSI_RecordGetString(rec, 3);
5777 comp = get_loaded_component(package, component);
5779 return ERROR_SUCCESS;
5781 compgroupid = MSI_RecordGetString(rec,1);
5782 qualifier = MSI_RecordGetString(rec,2);
5784 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5785 if (rc != ERROR_SUCCESS)
5788 advertise = create_component_advertise_string( package, comp, feature );
5789 text = MSI_RecordGetString( rec, 4 );
5792 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5793 strcpyW( p, advertise );
5795 msi_free( advertise );
5798 existing = msi_reg_get_val_str( hkey, qualifier );
5800 sz = strlenW( advertise ) + 1;
5803 for (p = existing; *p; p += len)
5805 len = strlenW( p ) + 1;
5806 if (strcmpW( advertise, p )) sz += len;
5809 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5811 rc = ERROR_OUTOFMEMORY;
5817 for (p = existing; *p; p += len)
5819 len = strlenW( p ) + 1;
5820 if (strcmpW( advertise, p ))
5822 memcpy( q, p, len * sizeof(WCHAR) );
5827 strcpyW( q, advertise );
5828 q[strlenW( q ) + 1] = 0;
5830 msi_reg_set_val_multi_str( hkey, qualifier, output );
5835 msi_free( advertise );
5836 msi_free( existing );
5839 uirow = MSI_CreateRecord( 2 );
5840 MSI_RecordSetStringW( uirow, 1, compgroupid );
5841 MSI_RecordSetStringW( uirow, 2, qualifier);
5842 ui_actiondata( package, szPublishComponents, uirow);
5843 msiobj_release( &uirow->hdr );
5844 /* FIXME: call ui_progress? */
5850 * At present I am ignorning the advertised components part of this and only
5851 * focusing on the qualified component sets
5853 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5857 static const WCHAR ExecSeqQuery[] =
5858 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5859 '`','P','u','b','l','i','s','h',
5860 'C','o','m','p','o','n','e','n','t','`',0};
5862 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5863 if (rc != ERROR_SUCCESS)
5864 return ERROR_SUCCESS;
5866 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5867 msiobj_release(&view->hdr);
5872 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5874 static const WCHAR szInstallerComponents[] = {
5875 'S','o','f','t','w','a','r','e','\\',
5876 'M','i','c','r','o','s','o','f','t','\\',
5877 'I','n','s','t','a','l','l','e','r','\\',
5878 'C','o','m','p','o','n','e','n','t','s','\\',0};
5880 MSIPACKAGE *package = param;
5881 LPCWSTR compgroupid, component, feature, qualifier;
5885 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5888 feature = MSI_RecordGetString( rec, 5 );
5889 feat = get_loaded_feature( package, feature );
5891 return ERROR_SUCCESS;
5893 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5895 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5896 feat->Action = feat->Installed;
5897 return ERROR_SUCCESS;
5900 component = MSI_RecordGetString( rec, 3 );
5901 comp = get_loaded_component( package, component );
5903 return ERROR_SUCCESS;
5905 compgroupid = MSI_RecordGetString( rec, 1 );
5906 qualifier = MSI_RecordGetString( rec, 2 );
5908 squash_guid( compgroupid, squashed );
5909 strcpyW( keypath, szInstallerComponents );
5910 strcatW( keypath, squashed );
5912 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5913 if (res != ERROR_SUCCESS)
5915 WARN("Unable to delete component key %d\n", res);
5918 uirow = MSI_CreateRecord( 2 );
5919 MSI_RecordSetStringW( uirow, 1, compgroupid );
5920 MSI_RecordSetStringW( uirow, 2, qualifier );
5921 ui_actiondata( package, szUnpublishComponents, uirow );
5922 msiobj_release( &uirow->hdr );
5924 return ERROR_SUCCESS;
5927 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5931 static const WCHAR query[] =
5932 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5933 '`','P','u','b','l','i','s','h',
5934 'C','o','m','p','o','n','e','n','t','`',0};
5936 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5937 if (rc != ERROR_SUCCESS)
5938 return ERROR_SUCCESS;
5940 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5941 msiobj_release( &view->hdr );
5946 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5948 MSIPACKAGE *package = param;
5951 SC_HANDLE hscm, service = NULL;
5953 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5954 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5955 DWORD serv_type, start_type, err_control;
5956 SERVICE_DESCRIPTIONW sd = {NULL};
5958 static const WCHAR query[] =
5959 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5960 '`','C','o','m','p','o','n','e','n','t','`',' ',
5961 'W','H','E','R','E',' ',
5962 '`','C','o','m','p','o','n','e','n','t','`',' ',
5963 '=','\'','%','s','\'',0};
5965 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5968 ERR("Failed to open the SC Manager!\n");
5972 comp = MSI_RecordGetString( rec, 12 );
5973 if (!get_loaded_component( package, comp ))
5976 start_type = MSI_RecordGetInteger(rec, 5);
5977 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5980 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5981 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5982 serv_type = MSI_RecordGetInteger(rec, 4);
5983 err_control = MSI_RecordGetInteger(rec, 6);
5984 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5985 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5986 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5987 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5988 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5989 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5991 /* fetch the service path */
5992 row = MSI_QueryGetRecord(package->db, query, comp);
5995 ERR("Control query failed!\n");
5998 key = MSI_RecordGetString(row, 6);
6000 file = get_loaded_file(package, key);
6001 msiobj_release(&row->hdr);
6004 ERR("Failed to load the service file\n");
6008 if (!args || !args[0]) image_path = file->TargetPath;
6011 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
6012 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
6013 return ERROR_OUTOFMEMORY;
6015 strcpyW(image_path, file->TargetPath);
6016 strcatW(image_path, szSpace);
6017 strcatW(image_path, args);
6019 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
6020 start_type, err_control, image_path, load_order,
6021 NULL, depends, serv_name, pass);
6025 if (GetLastError() != ERROR_SERVICE_EXISTS)
6026 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
6028 else if (sd.lpDescription)
6030 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
6031 WARN("failed to set service description %u\n", GetLastError());
6034 if (image_path != file->TargetPath) msi_free(image_path);
6036 CloseServiceHandle(service);
6037 CloseServiceHandle(hscm);
6040 msi_free(sd.lpDescription);
6041 msi_free(load_order);
6042 msi_free(serv_name);
6047 return ERROR_SUCCESS;
6050 static UINT ACTION_InstallServices( MSIPACKAGE *package )
6054 static const WCHAR ExecSeqQuery[] =
6055 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6056 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
6058 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6059 if (rc != ERROR_SUCCESS)
6060 return ERROR_SUCCESS;
6062 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
6063 msiobj_release(&view->hdr);
6068 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
6069 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
6071 LPCWSTR *vector, *temp_vector;
6075 static const WCHAR separator[] = {'[','~',']',0};
6078 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
6083 vector = msi_alloc(sizeof(LPWSTR));
6091 vector[*numargs - 1] = p;
6093 if ((q = strstrW(p, separator)))
6097 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
6103 vector = temp_vector;
6112 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
6114 MSIPACKAGE *package = param;
6117 SC_HANDLE scm = NULL, service = NULL;
6118 LPCWSTR component, *vector = NULL;
6119 LPWSTR name, args, display_name = NULL;
6120 DWORD event, numargs, len;
6121 UINT r = ERROR_FUNCTION_FAILED;
6123 component = MSI_RecordGetString(rec, 6);
6124 comp = get_loaded_component(package, component);
6126 return ERROR_SUCCESS;
6130 TRACE("component is disabled\n");
6131 return ERROR_SUCCESS;
6134 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6136 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6137 comp->Action = comp->Installed;
6138 return ERROR_SUCCESS;
6140 comp->Action = INSTALLSTATE_LOCAL;
6142 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
6143 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
6144 event = MSI_RecordGetInteger(rec, 3);
6146 if (!(event & msidbServiceControlEventStart))
6152 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
6155 ERR("Failed to open the service control manager\n");
6160 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6161 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6163 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6164 GetServiceDisplayNameW( scm, name, display_name, &len );
6167 service = OpenServiceW(scm, name, SERVICE_START);
6170 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
6174 vector = msi_service_args_to_vector(args, &numargs);
6176 if (!StartServiceW(service, numargs, vector) &&
6177 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
6179 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
6186 uirow = MSI_CreateRecord( 2 );
6187 MSI_RecordSetStringW( uirow, 1, display_name );
6188 MSI_RecordSetStringW( uirow, 2, name );
6189 ui_actiondata( package, szStartServices, uirow );
6190 msiobj_release( &uirow->hdr );
6192 CloseServiceHandle(service);
6193 CloseServiceHandle(scm);
6198 msi_free(display_name);
6202 static UINT ACTION_StartServices( MSIPACKAGE *package )
6207 static const WCHAR query[] = {
6208 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6209 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6211 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6212 if (rc != ERROR_SUCCESS)
6213 return ERROR_SUCCESS;
6215 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
6216 msiobj_release(&view->hdr);
6221 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6223 DWORD i, needed, count;
6224 ENUM_SERVICE_STATUSW *dependencies;
6228 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6229 0, &needed, &count))
6232 if (GetLastError() != ERROR_MORE_DATA)
6235 dependencies = msi_alloc(needed);
6239 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6240 needed, &needed, &count))
6243 for (i = 0; i < count; i++)
6245 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6246 SERVICE_STOP | SERVICE_QUERY_STATUS);
6250 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
6257 msi_free(dependencies);
6261 static UINT stop_service( LPCWSTR name )
6263 SC_HANDLE scm = NULL, service = NULL;
6264 SERVICE_STATUS status;
6265 SERVICE_STATUS_PROCESS ssp;
6268 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6271 WARN("Failed to open the SCM: %d\n", GetLastError());
6275 service = OpenServiceW(scm, name,
6277 SERVICE_QUERY_STATUS |
6278 SERVICE_ENUMERATE_DEPENDENTS);
6281 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
6285 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
6286 sizeof(SERVICE_STATUS_PROCESS), &needed))
6288 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
6292 if (ssp.dwCurrentState == SERVICE_STOPPED)
6295 stop_service_dependents(scm, service);
6297 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6298 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
6301 CloseServiceHandle(service);
6302 CloseServiceHandle(scm);
6304 return ERROR_SUCCESS;
6307 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6309 MSIPACKAGE *package = param;
6313 LPWSTR name = NULL, display_name = NULL;
6317 event = MSI_RecordGetInteger( rec, 3 );
6318 if (!(event & msidbServiceControlEventStop))
6319 return ERROR_SUCCESS;
6321 component = MSI_RecordGetString( rec, 6 );
6322 comp = get_loaded_component( package, component );
6324 return ERROR_SUCCESS;
6328 TRACE("component is disabled\n");
6329 return ERROR_SUCCESS;
6332 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6334 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6335 comp->Action = comp->Installed;
6336 return ERROR_SUCCESS;
6338 comp->Action = INSTALLSTATE_ABSENT;
6340 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6343 ERR("Failed to open the service control manager\n");
6348 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6349 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6351 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6352 GetServiceDisplayNameW( scm, name, display_name, &len );
6354 CloseServiceHandle( scm );
6356 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6357 stop_service( name );
6360 uirow = MSI_CreateRecord( 2 );
6361 MSI_RecordSetStringW( uirow, 1, display_name );
6362 MSI_RecordSetStringW( uirow, 2, name );
6363 ui_actiondata( package, szStopServices, uirow );
6364 msiobj_release( &uirow->hdr );
6367 msi_free( display_name );
6368 return ERROR_SUCCESS;
6371 static UINT ACTION_StopServices( MSIPACKAGE *package )
6376 static const WCHAR query[] = {
6377 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6378 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6380 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6381 if (rc != ERROR_SUCCESS)
6382 return ERROR_SUCCESS;
6384 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6385 msiobj_release(&view->hdr);
6390 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6392 MSIPACKAGE *package = param;
6396 LPWSTR name = NULL, display_name = NULL;
6398 SC_HANDLE scm = NULL, service = NULL;
6400 event = MSI_RecordGetInteger( rec, 3 );
6401 if (!(event & msidbServiceControlEventDelete))
6402 return ERROR_SUCCESS;
6404 component = MSI_RecordGetString(rec, 6);
6405 comp = get_loaded_component(package, component);
6407 return ERROR_SUCCESS;
6411 TRACE("component is disabled\n");
6412 return ERROR_SUCCESS;
6415 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6417 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6418 comp->Action = comp->Installed;
6419 return ERROR_SUCCESS;
6421 comp->Action = INSTALLSTATE_ABSENT;
6423 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6424 stop_service( name );
6426 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6429 WARN("Failed to open the SCM: %d\n", GetLastError());
6434 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6435 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6437 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6438 GetServiceDisplayNameW( scm, name, display_name, &len );
6441 service = OpenServiceW( scm, name, DELETE );
6444 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6448 if (!DeleteService( service ))
6449 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6452 uirow = MSI_CreateRecord( 2 );
6453 MSI_RecordSetStringW( uirow, 1, display_name );
6454 MSI_RecordSetStringW( uirow, 2, name );
6455 ui_actiondata( package, szDeleteServices, uirow );
6456 msiobj_release( &uirow->hdr );
6458 CloseServiceHandle( service );
6459 CloseServiceHandle( scm );
6461 msi_free( display_name );
6463 return ERROR_SUCCESS;
6466 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6471 static const WCHAR query[] = {
6472 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6473 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6475 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6476 if (rc != ERROR_SUCCESS)
6477 return ERROR_SUCCESS;
6479 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6480 msiobj_release( &view->hdr );
6485 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6487 MSIPACKAGE *package = param;
6488 LPWSTR driver, driver_path, ptr;
6489 WCHAR outpath[MAX_PATH];
6490 MSIFILE *driver_file = NULL, *setup_file = NULL;
6493 LPCWSTR desc, file_key, component;
6495 UINT r = ERROR_SUCCESS;
6497 static const WCHAR driver_fmt[] = {
6498 'D','r','i','v','e','r','=','%','s',0};
6499 static const WCHAR setup_fmt[] = {
6500 'S','e','t','u','p','=','%','s',0};
6501 static const WCHAR usage_fmt[] = {
6502 'F','i','l','e','U','s','a','g','e','=','1',0};
6504 component = MSI_RecordGetString( rec, 2 );
6505 comp = get_loaded_component( package, component );
6507 return ERROR_SUCCESS;
6511 TRACE("component is disabled\n");
6512 return ERROR_SUCCESS;
6515 desc = MSI_RecordGetString(rec, 3);
6517 file_key = MSI_RecordGetString( rec, 4 );
6518 if (file_key) driver_file = get_loaded_file( package, file_key );
6520 file_key = MSI_RecordGetString( rec, 5 );
6521 if (file_key) setup_file = get_loaded_file( package, file_key );
6525 ERR("ODBC Driver entry not found!\n");
6526 return ERROR_FUNCTION_FAILED;
6529 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6531 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6532 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6534 driver = msi_alloc(len * sizeof(WCHAR));
6536 return ERROR_OUTOFMEMORY;
6539 lstrcpyW(ptr, desc);
6540 ptr += lstrlenW(ptr) + 1;
6542 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6547 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6551 lstrcpyW(ptr, usage_fmt);
6552 ptr += lstrlenW(ptr) + 1;
6555 driver_path = strdupW(driver_file->TargetPath);
6556 ptr = strrchrW(driver_path, '\\');
6557 if (ptr) *ptr = '\0';
6559 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6560 NULL, ODBC_INSTALL_COMPLETE, &usage))
6562 ERR("Failed to install SQL driver!\n");
6563 r = ERROR_FUNCTION_FAILED;
6566 uirow = MSI_CreateRecord( 5 );
6567 MSI_RecordSetStringW( uirow, 1, desc );
6568 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6569 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6570 ui_actiondata( package, szInstallODBC, uirow );
6571 msiobj_release( &uirow->hdr );
6574 msi_free(driver_path);
6579 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6581 MSIPACKAGE *package = param;
6582 LPWSTR translator, translator_path, ptr;
6583 WCHAR outpath[MAX_PATH];
6584 MSIFILE *translator_file = NULL, *setup_file = NULL;
6587 LPCWSTR desc, file_key, component;
6589 UINT r = ERROR_SUCCESS;
6591 static const WCHAR translator_fmt[] = {
6592 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6593 static const WCHAR setup_fmt[] = {
6594 'S','e','t','u','p','=','%','s',0};
6596 component = MSI_RecordGetString( rec, 2 );
6597 comp = get_loaded_component( package, component );
6599 return ERROR_SUCCESS;
6603 TRACE("component is disabled\n");
6604 return ERROR_SUCCESS;
6607 desc = MSI_RecordGetString(rec, 3);
6609 file_key = MSI_RecordGetString( rec, 4 );
6610 if (file_key) translator_file = get_loaded_file( package, file_key );
6612 file_key = MSI_RecordGetString( rec, 5 );
6613 if (file_key) setup_file = get_loaded_file( package, file_key );
6615 if (!translator_file)
6617 ERR("ODBC Translator entry not found!\n");
6618 return ERROR_FUNCTION_FAILED;
6621 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6623 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6625 translator = msi_alloc(len * sizeof(WCHAR));
6627 return ERROR_OUTOFMEMORY;
6630 lstrcpyW(ptr, desc);
6631 ptr += lstrlenW(ptr) + 1;
6633 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6638 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6643 translator_path = strdupW(translator_file->TargetPath);
6644 ptr = strrchrW(translator_path, '\\');
6645 if (ptr) *ptr = '\0';
6647 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6648 NULL, ODBC_INSTALL_COMPLETE, &usage))
6650 ERR("Failed to install SQL translator!\n");
6651 r = ERROR_FUNCTION_FAILED;
6654 uirow = MSI_CreateRecord( 5 );
6655 MSI_RecordSetStringW( uirow, 1, desc );
6656 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6657 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6658 ui_actiondata( package, szInstallODBC, uirow );
6659 msiobj_release( &uirow->hdr );
6661 msi_free(translator);
6662 msi_free(translator_path);
6667 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6669 MSIPACKAGE *package = param;
6672 LPCWSTR desc, driver, component;
6673 WORD request = ODBC_ADD_SYS_DSN;
6676 UINT r = ERROR_SUCCESS;
6679 static const WCHAR attrs_fmt[] = {
6680 'D','S','N','=','%','s',0 };
6682 component = MSI_RecordGetString( rec, 2 );
6683 comp = get_loaded_component( package, component );
6685 return ERROR_SUCCESS;
6689 TRACE("component is disabled\n");
6690 return ERROR_SUCCESS;
6693 desc = MSI_RecordGetString(rec, 3);
6694 driver = MSI_RecordGetString(rec, 4);
6695 registration = MSI_RecordGetInteger(rec, 5);
6697 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6698 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6700 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6701 attrs = msi_alloc(len * sizeof(WCHAR));
6703 return ERROR_OUTOFMEMORY;
6705 len = sprintfW(attrs, attrs_fmt, desc);
6708 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6710 ERR("Failed to install SQL data source!\n");
6711 r = ERROR_FUNCTION_FAILED;
6714 uirow = MSI_CreateRecord( 5 );
6715 MSI_RecordSetStringW( uirow, 1, desc );
6716 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6717 MSI_RecordSetInteger( uirow, 3, request );
6718 ui_actiondata( package, szInstallODBC, uirow );
6719 msiobj_release( &uirow->hdr );
6726 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6731 static const WCHAR driver_query[] = {
6732 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6733 'O','D','B','C','D','r','i','v','e','r',0 };
6735 static const WCHAR translator_query[] = {
6736 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6737 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6739 static const WCHAR source_query[] = {
6740 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6741 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6743 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6744 if (rc != ERROR_SUCCESS)
6745 return ERROR_SUCCESS;
6747 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6748 msiobj_release(&view->hdr);
6750 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6751 if (rc != ERROR_SUCCESS)
6752 return ERROR_SUCCESS;
6754 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6755 msiobj_release(&view->hdr);
6757 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6758 if (rc != ERROR_SUCCESS)
6759 return ERROR_SUCCESS;
6761 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6762 msiobj_release(&view->hdr);
6767 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6769 MSIPACKAGE *package = param;
6773 LPCWSTR desc, component;
6775 component = MSI_RecordGetString( rec, 2 );
6776 comp = get_loaded_component( package, component );
6778 return ERROR_SUCCESS;
6782 TRACE("component is disabled\n");
6783 return ERROR_SUCCESS;
6786 desc = MSI_RecordGetString( rec, 3 );
6787 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6789 WARN("Failed to remove ODBC driver\n");
6793 FIXME("Usage count reached 0\n");
6796 uirow = MSI_CreateRecord( 2 );
6797 MSI_RecordSetStringW( uirow, 1, desc );
6798 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6799 ui_actiondata( package, szRemoveODBC, uirow );
6800 msiobj_release( &uirow->hdr );
6802 return ERROR_SUCCESS;
6805 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6807 MSIPACKAGE *package = param;
6811 LPCWSTR desc, component;
6813 component = MSI_RecordGetString( rec, 2 );
6814 comp = get_loaded_component( package, component );
6816 return ERROR_SUCCESS;
6820 TRACE("component is disabled\n");
6821 return ERROR_SUCCESS;
6824 desc = MSI_RecordGetString( rec, 3 );
6825 if (!SQLRemoveTranslatorW( desc, &usage ))
6827 WARN("Failed to remove ODBC translator\n");
6831 FIXME("Usage count reached 0\n");
6834 uirow = MSI_CreateRecord( 2 );
6835 MSI_RecordSetStringW( uirow, 1, desc );
6836 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6837 ui_actiondata( package, szRemoveODBC, uirow );
6838 msiobj_release( &uirow->hdr );
6840 return ERROR_SUCCESS;
6843 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6845 MSIPACKAGE *package = param;
6849 LPCWSTR desc, driver, component;
6850 WORD request = ODBC_REMOVE_SYS_DSN;
6854 static const WCHAR attrs_fmt[] = {
6855 'D','S','N','=','%','s',0 };
6857 component = MSI_RecordGetString( rec, 2 );
6858 comp = get_loaded_component( package, component );
6860 return ERROR_SUCCESS;
6864 TRACE("component is disabled\n");
6865 return ERROR_SUCCESS;
6868 desc = MSI_RecordGetString( rec, 3 );
6869 driver = MSI_RecordGetString( rec, 4 );
6870 registration = MSI_RecordGetInteger( rec, 5 );
6872 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6873 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6875 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6876 attrs = msi_alloc( len * sizeof(WCHAR) );
6878 return ERROR_OUTOFMEMORY;
6880 FIXME("Use ODBCSourceAttribute table\n");
6882 len = sprintfW( attrs, attrs_fmt, desc );
6885 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6887 WARN("Failed to remove ODBC data source\n");
6891 uirow = MSI_CreateRecord( 3 );
6892 MSI_RecordSetStringW( uirow, 1, desc );
6893 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6894 MSI_RecordSetInteger( uirow, 3, request );
6895 ui_actiondata( package, szRemoveODBC, uirow );
6896 msiobj_release( &uirow->hdr );
6898 return ERROR_SUCCESS;
6901 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6906 static const WCHAR driver_query[] = {
6907 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6908 'O','D','B','C','D','r','i','v','e','r',0 };
6910 static const WCHAR translator_query[] = {
6911 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6912 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6914 static const WCHAR source_query[] = {
6915 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6916 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6918 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6919 if (rc != ERROR_SUCCESS)
6920 return ERROR_SUCCESS;
6922 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6923 msiobj_release( &view->hdr );
6925 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6926 if (rc != ERROR_SUCCESS)
6927 return ERROR_SUCCESS;
6929 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6930 msiobj_release( &view->hdr );
6932 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6933 if (rc != ERROR_SUCCESS)
6934 return ERROR_SUCCESS;
6936 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6937 msiobj_release( &view->hdr );
6942 #define ENV_ACT_SETALWAYS 0x1
6943 #define ENV_ACT_SETABSENT 0x2
6944 #define ENV_ACT_REMOVE 0x4
6945 #define ENV_ACT_REMOVEMATCH 0x8
6947 #define ENV_MOD_MACHINE 0x20000000
6948 #define ENV_MOD_APPEND 0x40000000
6949 #define ENV_MOD_PREFIX 0x80000000
6950 #define ENV_MOD_MASK 0xC0000000
6952 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6954 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6956 LPCWSTR cptr = *name;
6958 static const WCHAR prefix[] = {'[','~',']',0};
6959 static const int prefix_len = 3;
6965 *flags |= ENV_ACT_SETALWAYS;
6966 else if (*cptr == '+')
6967 *flags |= ENV_ACT_SETABSENT;
6968 else if (*cptr == '-')
6969 *flags |= ENV_ACT_REMOVE;
6970 else if (*cptr == '!')
6971 *flags |= ENV_ACT_REMOVEMATCH;
6972 else if (*cptr == '*')
6973 *flags |= ENV_MOD_MACHINE;
6983 ERR("Missing environment variable\n");
6984 return ERROR_FUNCTION_FAILED;
6989 LPCWSTR ptr = *value;
6990 if (!strncmpW(ptr, prefix, prefix_len))
6992 if (ptr[prefix_len] == szSemiColon[0])
6994 *flags |= ENV_MOD_APPEND;
6995 *value += lstrlenW(prefix);
7002 else if (lstrlenW(*value) >= prefix_len)
7004 ptr += lstrlenW(ptr) - prefix_len;
7005 if (!strcmpW( ptr, prefix ))
7007 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
7009 *flags |= ENV_MOD_PREFIX;
7010 /* the "[~]" will be removed by deformat_string */;
7020 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
7021 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
7022 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
7023 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
7025 ERR("Invalid flags: %08x\n", *flags);
7026 return ERROR_FUNCTION_FAILED;
7030 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
7032 return ERROR_SUCCESS;
7035 static UINT open_env_key( DWORD flags, HKEY *key )
7037 static const WCHAR user_env[] =
7038 {'E','n','v','i','r','o','n','m','e','n','t',0};
7039 static const WCHAR machine_env[] =
7040 {'S','y','s','t','e','m','\\',
7041 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
7042 'C','o','n','t','r','o','l','\\',
7043 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
7044 'E','n','v','i','r','o','n','m','e','n','t',0};
7049 if (flags & ENV_MOD_MACHINE)
7052 root = HKEY_LOCAL_MACHINE;
7057 root = HKEY_CURRENT_USER;
7060 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
7061 if (res != ERROR_SUCCESS)
7063 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
7064 return ERROR_FUNCTION_FAILED;
7067 return ERROR_SUCCESS;
7070 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
7072 MSIPACKAGE *package = param;
7073 LPCWSTR name, value, component;
7074 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
7075 DWORD flags, type, size;
7082 component = MSI_RecordGetString(rec, 4);
7083 comp = get_loaded_component(package, component);
7085 return ERROR_SUCCESS;
7089 TRACE("component is disabled\n");
7090 return ERROR_SUCCESS;
7093 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
7095 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
7096 comp->Action = comp->Installed;
7097 return ERROR_SUCCESS;
7099 comp->Action = INSTALLSTATE_LOCAL;
7101 name = MSI_RecordGetString(rec, 2);
7102 value = MSI_RecordGetString(rec, 3);
7104 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7106 res = env_parse_flags(&name, &value, &flags);
7107 if (res != ERROR_SUCCESS || !value)
7110 if (value && !deformat_string(package, value, &deformatted))
7112 res = ERROR_OUTOFMEMORY;
7116 value = deformatted;
7118 res = open_env_key( flags, &env );
7119 if (res != ERROR_SUCCESS)
7122 if (flags & ENV_MOD_MACHINE)
7123 action |= 0x20000000;
7127 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
7128 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
7129 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
7132 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
7136 /* Nothing to do. */
7139 res = ERROR_SUCCESS;
7143 /* If we are appending but the string was empty, strip ; */
7144 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
7146 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
7147 newval = strdupW(value);
7150 res = ERROR_OUTOFMEMORY;
7158 /* Contrary to MSDN, +-variable to [~];path works */
7159 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
7161 res = ERROR_SUCCESS;
7165 data = msi_alloc(size);
7169 return ERROR_OUTOFMEMORY;
7172 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
7173 if (res != ERROR_SUCCESS)
7176 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
7179 res = RegDeleteValueW(env, name);
7180 if (res != ERROR_SUCCESS)
7181 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
7185 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
7186 if (flags & ENV_MOD_MASK)
7190 if (flags & ENV_MOD_APPEND) multiplier++;
7191 if (flags & ENV_MOD_PREFIX) multiplier++;
7192 mod_size = lstrlenW(value) * multiplier;
7193 size += mod_size * sizeof(WCHAR);
7196 newval = msi_alloc(size);
7200 res = ERROR_OUTOFMEMORY;
7204 if (flags & ENV_MOD_PREFIX)
7206 lstrcpyW(newval, value);
7207 ptr = newval + lstrlenW(value);
7208 action |= 0x80000000;
7211 lstrcpyW(ptr, data);
7213 if (flags & ENV_MOD_APPEND)
7215 lstrcatW(newval, value);
7216 action |= 0x40000000;
7219 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
7220 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
7223 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7227 uirow = MSI_CreateRecord( 3 );
7228 MSI_RecordSetStringW( uirow, 1, name );
7229 MSI_RecordSetStringW( uirow, 2, newval );
7230 MSI_RecordSetInteger( uirow, 3, action );
7231 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
7232 msiobj_release( &uirow->hdr );
7234 if (env) RegCloseKey(env);
7235 msi_free(deformatted);
7241 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7245 static const WCHAR ExecSeqQuery[] =
7246 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7247 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7248 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7249 if (rc != ERROR_SUCCESS)
7250 return ERROR_SUCCESS;
7252 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7253 msiobj_release(&view->hdr);
7258 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7260 MSIPACKAGE *package = param;
7261 LPCWSTR name, value, component;
7262 LPWSTR deformatted = NULL;
7271 component = MSI_RecordGetString( rec, 4 );
7272 comp = get_loaded_component( package, component );
7274 return ERROR_SUCCESS;
7278 TRACE("component is disabled\n");
7279 return ERROR_SUCCESS;
7282 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
7284 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
7285 comp->Action = comp->Installed;
7286 return ERROR_SUCCESS;
7288 comp->Action = INSTALLSTATE_ABSENT;
7290 name = MSI_RecordGetString( rec, 2 );
7291 value = MSI_RecordGetString( rec, 3 );
7293 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7295 r = env_parse_flags( &name, &value, &flags );
7296 if (r != ERROR_SUCCESS)
7299 if (!(flags & ENV_ACT_REMOVE))
7301 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7302 return ERROR_SUCCESS;
7305 if (value && !deformat_string( package, value, &deformatted ))
7306 return ERROR_OUTOFMEMORY;
7308 value = deformatted;
7310 r = open_env_key( flags, &env );
7311 if (r != ERROR_SUCCESS)
7317 if (flags & ENV_MOD_MACHINE)
7318 action |= 0x20000000;
7320 TRACE("Removing %s\n", debugstr_w(name));
7322 res = RegDeleteValueW( env, name );
7323 if (res != ERROR_SUCCESS)
7325 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
7330 uirow = MSI_CreateRecord( 3 );
7331 MSI_RecordSetStringW( uirow, 1, name );
7332 MSI_RecordSetStringW( uirow, 2, value );
7333 MSI_RecordSetInteger( uirow, 3, action );
7334 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
7335 msiobj_release( &uirow->hdr );
7337 if (env) RegCloseKey( env );
7338 msi_free( deformatted );
7342 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7346 static const WCHAR query[] =
7347 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7348 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7350 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
7351 if (rc != ERROR_SUCCESS)
7352 return ERROR_SUCCESS;
7354 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7355 msiobj_release( &view->hdr );
7360 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7362 LPWSTR key, template, id;
7363 UINT r = ERROR_SUCCESS;
7365 id = msi_dup_property( package->db, szProductID );
7369 return ERROR_SUCCESS;
7371 template = msi_dup_property( package->db, szPIDTemplate );
7372 key = msi_dup_property( package->db, szPIDKEY );
7374 if (key && template)
7376 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7377 r = msi_set_property( package->db, szProductID, key );
7379 msi_free( template );
7384 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7387 package->need_reboot = 1;
7388 return ERROR_SUCCESS;
7391 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7393 static const WCHAR szAvailableFreeReg[] =
7394 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7396 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7398 TRACE("%p %d kilobytes\n", package, space);
7400 uirow = MSI_CreateRecord( 1 );
7401 MSI_RecordSetInteger( uirow, 1, space );
7402 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7403 msiobj_release( &uirow->hdr );
7405 return ERROR_SUCCESS;
7408 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7410 FIXME("%p\n", package);
7411 return ERROR_SUCCESS;
7414 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7416 FIXME("%p\n", package);
7417 return ERROR_SUCCESS;
7420 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7425 static const WCHAR driver_query[] = {
7426 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7427 'O','D','B','C','D','r','i','v','e','r',0 };
7429 static const WCHAR translator_query[] = {
7430 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7431 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7433 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7434 if (r == ERROR_SUCCESS)
7437 r = MSI_IterateRecords( view, &count, NULL, package );
7438 msiobj_release( &view->hdr );
7439 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7442 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7443 if (r == ERROR_SUCCESS)
7446 r = MSI_IterateRecords( view, &count, NULL, package );
7447 msiobj_release( &view->hdr );
7448 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7451 return ERROR_SUCCESS;
7454 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7456 MSIPACKAGE *package = param;
7457 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7460 if ((value = msi_dup_property( package->db, property )))
7462 FIXME("remove %s\n", debugstr_w(value));
7465 return ERROR_SUCCESS;
7468 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7473 static const WCHAR query[] =
7474 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7475 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7477 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7478 if (r == ERROR_SUCCESS)
7480 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7481 msiobj_release( &view->hdr );
7483 return ERROR_SUCCESS;
7486 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7488 MSIPACKAGE *package = param;
7489 int attributes = MSI_RecordGetInteger( rec, 5 );
7491 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7493 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7494 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7495 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7496 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7500 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7502 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7503 if (r != ERROR_SUCCESS)
7504 return ERROR_SUCCESS;
7508 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7509 if (r != ERROR_SUCCESS)
7510 return ERROR_SUCCESS;
7512 RegCloseKey( hkey );
7514 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7515 debugstr_w(upgrade_code), debugstr_w(version_min),
7516 debugstr_w(version_max), debugstr_w(language));
7518 return ERROR_SUCCESS;
7521 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7526 static const WCHAR query[] =
7527 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7529 if (msi_get_property_int( package->db, szInstalled, 0 ))
7531 TRACE("product is installed, skipping action\n");
7532 return ERROR_SUCCESS;
7534 if (msi_get_property_int( package->db, szPreselected, 0 ))
7536 TRACE("Preselected property is set, not migrating feature states\n");
7537 return ERROR_SUCCESS;
7540 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7541 if (r == ERROR_SUCCESS)
7543 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7544 msiobj_release( &view->hdr );
7546 return ERROR_SUCCESS;
7549 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7550 LPCSTR action, LPCWSTR table )
7552 static const WCHAR query[] = {
7553 'S','E','L','E','C','T',' ','*',' ',
7554 'F','R','O','M',' ','`','%','s','`',0 };
7555 MSIQUERY *view = NULL;
7559 r = MSI_OpenQuery( package->db, &view, query, table );
7560 if (r == ERROR_SUCCESS)
7562 r = MSI_IterateRecords(view, &count, NULL, package);
7563 msiobj_release(&view->hdr);
7567 FIXME("%s -> %u ignored %s table values\n",
7568 action, count, debugstr_w(table));
7570 return ERROR_SUCCESS;
7573 static UINT ACTION_BindImage( MSIPACKAGE *package )
7575 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7576 return msi_unimplemented_action_stub( package, "BindImage", table );
7579 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7581 static const WCHAR table[] = {
7582 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7583 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7586 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7588 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7589 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7592 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7594 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7595 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7598 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7600 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7601 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7604 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7606 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7607 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7610 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7614 const WCHAR *action;
7615 UINT (*handler)(MSIPACKAGE *);
7619 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7620 { szAppSearch, ACTION_AppSearch },
7621 { szBindImage, ACTION_BindImage },
7622 { szCCPSearch, ACTION_CCPSearch },
7623 { szCostFinalize, ACTION_CostFinalize },
7624 { szCostInitialize, ACTION_CostInitialize },
7625 { szCreateFolders, ACTION_CreateFolders },
7626 { szCreateShortcuts, ACTION_CreateShortcuts },
7627 { szDeleteServices, ACTION_DeleteServices },
7628 { szDisableRollback, ACTION_DisableRollback },
7629 { szDuplicateFiles, ACTION_DuplicateFiles },
7630 { szExecuteAction, ACTION_ExecuteAction },
7631 { szFileCost, ACTION_FileCost },
7632 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7633 { szForceReboot, ACTION_ForceReboot },
7634 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7635 { szInstallExecute, ACTION_InstallExecute },
7636 { szInstallExecuteAgain, ACTION_InstallExecute },
7637 { szInstallFiles, ACTION_InstallFiles},
7638 { szInstallFinalize, ACTION_InstallFinalize },
7639 { szInstallInitialize, ACTION_InstallInitialize },
7640 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7641 { szInstallValidate, ACTION_InstallValidate },
7642 { szIsolateComponents, ACTION_IsolateComponents },
7643 { szLaunchConditions, ACTION_LaunchConditions },
7644 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7645 { szMoveFiles, ACTION_MoveFiles },
7646 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7647 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7648 { szInstallODBC, ACTION_InstallODBC },
7649 { szInstallServices, ACTION_InstallServices },
7650 { szPatchFiles, ACTION_PatchFiles },
7651 { szProcessComponents, ACTION_ProcessComponents },
7652 { szPublishComponents, ACTION_PublishComponents },
7653 { szPublishFeatures, ACTION_PublishFeatures },
7654 { szPublishProduct, ACTION_PublishProduct },
7655 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7656 { szRegisterComPlus, ACTION_RegisterComPlus},
7657 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7658 { szRegisterFonts, ACTION_RegisterFonts },
7659 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7660 { szRegisterProduct, ACTION_RegisterProduct },
7661 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7662 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7663 { szRegisterUser, ACTION_RegisterUser },
7664 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7665 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7666 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7667 { szRemoveFiles, ACTION_RemoveFiles },
7668 { szRemoveFolders, ACTION_RemoveFolders },
7669 { szRemoveIniValues, ACTION_RemoveIniValues },
7670 { szRemoveODBC, ACTION_RemoveODBC },
7671 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7672 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7673 { szResolveSource, ACTION_ResolveSource },
7674 { szRMCCPSearch, ACTION_RMCCPSearch },
7675 { szScheduleReboot, ACTION_ScheduleReboot },
7676 { szSelfRegModules, ACTION_SelfRegModules },
7677 { szSelfUnregModules, ACTION_SelfUnregModules },
7678 { szSetODBCFolders, ACTION_SetODBCFolders },
7679 { szStartServices, ACTION_StartServices },
7680 { szStopServices, ACTION_StopServices },
7681 { szUnpublishComponents, ACTION_UnpublishComponents },
7682 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7683 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7684 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7685 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7686 { szUnregisterFonts, ACTION_UnregisterFonts },
7687 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7688 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7689 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7690 { szValidateProductID, ACTION_ValidateProductID },
7691 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7692 { szWriteIniValues, ACTION_WriteIniValues },
7693 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7697 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7703 while (StandardActions[i].action != NULL)
7705 if (!strcmpW( StandardActions[i].action, action ))
7707 ui_actionstart( package, action );
7708 if (StandardActions[i].handler)
7710 ui_actioninfo( package, action, TRUE, 0 );
7711 *rc = StandardActions[i].handler( package );
7712 ui_actioninfo( package, action, FALSE, *rc );
7716 FIXME("unhandled standard action %s\n", debugstr_w(action));
7717 *rc = ERROR_SUCCESS;
7727 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7729 UINT rc = ERROR_SUCCESS;
7732 TRACE("Performing action (%s)\n", debugstr_w(action));
7734 handled = ACTION_HandleStandardAction(package, action, &rc);
7737 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7741 WARN("unhandled msi action %s\n", debugstr_w(action));
7742 rc = ERROR_FUNCTION_NOT_CALLED;
7748 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7750 UINT rc = ERROR_SUCCESS;
7751 BOOL handled = FALSE;
7753 TRACE("Performing action (%s)\n", debugstr_w(action));
7755 handled = ACTION_HandleStandardAction(package, action, &rc);
7758 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7760 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7765 WARN("unhandled msi action %s\n", debugstr_w(action));
7766 rc = ERROR_FUNCTION_NOT_CALLED;
7772 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7774 UINT rc = ERROR_SUCCESS;
7777 static const WCHAR ExecSeqQuery[] =
7778 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7779 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7780 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7781 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7782 static const WCHAR UISeqQuery[] =
7783 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7784 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7785 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7786 ' ', '=',' ','%','i',0};
7788 if (needs_ui_sequence(package))
7789 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7791 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7795 LPCWSTR action, cond;
7797 TRACE("Running the actions\n");
7799 /* check conditions */
7800 cond = MSI_RecordGetString(row, 2);
7802 /* this is a hack to skip errors in the condition code */
7803 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7805 msiobj_release(&row->hdr);
7806 return ERROR_SUCCESS;
7809 action = MSI_RecordGetString(row, 1);
7812 ERR("failed to fetch action\n");
7813 msiobj_release(&row->hdr);
7814 return ERROR_FUNCTION_FAILED;
7817 if (needs_ui_sequence(package))
7818 rc = ACTION_PerformUIAction(package, action, -1);
7820 rc = ACTION_PerformAction(package, action, -1);
7822 msiobj_release(&row->hdr);
7828 /****************************************************
7829 * TOP level entry points
7830 *****************************************************/
7832 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7833 LPCWSTR szCommandLine )
7838 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7839 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7841 msi_set_property( package->db, szAction, szInstall );
7843 package->script->InWhatSequence = SEQUENCE_INSTALL;
7850 dir = strdupW(szPackagePath);
7851 p = strrchrW(dir, '\\');
7855 file = szPackagePath + (p - dir);
7860 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7861 GetCurrentDirectoryW(MAX_PATH, dir);
7862 lstrcatW(dir, szBackSlash);
7863 file = szPackagePath;
7866 msi_free( package->PackagePath );
7867 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7868 if (!package->PackagePath)
7871 return ERROR_OUTOFMEMORY;
7874 lstrcpyW(package->PackagePath, dir);
7875 lstrcatW(package->PackagePath, file);
7878 msi_set_sourcedir_props(package, FALSE);
7881 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7882 if (rc != ERROR_SUCCESS)
7885 msi_apply_transforms( package );
7886 msi_apply_patches( package );
7888 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7890 TRACE("setting reinstall property\n");
7891 msi_set_property( package->db, szReinstall, szAll );
7894 /* properties may have been added by a transform */
7895 msi_clone_properties( package );
7897 msi_parse_command_line( package, szCommandLine, FALSE );
7898 msi_adjust_privilege_properties( package );
7899 msi_set_context( package );
7901 if (needs_ui_sequence( package))
7903 package->script->InWhatSequence |= SEQUENCE_UI;
7904 rc = ACTION_ProcessUISequence(package);
7905 ui_exists = ui_sequence_exists(package);
7906 if (rc == ERROR_SUCCESS || !ui_exists)
7908 package->script->InWhatSequence |= SEQUENCE_EXEC;
7909 rc = ACTION_ProcessExecSequence(package, ui_exists);
7913 rc = ACTION_ProcessExecSequence(package, FALSE);
7915 package->script->CurrentlyScripting = FALSE;
7917 /* process the ending type action */
7918 if (rc == ERROR_SUCCESS)
7919 ACTION_PerformActionSequence(package, -1);
7920 else if (rc == ERROR_INSTALL_USEREXIT)
7921 ACTION_PerformActionSequence(package, -2);
7922 else if (rc == ERROR_INSTALL_SUSPEND)
7923 ACTION_PerformActionSequence(package, -4);
7925 ACTION_PerformActionSequence(package, -3);
7927 /* finish up running custom actions */
7928 ACTION_FinishCustomActions(package);
7930 if (rc == ERROR_SUCCESS && package->need_reboot)
7931 return ERROR_SUCCESS_REBOOT_REQUIRED;