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;
237 if (in_quotes) count--;
242 if (!count) in_quotes = 0;
254 if (in_quotes) count--;
258 state = state_whitespace;
259 if (!count) goto done;
263 if (!count) in_quotes = 0;
274 if (in_quotes) count--;
278 state = state_whitespace;
279 if (!count) goto done;
284 if (!count) in_quotes = 0;
293 if (!ignore) *out++ = *p;
297 if (!len) *value = 0;
304 static void remove_quotes( WCHAR *str )
307 int len = strlenW( str );
309 while ((p = strchrW( p, '"' )))
311 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
316 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
326 return ERROR_SUCCESS;
331 while (*ptr == ' ') ptr++;
334 ptr2 = strchrW( ptr, '=' );
335 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
338 if (!len) return ERROR_INVALID_COMMAND_LINE;
340 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
341 memcpy( prop, ptr, len * sizeof(WCHAR) );
343 if (!preserve_case) struprW( prop );
346 while (*ptr2 == ' ') ptr2++;
349 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
350 len = parse_prop( ptr2, val, &num_quotes );
353 WARN("unbalanced quotes\n");
356 return ERROR_INVALID_COMMAND_LINE;
358 remove_quotes( val );
359 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
361 r = msi_set_property( package->db, prop, val );
362 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
363 msi_reset_folders( package, TRUE );
371 return ERROR_SUCCESS;
374 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
377 LPWSTR p, *ret = NULL;
383 /* count the number of substrings */
384 for ( pc = str, count = 0; pc; count++ )
386 pc = strchrW( pc, sep );
391 /* allocate space for an array of substring pointers and the substrings */
392 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
393 (lstrlenW(str)+1) * sizeof(WCHAR) );
397 /* copy the string and set the pointers */
398 p = (LPWSTR) &ret[count+1];
400 for( count = 0; (ret[count] = p); count++ )
402 p = strchrW( p, sep );
410 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
412 static const WCHAR szSystemLanguageID[] =
413 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
415 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
416 UINT ret = ERROR_FUNCTION_FAILED;
418 prod_code = msi_dup_property( package->db, szProductCode );
419 patch_product = msi_get_suminfo_product( patch );
421 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
423 if ( strstrW( patch_product, prod_code ) )
428 si = MSI_GetSummaryInformationW( patch, 0 );
431 ERR("no summary information!\n");
435 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
438 ERR("no template property!\n");
439 msiobj_release( &si->hdr );
446 msiobj_release( &si->hdr );
450 langid = msi_dup_property( package->db, szSystemLanguageID );
453 msiobj_release( &si->hdr );
457 p = strchrW( template, ';' );
458 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
460 TRACE("applicable transform\n");
464 /* FIXME: check platform */
466 msiobj_release( &si->hdr );
470 msi_free( patch_product );
471 msi_free( prod_code );
472 msi_free( template );
478 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
479 MSIDATABASE *patch_db, LPCWSTR name )
481 UINT ret = ERROR_FUNCTION_FAILED;
482 IStorage *stg = NULL;
485 TRACE("%p %s\n", package, debugstr_w(name) );
489 ERR("expected a colon in %s\n", debugstr_w(name));
490 return ERROR_FUNCTION_FAILED;
493 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
496 ret = msi_check_transform_applicable( package, stg );
497 if (ret == ERROR_SUCCESS)
498 msi_table_apply_transform( package->db, stg );
500 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
501 IStorage_Release( stg );
504 ERR("failed to open substorage %s\n", debugstr_w(name));
506 return ERROR_SUCCESS;
509 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
511 LPWSTR guid_list, *guids, product_code;
512 UINT i, ret = ERROR_FUNCTION_FAILED;
514 product_code = msi_dup_property( package->db, szProductCode );
517 /* FIXME: the property ProductCode should be written into the DB somewhere */
518 ERR("no product code to check\n");
519 return ERROR_SUCCESS;
522 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
523 guids = msi_split_string( guid_list, ';' );
524 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
526 if (!strcmpW( guids[i], product_code ))
530 msi_free( guid_list );
531 msi_free( product_code );
536 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
539 MSIRECORD *rec = NULL;
544 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
545 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
546 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
547 '`','S','o','u','r','c','e','`',' ','I','S',' ',
548 'N','O','T',' ','N','U','L','L',0};
550 r = MSI_DatabaseOpenViewW(package->db, query, &view);
551 if (r != ERROR_SUCCESS)
554 r = MSI_ViewExecute(view, 0);
555 if (r != ERROR_SUCCESS)
558 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
560 prop = MSI_RecordGetString(rec, 1);
561 patch = msi_dup_property(package->db, szPatch);
562 msi_set_property(package->db, prop, patch);
567 if (rec) msiobj_release(&rec->hdr);
568 msiobj_release(&view->hdr);
573 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
576 UINT r = ERROR_SUCCESS;
579 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
581 return ERROR_OUTOFMEMORY;
583 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
587 return ERROR_OUTOFMEMORY;
593 msi_free( pi->patchcode );
595 return ERROR_PATCH_PACKAGE_INVALID;
598 p = strchrW( p + 1, '}' );
601 msi_free( pi->patchcode );
603 return ERROR_PATCH_PACKAGE_INVALID;
608 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
612 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
614 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
617 msi_free( pi->patchcode );
619 return ERROR_OUTOFMEMORY;
626 struct msi_patch_offset
633 struct msi_patch_offset_list
636 UINT count, min, max;
637 UINT offset_to_apply;
640 static struct msi_patch_offset_list *msi_patch_offset_list_create(void)
642 struct msi_patch_offset_list *pos = msi_alloc(sizeof(struct msi_patch_offset_list));
643 list_init( &pos->files );
644 pos->count = pos->max = 0;
650 static void msi_patch_offset_list_free(struct msi_patch_offset_list *pos)
652 struct msi_patch_offset *po, *po2;
654 LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct msi_patch_offset, entry )
656 msi_free( po->Name );
663 static void msi_patch_offset_get_patches(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
668 static const WCHAR query_patch[] = {
669 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
670 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
671 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
673 r = MSI_DatabaseOpenViewW( db, query_patch, &view );
674 if (r != ERROR_SUCCESS)
677 rec = MSI_CreateRecord( 1 );
678 MSI_RecordSetInteger(rec, 1, last_sequence);
680 r = MSI_ViewExecute( view, rec );
681 msiobj_release( &rec->hdr );
682 if (r != ERROR_SUCCESS)
685 while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
687 UINT sequence = MSI_RecordGetInteger( rec, 2 );
690 * We only use the max/min sequence numbers for now.
693 pos->min = min(pos->min, sequence);
694 pos->max = max(pos->max, sequence);
697 msiobj_release( &rec->hdr );
700 msiobj_release( &view->hdr );
703 static void msi_patch_offset_get_files(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
708 static const WCHAR query_files[] = {
709 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
710 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
711 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
713 r = MSI_DatabaseOpenViewW( db, query_files, &view );
714 if (r != ERROR_SUCCESS)
717 rec = MSI_CreateRecord( 1 );
718 MSI_RecordSetInteger(rec, 1, last_sequence);
720 r = MSI_ViewExecute( view, rec );
721 msiobj_release( &rec->hdr );
722 if (r != ERROR_SUCCESS)
725 while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
727 UINT attributes = MSI_RecordGetInteger( rec, 7 );
728 if (attributes & msidbFileAttributesPatchAdded)
730 struct msi_patch_offset *po = msi_alloc(sizeof(struct msi_patch_offset));
732 po->Name = msi_dup_record_field( rec, 1 );
733 po->Sequence = MSI_RecordGetInteger( rec, 8 );
735 pos->min = min(pos->min, po->Sequence);
736 pos->max = max(pos->max, po->Sequence);
738 list_add_tail( &pos->files, &po->entry );
741 msiobj_release( &rec->hdr );
744 msiobj_release( &view->hdr );
747 static UINT msi_patch_offset_modify_db(MSIDATABASE *db, struct msi_patch_offset_list *pos)
749 static const WCHAR query_files[] =
750 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
751 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ',
752 'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
753 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
754 struct msi_patch_offset *po;
759 r = MSI_DatabaseOpenViewW( db, query_files, &view );
760 if (r != ERROR_SUCCESS)
761 return ERROR_SUCCESS;
763 rec = MSI_CreateRecord( 2 );
764 MSI_RecordSetInteger( rec, 1, pos->min );
765 MSI_RecordSetInteger( rec, 2, pos->max );
767 r = MSI_ViewExecute( view, rec );
768 msiobj_release( &rec->hdr );
769 if (r != ERROR_SUCCESS)
772 LIST_FOR_EACH_ENTRY( po, &pos->files, struct msi_patch_offset, entry )
775 while ( (r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS )
777 LPCWSTR file = MSI_RecordGetString( rec, 1 );
780 if (!strcmpiW(file, po->Name))
783 seq = MSI_RecordGetInteger( rec, 8 );
784 MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
785 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
786 if (r != ERROR_SUCCESS)
787 ERR("Failed to update offset for file %s.\n", debugstr_w(file));
789 msiobj_release( &rec->hdr );
793 msiobj_release( &rec->hdr );
796 if (r_fetch != ERROR_SUCCESS)
801 msiobj_release( &view->hdr );
803 return ERROR_SUCCESS;
806 static UINT msi_set_patch_offsets(MSIDATABASE *db)
808 static const WCHAR query_media[] = {
809 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','M','e','d','i','a',' ',
810 'W','H','E','R','E',' ','S','o','u','r','c','e',' ','I','S',' ','N','O','T',' ','N','U','L','L',
811 ' ','A','N','D',' ','C','a','b','i','n','e','t',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
812 'O','R','D','E','R',' ','B','Y',' ','D','i','s','k','I','d',0};
813 MSIQUERY *view = NULL;
814 MSIRECORD *rec = NULL;
817 r = MSI_DatabaseOpenViewW( db, query_media, &view );
818 if (r != ERROR_SUCCESS)
821 r = MSI_ViewExecute( view, 0 );
822 if (r != ERROR_SUCCESS)
825 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
827 UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
828 struct msi_patch_offset_list *pos;
830 /* FIXME: Set/Check Source field instead? */
831 if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET)
833 msiobj_release( &rec->hdr );
837 pos = msi_patch_offset_list_create();
839 msi_patch_offset_get_files( db, last_sequence, pos );
840 msi_patch_offset_get_patches( db, last_sequence, pos );
844 UINT offset = db->media_transform_offset - pos->min;
845 last_sequence = offset + pos->max;
848 * This is for the patch table, which is not yet properly transformed.
850 last_sequence += pos->min;
852 pos->offset_to_apply = offset;
853 msi_patch_offset_modify_db( db, pos );
855 MSI_RecordSetInteger( rec, 2, last_sequence );
856 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
857 if (r != ERROR_SUCCESS)
858 ERR("Failed to update Media table entry, expect breakage (%u).\n", r);
860 db->media_transform_offset = last_sequence + 1;
863 msi_patch_offset_list_free( pos );
864 msiobj_release( &rec->hdr );
868 msiobj_release( &view->hdr );
873 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
875 UINT i, r = ERROR_SUCCESS;
878 /* apply substorage transforms */
879 substorage = msi_split_string( patch->transforms, ';' );
880 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
882 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
883 if (r == ERROR_SUCCESS)
884 msi_set_patch_offsets( package->db );
887 msi_free( substorage );
888 if (r != ERROR_SUCCESS)
891 msi_set_media_source_prop( package );
894 * There might be a CAB file in the patch package,
895 * so append it to the list of storages to search for streams.
897 append_storage_to_db( package->db, patch_db->storage );
899 patch->state = MSIPATCHSTATE_APPLIED;
900 list_add_tail( &package->patches, &patch->entry );
901 return ERROR_SUCCESS;
904 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
906 static const WCHAR dotmsp[] = {'.','m','s','p',0};
907 MSIDATABASE *patch_db = NULL;
908 WCHAR localfile[MAX_PATH];
910 MSIPATCHINFO *patch = NULL;
911 UINT r = ERROR_SUCCESS;
913 TRACE("%p %s\n", package, debugstr_w( file ) );
915 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
916 if ( r != ERROR_SUCCESS )
918 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
922 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
925 msiobj_release( &patch_db->hdr );
926 return ERROR_FUNCTION_FAILED;
929 r = msi_check_patch_applicable( package, si );
930 if (r != ERROR_SUCCESS)
932 TRACE("patch not applicable\n");
937 r = msi_parse_patch_summary( si, &patch );
938 if ( r != ERROR_SUCCESS )
941 r = msi_get_local_package_name( localfile, dotmsp );
942 if ( r != ERROR_SUCCESS )
945 TRACE("copying to local package %s\n", debugstr_w(localfile));
947 if (!CopyFileW( file, localfile, FALSE ))
949 ERR("Unable to copy package (%s -> %s) (error %u)\n",
950 debugstr_w(file), debugstr_w(localfile), GetLastError());
954 patch->localfile = strdupW( localfile );
956 r = msi_apply_patch_db( package, patch_db, patch );
957 if ( r != ERROR_SUCCESS )
958 WARN("patch failed to apply %u\n", r);
961 msiobj_release( &si->hdr );
962 msiobj_release( &patch_db->hdr );
963 if (patch && r != ERROR_SUCCESS)
965 if (patch->localfile)
966 DeleteFileW( patch->localfile );
968 msi_free( patch->patchcode );
969 msi_free( patch->transforms );
970 msi_free( patch->localfile );
976 /* get the PATCH property, and apply all the patches it specifies */
977 static UINT msi_apply_patches( MSIPACKAGE *package )
979 LPWSTR patch_list, *patches;
980 UINT i, r = ERROR_SUCCESS;
982 patch_list = msi_dup_property( package->db, szPatch );
984 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
986 patches = msi_split_string( patch_list, ';' );
987 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
988 r = msi_apply_patch_package( package, patches[i] );
991 msi_free( patch_list );
996 static UINT msi_apply_transforms( MSIPACKAGE *package )
998 static const WCHAR szTransforms[] = {
999 'T','R','A','N','S','F','O','R','M','S',0 };
1000 LPWSTR xform_list, *xforms;
1001 UINT i, r = ERROR_SUCCESS;
1003 xform_list = msi_dup_property( package->db, szTransforms );
1004 xforms = msi_split_string( xform_list, ';' );
1006 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
1008 if (xforms[i][0] == ':')
1009 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
1014 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
1017 WCHAR *p = strrchrW( package->PackagePath, '\\' );
1018 DWORD len = p - package->PackagePath + 1;
1020 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
1023 msi_free( xform_list );
1024 return ERROR_OUTOFMEMORY;
1026 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
1027 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
1029 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
1030 if (transform != xforms[i]) msi_free( transform );
1035 msi_free( xform_list );
1040 static BOOL ui_sequence_exists( MSIPACKAGE *package )
1045 static const WCHAR ExecSeqQuery [] =
1046 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1047 '`','I','n','s','t','a','l','l',
1048 'U','I','S','e','q','u','e','n','c','e','`',
1049 ' ','W','H','E','R','E',' ',
1050 '`','S','e','q','u','e','n','c','e','`',' ',
1051 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1052 '`','S','e','q','u','e','n','c','e','`',0};
1054 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1055 if (rc == ERROR_SUCCESS)
1057 msiobj_release(&view->hdr);
1064 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
1066 LPWSTR source, check;
1068 if (msi_get_property_int( package->db, szInstalled, 0 ))
1072 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
1073 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
1074 RegCloseKey( hkey );
1081 db = msi_dup_property( package->db, szOriginalDatabase );
1083 return ERROR_OUTOFMEMORY;
1085 p = strrchrW( db, '\\' );
1088 p = strrchrW( db, '/' );
1092 return ERROR_SUCCESS;
1097 source = msi_alloc( len * sizeof(WCHAR) );
1098 lstrcpynW( source, db, len );
1102 check = msi_dup_property( package->db, cszSourceDir );
1103 if (!check || replace)
1105 UINT r = msi_set_property( package->db, cszSourceDir, source );
1106 if (r == ERROR_SUCCESS)
1107 msi_reset_folders( package, TRUE );
1111 check = msi_dup_property( package->db, cszSOURCEDIR );
1112 if (!check || replace)
1113 msi_set_property( package->db, cszSOURCEDIR, source );
1118 return ERROR_SUCCESS;
1121 static BOOL needs_ui_sequence(MSIPACKAGE *package)
1123 INT level = msi_get_property_int(package->db, szUILevel, 0);
1124 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
1127 UINT msi_set_context(MSIPACKAGE *package)
1131 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
1133 num = msi_get_property_int(package->db, szAllUsers, 0);
1134 if (num == 1 || num == 2)
1135 package->Context = MSIINSTALLCONTEXT_MACHINE;
1137 return ERROR_SUCCESS;
1140 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
1143 LPCWSTR cond, action;
1144 MSIPACKAGE *package = param;
1146 action = MSI_RecordGetString(row,1);
1149 ERR("Error is retrieving action name\n");
1150 return ERROR_FUNCTION_FAILED;
1153 /* check conditions */
1154 cond = MSI_RecordGetString(row,2);
1156 /* this is a hack to skip errors in the condition code */
1157 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1159 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
1160 return ERROR_SUCCESS;
1163 if (needs_ui_sequence(package))
1164 rc = ACTION_PerformUIAction(package, action, -1);
1166 rc = ACTION_PerformAction(package, action, -1);
1168 msi_dialog_check_messages( NULL );
1170 if (package->CurrentInstallState != ERROR_SUCCESS)
1171 rc = package->CurrentInstallState;
1173 if (rc == ERROR_FUNCTION_NOT_CALLED)
1176 if (rc != ERROR_SUCCESS)
1177 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
1182 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
1186 static const WCHAR query[] =
1187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1189 ' ','W','H','E','R','E',' ',
1190 '`','S','e','q','u','e','n','c','e','`',' ',
1191 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1192 '`','S','e','q','u','e','n','c','e','`',0};
1194 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
1196 r = MSI_OpenQuery( package->db, &view, query, szTable );
1197 if (r == ERROR_SUCCESS)
1199 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
1200 msiobj_release(&view->hdr);
1206 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1210 static const WCHAR ExecSeqQuery[] =
1211 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1212 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1213 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1214 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1215 'O','R','D','E','R',' ', 'B','Y',' ',
1216 '`','S','e','q','u','e','n','c','e','`',0 };
1217 static const WCHAR IVQuery[] =
1218 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1219 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1220 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1221 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1222 ' ','\'', 'I','n','s','t','a','l','l',
1223 'V','a','l','i','d','a','t','e','\'', 0};
1226 if (package->script->ExecuteSequenceRun)
1228 TRACE("Execute Sequence already Run\n");
1229 return ERROR_SUCCESS;
1232 package->script->ExecuteSequenceRun = TRUE;
1234 /* get the sequence number */
1237 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
1239 return ERROR_FUNCTION_FAILED;
1240 seq = MSI_RecordGetInteger(row,1);
1241 msiobj_release(&row->hdr);
1244 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1245 if (rc == ERROR_SUCCESS)
1247 TRACE("Running the actions\n");
1249 msi_set_property(package->db, cszSourceDir, NULL);
1251 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1252 msiobj_release(&view->hdr);
1258 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1262 static const WCHAR ExecSeqQuery [] =
1263 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1264 '`','I','n','s','t','a','l','l',
1265 'U','I','S','e','q','u','e','n','c','e','`',
1266 ' ','W','H','E','R','E',' ',
1267 '`','S','e','q','u','e','n','c','e','`',' ',
1268 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1269 '`','S','e','q','u','e','n','c','e','`',0};
1271 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1272 if (rc == ERROR_SUCCESS)
1274 TRACE("Running the actions\n");
1276 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1277 msiobj_release(&view->hdr);
1283 /********************************************************
1284 * ACTION helper functions and functions that perform the actions
1285 *******************************************************/
1286 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1287 UINT* rc, UINT script, BOOL force )
1292 arc = ACTION_CustomAction(package, action, script, force);
1294 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1303 * Actual Action Handlers
1306 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1308 MSIPACKAGE *package = param;
1309 LPCWSTR dir, component;
1315 component = MSI_RecordGetString(row, 2);
1317 return ERROR_SUCCESS;
1319 comp = get_loaded_component(package, component);
1321 return ERROR_SUCCESS;
1325 TRACE("component is disabled\n");
1326 return ERROR_SUCCESS;
1329 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1331 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1332 comp->Action = comp->Installed;
1333 return ERROR_SUCCESS;
1335 comp->Action = INSTALLSTATE_LOCAL;
1337 dir = MSI_RecordGetString(row,1);
1340 ERR("Unable to get folder id\n");
1341 return ERROR_SUCCESS;
1344 uirow = MSI_CreateRecord(1);
1345 MSI_RecordSetStringW(uirow, 1, dir);
1346 ui_actiondata(package, szCreateFolders, uirow);
1347 msiobj_release(&uirow->hdr);
1349 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1352 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1353 return ERROR_SUCCESS;
1356 TRACE("Folder is %s\n",debugstr_w(full_path));
1358 if (folder->State == 0)
1359 create_full_pathW(full_path);
1363 msi_free(full_path);
1364 return ERROR_SUCCESS;
1367 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1369 static const WCHAR query[] =
1370 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1371 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1375 /* create all the empty folders specified in the CreateFolder table */
1376 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1377 if (rc != ERROR_SUCCESS)
1378 return ERROR_SUCCESS;
1380 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1381 msiobj_release(&view->hdr);
1386 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1388 MSIPACKAGE *package = param;
1389 LPCWSTR dir, component;
1395 component = MSI_RecordGetString(row, 2);
1397 return ERROR_SUCCESS;
1399 comp = get_loaded_component(package, component);
1401 return ERROR_SUCCESS;
1405 TRACE("component is disabled\n");
1406 return ERROR_SUCCESS;
1409 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1411 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1412 comp->Action = comp->Installed;
1413 return ERROR_SUCCESS;
1415 comp->Action = INSTALLSTATE_ABSENT;
1417 dir = MSI_RecordGetString( row, 1 );
1420 ERR("Unable to get folder id\n");
1421 return ERROR_SUCCESS;
1424 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1427 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1428 return ERROR_SUCCESS;
1431 TRACE("folder is %s\n", debugstr_w(full_path));
1433 uirow = MSI_CreateRecord( 1 );
1434 MSI_RecordSetStringW( uirow, 1, dir );
1435 ui_actiondata( package, szRemoveFolders, uirow );
1436 msiobj_release( &uirow->hdr );
1438 RemoveDirectoryW( full_path );
1441 msi_free( full_path );
1442 return ERROR_SUCCESS;
1445 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1447 static const WCHAR query[] =
1448 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1449 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1454 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1455 if (rc != ERROR_SUCCESS)
1456 return ERROR_SUCCESS;
1458 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1459 msiobj_release( &view->hdr );
1464 static UINT load_component( MSIRECORD *row, LPVOID param )
1466 MSIPACKAGE *package = param;
1469 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1471 return ERROR_FUNCTION_FAILED;
1473 list_add_tail( &package->components, &comp->entry );
1475 /* fill in the data */
1476 comp->Component = msi_dup_record_field( row, 1 );
1478 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1480 comp->ComponentId = msi_dup_record_field( row, 2 );
1481 comp->Directory = msi_dup_record_field( row, 3 );
1482 comp->Attributes = MSI_RecordGetInteger(row,4);
1483 comp->Condition = msi_dup_record_field( row, 5 );
1484 comp->KeyPath = msi_dup_record_field( row, 6 );
1486 comp->Installed = INSTALLSTATE_UNKNOWN;
1487 comp->Action = INSTALLSTATE_UNKNOWN;
1488 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1490 comp->assembly = load_assembly( package, comp );
1491 return ERROR_SUCCESS;
1494 static UINT load_all_components( MSIPACKAGE *package )
1496 static const WCHAR query[] = {
1497 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1498 '`','C','o','m','p','o','n','e','n','t','`',0 };
1502 if (!list_empty(&package->components))
1503 return ERROR_SUCCESS;
1505 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1506 if (r != ERROR_SUCCESS)
1509 r = MSI_IterateRecords(view, NULL, load_component, package);
1510 msiobj_release(&view->hdr);
1515 MSIPACKAGE *package;
1516 MSIFEATURE *feature;
1519 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1523 cl = msi_alloc( sizeof (*cl) );
1525 return ERROR_NOT_ENOUGH_MEMORY;
1526 cl->component = comp;
1527 list_add_tail( &feature->Components, &cl->entry );
1529 return ERROR_SUCCESS;
1532 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1536 fl = msi_alloc( sizeof(*fl) );
1538 return ERROR_NOT_ENOUGH_MEMORY;
1539 fl->feature = child;
1540 list_add_tail( &parent->Children, &fl->entry );
1542 return ERROR_SUCCESS;
1545 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1547 _ilfs* ilfs = param;
1551 component = MSI_RecordGetString(row,1);
1553 /* check to see if the component is already loaded */
1554 comp = get_loaded_component( ilfs->package, component );
1557 ERR("unknown component %s\n", debugstr_w(component));
1558 return ERROR_FUNCTION_FAILED;
1561 add_feature_component( ilfs->feature, comp );
1562 comp->Enabled = TRUE;
1564 return ERROR_SUCCESS;
1567 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1569 MSIFEATURE *feature;
1574 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1576 if ( !strcmpW( feature->Feature, name ) )
1583 static UINT load_feature(MSIRECORD * row, LPVOID param)
1585 MSIPACKAGE* package = param;
1586 MSIFEATURE* feature;
1587 static const WCHAR Query1[] =
1588 {'S','E','L','E','C','T',' ',
1589 '`','C','o','m','p','o','n','e','n','t','_','`',
1590 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1591 'C','o','m','p','o','n','e','n','t','s','`',' ',
1592 'W','H','E','R','E',' ',
1593 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1598 /* fill in the data */
1600 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1602 return ERROR_NOT_ENOUGH_MEMORY;
1604 list_init( &feature->Children );
1605 list_init( &feature->Components );
1607 feature->Feature = msi_dup_record_field( row, 1 );
1609 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1611 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1612 feature->Title = msi_dup_record_field( row, 3 );
1613 feature->Description = msi_dup_record_field( row, 4 );
1615 if (!MSI_RecordIsNull(row,5))
1616 feature->Display = MSI_RecordGetInteger(row,5);
1618 feature->Level= MSI_RecordGetInteger(row,6);
1619 feature->Directory = msi_dup_record_field( row, 7 );
1620 feature->Attributes = MSI_RecordGetInteger(row,8);
1622 feature->Installed = INSTALLSTATE_UNKNOWN;
1623 feature->Action = INSTALLSTATE_UNKNOWN;
1624 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1626 list_add_tail( &package->features, &feature->entry );
1628 /* load feature components */
1630 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1631 if (rc != ERROR_SUCCESS)
1632 return ERROR_SUCCESS;
1634 ilfs.package = package;
1635 ilfs.feature = feature;
1637 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1638 msiobj_release(&view->hdr);
1640 return ERROR_SUCCESS;
1643 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1645 MSIPACKAGE* package = param;
1646 MSIFEATURE *parent, *child;
1648 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1650 return ERROR_FUNCTION_FAILED;
1652 if (!child->Feature_Parent)
1653 return ERROR_SUCCESS;
1655 parent = find_feature_by_name( package, child->Feature_Parent );
1657 return ERROR_FUNCTION_FAILED;
1659 add_feature_child( parent, child );
1660 return ERROR_SUCCESS;
1663 static UINT load_all_features( MSIPACKAGE *package )
1665 static const WCHAR query[] = {
1666 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1667 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1668 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1672 if (!list_empty(&package->features))
1673 return ERROR_SUCCESS;
1675 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1676 if (r != ERROR_SUCCESS)
1679 r = MSI_IterateRecords( view, NULL, load_feature, package );
1680 if (r != ERROR_SUCCESS)
1683 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1684 msiobj_release( &view->hdr );
1689 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1700 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1702 static const WCHAR query[] = {
1703 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1704 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1705 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1706 MSIQUERY *view = NULL;
1707 MSIRECORD *row = NULL;
1710 TRACE("%s\n", debugstr_w(file->File));
1712 r = MSI_OpenQuery(package->db, &view, query, file->File);
1713 if (r != ERROR_SUCCESS)
1716 r = MSI_ViewExecute(view, NULL);
1717 if (r != ERROR_SUCCESS)
1720 r = MSI_ViewFetch(view, &row);
1721 if (r != ERROR_SUCCESS)
1724 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1725 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1726 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1727 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1728 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1731 if (view) msiobj_release(&view->hdr);
1732 if (row) msiobj_release(&row->hdr);
1736 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1739 static const WCHAR query[] = {
1740 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1741 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1742 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1744 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1747 WARN("query failed\n");
1748 return ERROR_FUNCTION_FAILED;
1751 file->disk_id = MSI_RecordGetInteger( row, 1 );
1752 msiobj_release( &row->hdr );
1753 return ERROR_SUCCESS;
1756 static UINT load_file(MSIRECORD *row, LPVOID param)
1758 MSIPACKAGE* package = param;
1762 /* fill in the data */
1764 file = msi_alloc_zero( sizeof (MSIFILE) );
1766 return ERROR_NOT_ENOUGH_MEMORY;
1768 file->File = msi_dup_record_field( row, 1 );
1770 component = MSI_RecordGetString( row, 2 );
1771 file->Component = get_loaded_component( package, component );
1773 if (!file->Component)
1775 WARN("Component not found: %s\n", debugstr_w(component));
1776 msi_free(file->File);
1778 return ERROR_SUCCESS;
1781 file->FileName = msi_dup_record_field( row, 3 );
1782 reduce_to_longfilename( file->FileName );
1784 file->ShortName = msi_dup_record_field( row, 3 );
1785 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1787 file->FileSize = MSI_RecordGetInteger( row, 4 );
1788 file->Version = msi_dup_record_field( row, 5 );
1789 file->Language = msi_dup_record_field( row, 6 );
1790 file->Attributes = MSI_RecordGetInteger( row, 7 );
1791 file->Sequence = MSI_RecordGetInteger( row, 8 );
1793 file->state = msifs_invalid;
1795 /* if the compressed bits are not set in the file attributes,
1796 * then read the information from the package word count property
1798 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1800 file->IsCompressed = FALSE;
1802 else if (file->Attributes &
1803 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1805 file->IsCompressed = TRUE;
1807 else if (file->Attributes & msidbFileAttributesNoncompressed)
1809 file->IsCompressed = FALSE;
1813 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1816 load_file_hash(package, file);
1817 load_file_disk_id(package, file);
1819 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1821 list_add_tail( &package->files, &file->entry );
1823 return ERROR_SUCCESS;
1826 static UINT load_all_files(MSIPACKAGE *package)
1830 static const WCHAR Query[] =
1831 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1832 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1833 '`','S','e','q','u','e','n','c','e','`', 0};
1835 if (!list_empty(&package->files))
1836 return ERROR_SUCCESS;
1838 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1839 if (rc != ERROR_SUCCESS)
1840 return ERROR_SUCCESS;
1842 rc = MSI_IterateRecords(view, NULL, load_file, package);
1843 msiobj_release(&view->hdr);
1845 return ERROR_SUCCESS;
1848 static UINT load_patch(MSIRECORD *row, LPVOID param)
1850 MSIPACKAGE *package = param;
1851 MSIFILEPATCH *patch;
1854 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1856 return ERROR_NOT_ENOUGH_MEMORY;
1858 file_key = msi_dup_record_field( row, 1 );
1859 patch->File = get_loaded_file( package, file_key );
1864 ERR("Failed to find target for patch in File table\n");
1866 return ERROR_FUNCTION_FAILED;
1869 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1871 /* FIXME: The database should be properly transformed */
1872 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1874 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1875 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1876 patch->IsApplied = FALSE;
1879 * Header field - for patch validation.
1880 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1883 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1885 list_add_tail( &package->filepatches, &patch->entry );
1887 return ERROR_SUCCESS;
1890 static UINT load_all_patches(MSIPACKAGE *package)
1894 static const WCHAR Query[] =
1895 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1896 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1897 '`','S','e','q','u','e','n','c','e','`',0};
1899 if (!list_empty(&package->filepatches))
1900 return ERROR_SUCCESS;
1902 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1903 if (rc != ERROR_SUCCESS)
1904 return ERROR_SUCCESS;
1906 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1907 msiobj_release(&view->hdr);
1909 return ERROR_SUCCESS;
1912 static UINT load_folder( MSIRECORD *row, LPVOID param )
1914 MSIPACKAGE *package = param;
1915 static WCHAR szEmpty[] = { 0 };
1916 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1919 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1921 return ERROR_NOT_ENOUGH_MEMORY;
1923 folder->Directory = msi_dup_record_field( row, 1 );
1925 TRACE("%s\n", debugstr_w(folder->Directory));
1927 p = msi_dup_record_field(row, 3);
1929 /* split src and target dir */
1931 src_short = folder_split_path( p, ':' );
1933 /* split the long and short paths */
1934 tgt_long = folder_split_path( tgt_short, '|' );
1935 src_long = folder_split_path( src_short, '|' );
1937 /* check for no-op dirs */
1938 if (tgt_short && !strcmpW( szDot, tgt_short ))
1939 tgt_short = szEmpty;
1940 if (src_short && !strcmpW( szDot, src_short ))
1941 src_short = szEmpty;
1944 tgt_long = tgt_short;
1947 src_short = tgt_short;
1948 src_long = tgt_long;
1952 src_long = src_short;
1954 /* FIXME: use the target short path too */
1955 folder->TargetDefault = strdupW(tgt_long);
1956 folder->SourceShortPath = strdupW(src_short);
1957 folder->SourceLongPath = strdupW(src_long);
1960 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1961 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1962 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1964 folder->Parent = msi_dup_record_field( row, 2 );
1966 folder->Property = msi_dup_property( package->db, folder->Directory );
1968 list_add_tail( &package->folders, &folder->entry );
1970 TRACE("returning %p\n", folder);
1972 return ERROR_SUCCESS;
1975 static UINT load_all_folders( MSIPACKAGE *package )
1977 static const WCHAR query[] = {
1978 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1979 '`','D','i','r','e','c','t','o','r','y','`',0 };
1983 if (!list_empty(&package->folders))
1984 return ERROR_SUCCESS;
1986 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1987 if (r != ERROR_SUCCESS)
1990 r = MSI_IterateRecords(view, NULL, load_folder, package);
1991 msiobj_release(&view->hdr);
1996 * I am not doing any of the costing functionality yet.
1997 * Mostly looking at doing the Component and Feature loading
1999 * The native MSI does A LOT of modification to tables here. Mostly adding
2000 * a lot of temporary columns to the Feature and Component tables.
2002 * note: Native msi also tracks the short filename. But I am only going to
2003 * track the long ones. Also looking at this directory table
2004 * it appears that the directory table does not get the parents
2005 * resolved base on property only based on their entries in the
2008 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
2010 static const WCHAR szCosting[] =
2011 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2013 msi_set_property( package->db, szCosting, szZero );
2014 msi_set_property( package->db, cszRootDrive, c_colon );
2016 load_all_folders( package );
2017 load_all_components( package );
2018 load_all_features( package );
2019 load_all_files( package );
2020 load_all_patches( package );
2022 return ERROR_SUCCESS;
2025 static UINT execute_script(MSIPACKAGE *package, UINT script )
2028 UINT rc = ERROR_SUCCESS;
2030 TRACE("Executing Script %i\n",script);
2032 if (!package->script)
2034 ERR("no script!\n");
2035 return ERROR_FUNCTION_FAILED;
2038 for (i = 0; i < package->script->ActionCount[script]; i++)
2041 action = package->script->Actions[script][i];
2042 ui_actionstart(package, action);
2043 TRACE("Executing Action (%s)\n",debugstr_w(action));
2044 rc = ACTION_PerformAction(package, action, script);
2045 if (rc != ERROR_SUCCESS)
2048 msi_free_action_script(package, script);
2052 static UINT ACTION_FileCost(MSIPACKAGE *package)
2054 return ERROR_SUCCESS;
2057 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
2062 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
2064 if (!comp->ComponentId) continue;
2066 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2067 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
2069 if (r != ERROR_SUCCESS)
2070 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2071 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
2073 if (r != ERROR_SUCCESS)
2074 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2075 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
2077 if (r != ERROR_SUCCESS)
2078 comp->Installed = INSTALLSTATE_ABSENT;
2082 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
2084 MSIFEATURE *feature;
2086 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2088 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
2090 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
2091 feature->Installed = INSTALLSTATE_ABSENT;
2093 feature->Installed = state;
2097 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
2099 return (feature->Level > 0 && feature->Level <= level);
2102 static BOOL process_state_property(MSIPACKAGE* package, int level,
2103 LPCWSTR property, INSTALLSTATE state)
2106 MSIFEATURE *feature;
2108 override = msi_dup_property( package->db, property );
2112 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2114 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
2117 if (!strcmpW(property, szReinstall)) state = feature->Installed;
2119 if (!strcmpiW( override, szAll ))
2121 if (feature->Installed != state)
2123 feature->Action = state;
2124 feature->ActionRequest = state;
2129 LPWSTR ptr = override;
2130 LPWSTR ptr2 = strchrW(override,',');
2134 int len = ptr2 - ptr;
2136 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
2137 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
2139 if (feature->Installed != state)
2141 feature->Action = state;
2142 feature->ActionRequest = state;
2149 ptr2 = strchrW(ptr,',');
2160 static BOOL process_overrides( MSIPACKAGE *package, int level )
2162 static const WCHAR szAddLocal[] =
2163 {'A','D','D','L','O','C','A','L',0};
2164 static const WCHAR szAddSource[] =
2165 {'A','D','D','S','O','U','R','C','E',0};
2166 static const WCHAR szAdvertise[] =
2167 {'A','D','V','E','R','T','I','S','E',0};
2170 /* all these activation/deactivation things happen in order and things
2171 * later on the list override things earlier on the list.
2173 * 0 INSTALLLEVEL processing
2186 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
2187 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
2188 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
2189 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
2190 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
2193 msi_set_property( package->db, szPreselected, szOne );
2198 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
2201 static const WCHAR szlevel[] =
2202 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2203 MSICOMPONENT* component;
2204 MSIFEATURE *feature;
2206 TRACE("Checking Install Level\n");
2208 level = msi_get_property_int(package->db, szlevel, 1);
2210 if (!msi_get_property_int( package->db, szPreselected, 0 ))
2212 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2214 if (!is_feature_selected( feature, level )) continue;
2216 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2218 if (feature->Attributes & msidbFeatureAttributesFavorSource)
2220 feature->Action = INSTALLSTATE_SOURCE;
2221 feature->ActionRequest = INSTALLSTATE_SOURCE;
2223 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2225 feature->Action = INSTALLSTATE_ADVERTISED;
2226 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
2230 feature->Action = INSTALLSTATE_LOCAL;
2231 feature->ActionRequest = INSTALLSTATE_LOCAL;
2236 /* disable child features of unselected parent features */
2237 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2241 if (is_feature_selected( feature, level )) continue;
2243 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
2245 fl->feature->Action = INSTALLSTATE_UNKNOWN;
2246 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
2250 else /* preselected */
2252 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2254 if (!is_feature_selected( feature, level )) continue;
2256 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2258 if (feature->Installed == INSTALLSTATE_ABSENT)
2260 feature->Action = INSTALLSTATE_UNKNOWN;
2261 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
2265 feature->Action = feature->Installed;
2266 feature->ActionRequest = feature->Installed;
2272 /* now we want to set component state based based on feature state */
2273 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2277 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
2278 debugstr_w(feature->Feature), feature->Level, feature->Installed,
2279 feature->ActionRequest, feature->Action);
2281 if (!is_feature_selected( feature, level )) continue;
2283 /* features with components that have compressed files are made local */
2284 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2286 if (cl->component->ForceLocalState &&
2287 feature->ActionRequest == INSTALLSTATE_SOURCE)
2289 feature->Action = INSTALLSTATE_LOCAL;
2290 feature->ActionRequest = INSTALLSTATE_LOCAL;
2295 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2297 component = cl->component;
2299 switch (feature->ActionRequest)
2301 case INSTALLSTATE_ABSENT:
2302 component->anyAbsent = 1;
2304 case INSTALLSTATE_ADVERTISED:
2305 component->hasAdvertiseFeature = 1;
2307 case INSTALLSTATE_SOURCE:
2308 component->hasSourceFeature = 1;
2310 case INSTALLSTATE_LOCAL:
2311 component->hasLocalFeature = 1;
2313 case INSTALLSTATE_DEFAULT:
2314 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2315 component->hasAdvertiseFeature = 1;
2316 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2317 component->hasSourceFeature = 1;
2319 component->hasLocalFeature = 1;
2327 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2329 /* check if it's local or source */
2330 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2331 (component->hasLocalFeature || component->hasSourceFeature))
2333 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2334 !component->ForceLocalState)
2336 component->Action = INSTALLSTATE_SOURCE;
2337 component->ActionRequest = INSTALLSTATE_SOURCE;
2341 component->Action = INSTALLSTATE_LOCAL;
2342 component->ActionRequest = INSTALLSTATE_LOCAL;
2347 /* if any feature is local, the component must be local too */
2348 if (component->hasLocalFeature)
2350 component->Action = INSTALLSTATE_LOCAL;
2351 component->ActionRequest = INSTALLSTATE_LOCAL;
2354 if (component->hasSourceFeature)
2356 component->Action = INSTALLSTATE_SOURCE;
2357 component->ActionRequest = INSTALLSTATE_SOURCE;
2360 if (component->hasAdvertiseFeature)
2362 component->Action = INSTALLSTATE_ADVERTISED;
2363 component->ActionRequest = INSTALLSTATE_ADVERTISED;
2366 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2367 if (component->anyAbsent &&
2368 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
2370 component->Action = INSTALLSTATE_ABSENT;
2371 component->ActionRequest = INSTALLSTATE_ABSENT;
2375 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2377 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2379 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2380 component->Action = INSTALLSTATE_LOCAL;
2381 component->ActionRequest = INSTALLSTATE_LOCAL;
2384 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2385 component->Installed == INSTALLSTATE_SOURCE &&
2386 component->hasSourceFeature)
2388 component->Action = INSTALLSTATE_UNKNOWN;
2389 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2392 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2393 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2396 return ERROR_SUCCESS;
2399 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2401 MSIPACKAGE *package = param;
2406 name = MSI_RecordGetString(row,1);
2408 f = get_loaded_folder(package, name);
2409 if (!f) return ERROR_SUCCESS;
2411 /* reset the ResolvedTarget */
2412 msi_free(f->ResolvedTarget);
2413 f->ResolvedTarget = NULL;
2415 TRACE("directory %s ...\n", debugstr_w(name));
2416 path = resolve_target_folder( package, name, TRUE, TRUE, NULL );
2417 TRACE("resolves to %s\n", debugstr_w(path));
2420 return ERROR_SUCCESS;
2423 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2425 MSIPACKAGE *package = param;
2427 MSIFEATURE *feature;
2429 name = MSI_RecordGetString( row, 1 );
2431 feature = get_loaded_feature( package, name );
2433 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2437 Condition = MSI_RecordGetString(row,3);
2439 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2441 int level = MSI_RecordGetInteger(row,2);
2442 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2443 feature->Level = level;
2446 return ERROR_SUCCESS;
2449 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2451 static const WCHAR name[] = {'\\',0};
2452 VS_FIXEDFILEINFO *ptr, *ret;
2454 DWORD versize, handle;
2457 TRACE("%s\n", debugstr_w(filename));
2459 versize = GetFileVersionInfoSizeW( filename, &handle );
2463 version = msi_alloc( versize );
2467 GetFileVersionInfoW( filename, 0, versize, version );
2469 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2471 msi_free( version );
2475 ret = msi_alloc( sz );
2476 memcpy( ret, ptr, sz );
2478 msi_free( version );
2482 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2486 msi_parse_version_string( version, &ms, &ls );
2488 if (fi->dwFileVersionMS > ms) return 1;
2489 else if (fi->dwFileVersionMS < ms) return -1;
2490 else if (fi->dwFileVersionLS > ls) return 1;
2491 else if (fi->dwFileVersionLS < ls) return -1;
2495 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2499 msi_parse_version_string( ver1, &ms1, NULL );
2500 msi_parse_version_string( ver2, &ms2, NULL );
2502 if (ms1 > ms2) return 1;
2503 else if (ms1 < ms2) return -1;
2507 DWORD msi_get_disk_file_size( LPCWSTR filename )
2512 TRACE("%s\n", debugstr_w(filename));
2514 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2515 if (file == INVALID_HANDLE_VALUE)
2516 return INVALID_FILE_SIZE;
2518 size = GetFileSize( file, NULL );
2519 CloseHandle( file );
2523 BOOL msi_file_hash_matches( MSIFILE *file )
2526 MSIFILEHASHINFO hash;
2528 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2529 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2530 if (r != ERROR_SUCCESS)
2533 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2536 static WCHAR *get_temp_dir( void )
2539 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2541 GetTempPathW( MAX_PATH, tmp );
2544 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2545 if (CreateDirectoryW( dir, NULL )) break;
2547 return strdupW( dir );
2550 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2552 MSIASSEMBLY *assembly = file->Component->assembly;
2554 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2556 msi_free( file->TargetPath );
2557 if (assembly && !assembly->application)
2559 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2560 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2561 track_tempfile( package, file->TargetPath );
2565 WCHAR *dir = resolve_target_folder( package, file->Component->Directory, FALSE, TRUE, NULL );
2566 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2570 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2573 static UINT calculate_file_cost( MSIPACKAGE *package )
2575 VS_FIXEDFILEINFO *file_version;
2576 WCHAR *font_version;
2579 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2581 MSICOMPONENT *comp = file->Component;
2584 if (!comp->Enabled) continue;
2586 if (file->IsCompressed)
2587 comp->ForceLocalState = TRUE;
2589 set_target_path( package, file );
2591 if ((comp->assembly && !comp->assembly->installed) ||
2592 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2594 comp->Cost += file->FileSize;
2597 file_size = msi_get_disk_file_size( file->TargetPath );
2601 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2603 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2605 comp->Cost += file->FileSize - file_size;
2607 msi_free( file_version );
2610 else if ((font_version = font_version_from_file( file->TargetPath )))
2612 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2614 comp->Cost += file->FileSize - file_size;
2616 msi_free( font_version );
2620 if (file_size != file->FileSize)
2622 comp->Cost += file->FileSize - file_size;
2625 return ERROR_SUCCESS;
2629 * A lot is done in this function aside from just the costing.
2630 * The costing needs to be implemented at some point but for now I am going
2631 * to focus on the directory building
2634 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2636 static const WCHAR ExecSeqQuery[] =
2637 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2638 '`','D','i','r','e','c','t','o','r','y','`',0};
2639 static const WCHAR ConditionQuery[] =
2640 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2641 '`','C','o','n','d','i','t','i','o','n','`',0};
2642 static const WCHAR szCosting[] =
2643 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2644 static const WCHAR szlevel[] =
2645 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2646 static const WCHAR szOutOfDiskSpace[] =
2647 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2649 UINT rc = ERROR_SUCCESS;
2653 TRACE("Building Directory properties\n");
2655 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2656 if (rc == ERROR_SUCCESS)
2658 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2660 msiobj_release(&view->hdr);
2663 TRACE("Evaluating component conditions\n");
2664 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2666 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2668 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2669 comp->Enabled = FALSE;
2672 comp->Enabled = TRUE;
2675 /* read components states from the registry */
2676 ACTION_GetComponentInstallStates(package);
2677 ACTION_GetFeatureInstallStates(package);
2679 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2681 TRACE("Evaluating feature conditions\n");
2683 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2684 if (rc == ERROR_SUCCESS)
2686 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2687 msiobj_release( &view->hdr );
2691 TRACE("Calculating file cost\n");
2692 calculate_file_cost( package );
2694 msi_set_property( package->db, szCosting, szOne );
2695 /* set default run level if not set */
2696 level = msi_dup_property( package->db, szlevel );
2698 msi_set_property( package->db, szlevel, szOne );
2701 /* FIXME: check volume disk space */
2702 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2704 return MSI_SetFeatureStates(package);
2707 /* OK this value is "interpreted" and then formatted based on the
2708 first few characters */
2709 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2714 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2720 LPWSTR deformated = NULL;
2723 deformat_string(package, &value[2], &deformated);
2725 /* binary value type */
2729 *size = (strlenW(ptr)/2)+1;
2731 *size = strlenW(ptr)/2;
2733 data = msi_alloc(*size);
2739 /* if uneven pad with a zero in front */
2745 data[count] = (BYTE)strtol(byte,NULL,0);
2747 TRACE("Uneven byte count\n");
2755 data[count] = (BYTE)strtol(byte,NULL,0);
2758 msi_free(deformated);
2760 TRACE("Data %i bytes(%i)\n",*size,count);
2767 deformat_string(package, &value[1], &deformated);
2770 *size = sizeof(DWORD);
2771 data = msi_alloc(*size);
2777 if ( (*p < '0') || (*p > '9') )
2783 if (deformated[0] == '-')
2786 TRACE("DWORD %i\n",*(LPDWORD)data);
2788 msi_free(deformated);
2793 static const WCHAR szMulti[] = {'[','~',']',0};
2802 *type=REG_EXPAND_SZ;
2810 if (strstrW(value, szMulti))
2811 *type = REG_MULTI_SZ;
2813 /* remove initial delimiter */
2814 if (!strncmpW(value, szMulti, 3))
2817 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2819 /* add double NULL terminator */
2820 if (*type == REG_MULTI_SZ)
2822 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2823 data = msi_realloc_zero(data, *size);
2829 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2836 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2838 *root_key = HKEY_LOCAL_MACHINE;
2843 *root_key = HKEY_CURRENT_USER;
2848 *root_key = HKEY_CLASSES_ROOT;
2852 *root_key = HKEY_CURRENT_USER;
2856 *root_key = HKEY_LOCAL_MACHINE;
2860 *root_key = HKEY_USERS;
2864 ERR("Unknown root %i\n", root);
2871 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2873 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2874 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2876 if (is_64bit && package->platform == PLATFORM_INTEL &&
2877 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2882 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2883 path_32node = msi_alloc( size );
2887 memcpy( path_32node, path, len * sizeof(WCHAR) );
2888 path_32node[len] = 0;
2889 strcatW( path_32node, szWow6432Node );
2890 strcatW( path_32node, szBackSlash );
2891 strcatW( path_32node, path + len );
2895 return strdupW( path );
2898 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2900 MSIPACKAGE *package = param;
2901 LPSTR value_data = NULL;
2902 HKEY root_key, hkey;
2904 LPWSTR deformated, uikey, keypath;
2905 LPCWSTR szRoot, component, name, key, value;
2909 BOOL check_first = FALSE;
2912 ui_progress(package,2,0,0,0);
2914 component = MSI_RecordGetString(row, 6);
2915 comp = get_loaded_component(package,component);
2917 return ERROR_SUCCESS;
2921 TRACE("component is disabled\n");
2922 return ERROR_SUCCESS;
2925 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2927 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2928 comp->Action = comp->Installed;
2929 return ERROR_SUCCESS;
2931 comp->Action = INSTALLSTATE_LOCAL;
2933 name = MSI_RecordGetString(row, 4);
2934 if( MSI_RecordIsNull(row,5) && name )
2936 /* null values can have special meanings */
2937 if (name[0]=='-' && name[1] == 0)
2938 return ERROR_SUCCESS;
2939 else if ((name[0]=='+' && name[1] == 0) ||
2940 (name[0] == '*' && name[1] == 0))
2945 root = MSI_RecordGetInteger(row,2);
2946 key = MSI_RecordGetString(row, 3);
2948 szRoot = get_root_key( package, root, &root_key );
2950 return ERROR_SUCCESS;
2952 deformat_string(package, key , &deformated);
2953 size = strlenW(deformated) + strlenW(szRoot) + 1;
2954 uikey = msi_alloc(size*sizeof(WCHAR));
2955 strcpyW(uikey,szRoot);
2956 strcatW(uikey,deformated);
2958 keypath = get_keypath( package, root_key, deformated );
2959 msi_free( deformated );
2960 if (RegCreateKeyW( root_key, keypath, &hkey ))
2962 ERR("Could not create key %s\n", debugstr_w(keypath));
2965 return ERROR_SUCCESS;
2968 value = MSI_RecordGetString(row,5);
2970 value_data = parse_value(package, value, &type, &size);
2973 value_data = (LPSTR)strdupW(szEmpty);
2974 size = sizeof(szEmpty);
2978 deformat_string(package, name, &deformated);
2982 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2984 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2989 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2990 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2992 TRACE("value %s of %s checked already exists\n",
2993 debugstr_w(deformated), debugstr_w(uikey));
2997 TRACE("Checked and setting value %s of %s\n",
2998 debugstr_w(deformated), debugstr_w(uikey));
2999 if (deformated || size)
3000 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
3005 uirow = MSI_CreateRecord(3);
3006 MSI_RecordSetStringW(uirow,2,deformated);
3007 MSI_RecordSetStringW(uirow,1,uikey);
3008 if (type == REG_SZ || type == REG_EXPAND_SZ)
3009 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3010 ui_actiondata(package,szWriteRegistryValues,uirow);
3011 msiobj_release( &uirow->hdr );
3013 msi_free(value_data);
3014 msi_free(deformated);
3018 return ERROR_SUCCESS;
3021 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3025 static const WCHAR ExecSeqQuery[] =
3026 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3027 '`','R','e','g','i','s','t','r','y','`',0 };
3029 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3030 if (rc != ERROR_SUCCESS)
3031 return ERROR_SUCCESS;
3033 /* increment progress bar each time action data is sent */
3034 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3036 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
3038 msiobj_release(&view->hdr);
3042 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
3046 DWORD num_subkeys, num_values;
3050 if ((res = RegDeleteTreeW( hkey_root, key )))
3052 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
3057 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
3059 if ((res = RegDeleteValueW( hkey, value )))
3061 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
3063 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
3064 NULL, NULL, NULL, NULL );
3065 RegCloseKey( hkey );
3066 if (!res && !num_subkeys && !num_values)
3068 TRACE("Removing empty key %s\n", debugstr_w(key));
3069 RegDeleteKeyW( hkey_root, key );
3073 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
3077 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
3079 MSIPACKAGE *package = param;
3080 LPCWSTR component, name, key_str, root_key_str;
3081 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3084 BOOL delete_key = FALSE;
3089 ui_progress( package, 2, 0, 0, 0 );
3091 component = MSI_RecordGetString( row, 6 );
3092 comp = get_loaded_component( package, component );
3094 return ERROR_SUCCESS;
3098 TRACE("component is disabled\n");
3099 return ERROR_SUCCESS;
3102 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3104 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
3105 comp->Action = comp->Installed;
3106 return ERROR_SUCCESS;
3108 comp->Action = INSTALLSTATE_ABSENT;
3110 name = MSI_RecordGetString( row, 4 );
3111 if (MSI_RecordIsNull( row, 5 ) && name )
3113 if (name[0] == '+' && !name[1])
3114 return ERROR_SUCCESS;
3115 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
3122 root = MSI_RecordGetInteger( row, 2 );
3123 key_str = MSI_RecordGetString( row, 3 );
3125 root_key_str = get_root_key( package, root, &hkey_root );
3127 return ERROR_SUCCESS;
3129 deformat_string( package, key_str, &deformated_key );
3130 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3131 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3132 strcpyW( ui_key_str, root_key_str );
3133 strcatW( ui_key_str, deformated_key );
3135 deformat_string( package, name, &deformated_name );
3137 keypath = get_keypath( package, hkey_root, deformated_key );
3138 msi_free( deformated_key );
3139 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
3140 msi_free( keypath );
3142 uirow = MSI_CreateRecord( 2 );
3143 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3144 MSI_RecordSetStringW( uirow, 2, deformated_name );
3146 ui_actiondata( package, szRemoveRegistryValues, uirow );
3147 msiobj_release( &uirow->hdr );
3149 msi_free( ui_key_str );
3150 msi_free( deformated_name );
3151 return ERROR_SUCCESS;
3154 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
3156 MSIPACKAGE *package = param;
3157 LPCWSTR component, name, key_str, root_key_str;
3158 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3161 BOOL delete_key = FALSE;
3166 ui_progress( package, 2, 0, 0, 0 );
3168 component = MSI_RecordGetString( row, 5 );
3169 comp = get_loaded_component( package, component );
3171 return ERROR_SUCCESS;
3175 TRACE("component is disabled\n");
3176 return ERROR_SUCCESS;
3179 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3181 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3182 comp->Action = comp->Installed;
3183 return ERROR_SUCCESS;
3185 comp->Action = INSTALLSTATE_LOCAL;
3187 if ((name = MSI_RecordGetString( row, 4 )))
3189 if (name[0] == '-' && !name[1])
3196 root = MSI_RecordGetInteger( row, 2 );
3197 key_str = MSI_RecordGetString( row, 3 );
3199 root_key_str = get_root_key( package, root, &hkey_root );
3201 return ERROR_SUCCESS;
3203 deformat_string( package, key_str, &deformated_key );
3204 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3205 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3206 strcpyW( ui_key_str, root_key_str );
3207 strcatW( ui_key_str, deformated_key );
3209 deformat_string( package, name, &deformated_name );
3211 keypath = get_keypath( package, hkey_root, deformated_key );
3212 msi_free( deformated_key );
3213 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
3214 msi_free( keypath );
3216 uirow = MSI_CreateRecord( 2 );
3217 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3218 MSI_RecordSetStringW( uirow, 2, deformated_name );
3220 ui_actiondata( package, szRemoveRegistryValues, uirow );
3221 msiobj_release( &uirow->hdr );
3223 msi_free( ui_key_str );
3224 msi_free( deformated_name );
3225 return ERROR_SUCCESS;
3228 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3232 static const WCHAR registry_query[] =
3233 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3234 '`','R','e','g','i','s','t','r','y','`',0 };
3235 static const WCHAR remove_registry_query[] =
3236 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3237 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
3239 /* increment progress bar each time action data is sent */
3240 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
3242 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3243 if (rc == ERROR_SUCCESS)
3245 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3246 msiobj_release( &view->hdr );
3247 if (rc != ERROR_SUCCESS)
3251 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3252 if (rc == ERROR_SUCCESS)
3254 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3255 msiobj_release( &view->hdr );
3256 if (rc != ERROR_SUCCESS)
3260 return ERROR_SUCCESS;
3263 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3265 package->script->CurrentlyScripting = TRUE;
3267 return ERROR_SUCCESS;
3271 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3276 static const WCHAR q1[]=
3277 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3278 '`','R','e','g','i','s','t','r','y','`',0};
3281 MSIFEATURE *feature;
3284 TRACE("InstallValidate\n");
3286 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3287 if (rc == ERROR_SUCCESS)
3289 MSI_IterateRecords( view, &progress, NULL, package );
3290 msiobj_release( &view->hdr );
3291 total += progress * REG_PROGRESS_VALUE;
3294 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3295 total += COMPONENT_PROGRESS_VALUE;
3297 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3298 total += file->FileSize;
3300 ui_progress(package,0,total,0,0);
3302 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3304 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3305 debugstr_w(feature->Feature), feature->Installed,
3306 feature->ActionRequest, feature->Action);
3309 return ERROR_SUCCESS;
3312 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3314 MSIPACKAGE* package = param;
3315 LPCWSTR cond = NULL;
3316 LPCWSTR message = NULL;
3319 static const WCHAR title[]=
3320 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3322 cond = MSI_RecordGetString(row,1);
3324 r = MSI_EvaluateConditionW(package,cond);
3325 if (r == MSICONDITION_FALSE)
3327 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3330 message = MSI_RecordGetString(row,2);
3331 deformat_string(package,message,&deformated);
3332 MessageBoxW(NULL,deformated,title,MB_OK);
3333 msi_free(deformated);
3336 return ERROR_INSTALL_FAILURE;
3339 return ERROR_SUCCESS;
3342 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3345 MSIQUERY * view = NULL;
3346 static const WCHAR ExecSeqQuery[] =
3347 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3348 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3350 TRACE("Checking launch conditions\n");
3352 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3353 if (rc != ERROR_SUCCESS)
3354 return ERROR_SUCCESS;
3356 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3357 msiobj_release(&view->hdr);
3362 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3366 return resolve_target_folder( package, cmp->Directory, FALSE, TRUE, NULL );
3368 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3370 MSIRECORD * row = 0;
3372 LPWSTR deformated,buffer,deformated_name;
3374 static const WCHAR ExecSeqQuery[] =
3375 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3376 '`','R','e','g','i','s','t','r','y','`',' ',
3377 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3378 ' ','=',' ' ,'\'','%','s','\'',0 };
3379 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3380 static const WCHAR fmt2[]=
3381 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3383 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3387 root = MSI_RecordGetInteger(row,2);
3388 key = MSI_RecordGetString(row, 3);
3389 name = MSI_RecordGetString(row, 4);
3390 deformat_string(package, key , &deformated);
3391 deformat_string(package, name, &deformated_name);
3393 len = strlenW(deformated) + 6;
3394 if (deformated_name)
3395 len+=strlenW(deformated_name);
3397 buffer = msi_alloc( len *sizeof(WCHAR));
3399 if (deformated_name)
3400 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3402 sprintfW(buffer,fmt,root,deformated);
3404 msi_free(deformated);
3405 msi_free(deformated_name);
3406 msiobj_release(&row->hdr);
3410 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3412 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3417 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3420 return strdupW( file->TargetPath );
3425 static HKEY openSharedDLLsKey(void)
3428 static const WCHAR path[] =
3429 {'S','o','f','t','w','a','r','e','\\',
3430 'M','i','c','r','o','s','o','f','t','\\',
3431 'W','i','n','d','o','w','s','\\',
3432 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3433 'S','h','a','r','e','d','D','L','L','s',0};
3435 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3439 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3444 DWORD sz = sizeof(count);
3447 hkey = openSharedDLLsKey();
3448 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3449 if (rc != ERROR_SUCCESS)
3455 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3459 hkey = openSharedDLLsKey();
3461 msi_reg_set_val_dword( hkey, path, count );
3463 RegDeleteValueW(hkey,path);
3468 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3470 MSIFEATURE *feature;
3474 /* only refcount DLLs */
3475 if (comp->KeyPath == NULL ||
3477 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3478 comp->Attributes & msidbComponentAttributesODBCDataSource)
3482 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3483 write = (count > 0);
3485 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3489 /* increment counts */
3490 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3494 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3497 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3499 if ( cl->component == comp )
3504 /* decrement counts */
3505 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3509 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3512 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3514 if ( cl->component == comp )
3519 /* ref count all the files in the component */
3524 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3526 if (file->Component == comp)
3527 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3531 /* add a count for permanent */
3532 if (comp->Attributes & msidbComponentAttributesPermanent)
3535 comp->RefCount = count;
3538 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3541 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3543 WCHAR squished_pc[GUID_SIZE];
3544 WCHAR squished_cc[GUID_SIZE];
3551 squash_guid(package->ProductCode,squished_pc);
3552 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3554 msi_set_sourcedir_props(package, FALSE);
3556 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3560 ui_progress(package,2,0,0,0);
3561 if (!comp->ComponentId)
3564 squash_guid(comp->ComponentId,squished_cc);
3566 msi_free(comp->FullKeypath);
3569 const WCHAR prefixW[] = {'<','\\',0};
3570 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3572 comp->FullKeypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3573 if (comp->FullKeypath)
3575 strcpyW( comp->FullKeypath, prefixW );
3576 strcatW( comp->FullKeypath, comp->assembly->display_name );
3579 else comp->FullKeypath = resolve_keypath( package, comp );
3581 ACTION_RefCountComponent( package, comp );
3583 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3584 debugstr_w(comp->Component),
3585 debugstr_w(squished_cc),
3586 debugstr_w(comp->FullKeypath),
3588 comp->ActionRequest);
3590 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3591 comp->ActionRequest == INSTALLSTATE_SOURCE)
3593 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3594 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3596 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3598 if (rc != ERROR_SUCCESS)
3601 if (comp->Attributes & msidbComponentAttributesPermanent)
3603 static const WCHAR szPermKey[] =
3604 { '0','0','0','0','0','0','0','0','0','0','0','0',
3605 '0','0','0','0','0','0','0','0','0','0','0','0',
3606 '0','0','0','0','0','0','0','0',0 };
3608 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3611 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3612 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3618 WCHAR source[MAX_PATH];
3619 WCHAR base[MAX_PATH];
3622 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3623 static const WCHAR query[] = {
3624 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3625 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3626 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3627 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3628 '`','D','i','s','k','I','d','`',0};
3630 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3633 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3634 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3635 ptr2 = strrchrW(source, '\\') + 1;
3636 msiobj_release(&row->hdr);
3638 lstrcpyW(base, package->PackagePath);
3639 ptr = strrchrW(base, '\\');
3642 sourcepath = resolve_file_source(package, file);
3643 ptr = sourcepath + lstrlenW(base);
3644 lstrcpyW(ptr2, ptr);
3645 msi_free(sourcepath);
3647 msi_reg_set_val_str(hkey, squished_pc, source);
3651 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3653 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3654 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3656 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3658 comp->Action = comp->ActionRequest;
3661 uirow = MSI_CreateRecord(3);
3662 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3663 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3664 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3665 ui_actiondata(package,szProcessComponents,uirow);
3666 msiobj_release( &uirow->hdr );
3669 return ERROR_SUCCESS;
3680 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3681 LPWSTR lpszName, LONG_PTR lParam)
3684 typelib_struct *tl_struct = (typelib_struct*) lParam;
3685 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3689 if (!IS_INTRESOURCE(lpszName))
3691 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3695 sz = strlenW(tl_struct->source)+4;
3696 sz *= sizeof(WCHAR);
3698 if ((INT_PTR)lpszName == 1)
3699 tl_struct->path = strdupW(tl_struct->source);
3702 tl_struct->path = msi_alloc(sz);
3703 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3706 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3707 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3710 msi_free(tl_struct->path);
3711 tl_struct->path = NULL;
3716 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3717 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3719 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3723 msi_free(tl_struct->path);
3724 tl_struct->path = NULL;
3726 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3727 ITypeLib_Release(tl_struct->ptLib);
3732 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3734 MSIPACKAGE* package = param;
3738 typelib_struct tl_struct;
3743 component = MSI_RecordGetString(row,3);
3744 comp = get_loaded_component(package,component);
3746 return ERROR_SUCCESS;
3750 TRACE("component is disabled\n");
3751 return ERROR_SUCCESS;
3754 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3756 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3757 comp->Action = comp->Installed;
3758 return ERROR_SUCCESS;
3760 comp->Action = INSTALLSTATE_LOCAL;
3762 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3764 TRACE("component has no key path\n");
3765 return ERROR_SUCCESS;
3767 ui_actiondata( package, szRegisterTypeLibraries, row );
3769 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3773 guid = MSI_RecordGetString(row,1);
3774 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3775 tl_struct.source = strdupW( file->TargetPath );
3776 tl_struct.path = NULL;
3778 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3779 (LONG_PTR)&tl_struct);
3787 helpid = MSI_RecordGetString(row,6);
3789 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3790 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3794 ERR("Failed to register type library %s\n",
3795 debugstr_w(tl_struct.path));
3797 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3799 ITypeLib_Release(tl_struct.ptLib);
3800 msi_free(tl_struct.path);
3803 ERR("Failed to load type library %s\n",
3804 debugstr_w(tl_struct.source));
3806 FreeLibrary(module);
3807 msi_free(tl_struct.source);
3811 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3814 ERR("Failed to load type library: %08x\n", hr);
3815 return ERROR_INSTALL_FAILURE;
3818 ITypeLib_Release(tlib);
3821 return ERROR_SUCCESS;
3824 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3827 * OK this is a bit confusing.. I am given a _Component key and I believe
3828 * that the file that is being registered as a type library is the "key file
3829 * of that component" which I interpret to mean "The file in the KeyPath of
3834 static const WCHAR Query[] =
3835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3836 '`','T','y','p','e','L','i','b','`',0};
3838 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3839 if (rc != ERROR_SUCCESS)
3840 return ERROR_SUCCESS;
3842 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3843 msiobj_release(&view->hdr);
3847 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3849 MSIPACKAGE *package = param;
3850 LPCWSTR component, guid;
3858 component = MSI_RecordGetString( row, 3 );
3859 comp = get_loaded_component( package, component );
3861 return ERROR_SUCCESS;
3865 TRACE("component is disabled\n");
3866 return ERROR_SUCCESS;
3869 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3871 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3872 comp->Action = comp->Installed;
3873 return ERROR_SUCCESS;
3875 comp->Action = INSTALLSTATE_ABSENT;
3877 ui_actiondata( package, szUnregisterTypeLibraries, row );
3879 guid = MSI_RecordGetString( row, 1 );
3880 CLSIDFromString( (LPCWSTR)guid, &libid );
3881 version = MSI_RecordGetInteger( row, 4 );
3882 language = MSI_RecordGetInteger( row, 2 );
3885 syskind = SYS_WIN64;
3887 syskind = SYS_WIN32;
3890 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3893 WARN("Failed to unregister typelib: %08x\n", hr);
3896 return ERROR_SUCCESS;
3899 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3903 static const WCHAR query[] =
3904 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3905 '`','T','y','p','e','L','i','b','`',0};
3907 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3908 if (rc != ERROR_SUCCESS)
3909 return ERROR_SUCCESS;
3911 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3912 msiobj_release( &view->hdr );
3916 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3918 static const WCHAR szlnk[] = {'.','l','n','k',0};
3919 LPCWSTR directory, extension;
3920 LPWSTR link_folder, link_file, filename;
3922 directory = MSI_RecordGetString( row, 2 );
3923 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
3925 /* may be needed because of a bug somewhere else */
3926 create_full_pathW( link_folder );
3928 filename = msi_dup_record_field( row, 3 );
3929 reduce_to_longfilename( filename );
3931 extension = strchrW( filename, '.' );
3932 if (!extension || strcmpiW( extension, szlnk ))
3934 int len = strlenW( filename );
3935 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3936 memcpy( filename + len, szlnk, sizeof(szlnk) );
3938 link_file = build_directory_name( 2, link_folder, filename );
3939 msi_free( link_folder );
3940 msi_free( filename );
3945 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3947 MSIPACKAGE *package = param;
3948 LPWSTR link_file, deformated, path;
3949 LPCWSTR component, target;
3951 IShellLinkW *sl = NULL;
3952 IPersistFile *pf = NULL;
3955 component = MSI_RecordGetString(row, 4);
3956 comp = get_loaded_component(package, component);
3958 return ERROR_SUCCESS;
3962 TRACE("component is disabled\n");
3963 return ERROR_SUCCESS;
3966 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3968 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3969 comp->Action = comp->Installed;
3970 return ERROR_SUCCESS;
3972 comp->Action = INSTALLSTATE_LOCAL;
3974 ui_actiondata(package,szCreateShortcuts,row);
3976 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3977 &IID_IShellLinkW, (LPVOID *) &sl );
3981 ERR("CLSID_ShellLink not available\n");
3985 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3988 ERR("QueryInterface(IID_IPersistFile) failed\n");
3992 target = MSI_RecordGetString(row, 5);
3993 if (strchrW(target, '['))
3995 deformat_string(package, target, &deformated);
3996 IShellLinkW_SetPath(sl,deformated);
3997 msi_free(deformated);
4001 FIXME("poorly handled shortcut format, advertised shortcut\n");
4002 IShellLinkW_SetPath(sl,comp->FullKeypath);
4005 if (!MSI_RecordIsNull(row,6))
4007 LPCWSTR arguments = MSI_RecordGetString(row, 6);
4008 deformat_string(package, arguments, &deformated);
4009 IShellLinkW_SetArguments(sl,deformated);
4010 msi_free(deformated);
4013 if (!MSI_RecordIsNull(row,7))
4015 LPCWSTR description = MSI_RecordGetString(row, 7);
4016 IShellLinkW_SetDescription(sl, description);
4019 if (!MSI_RecordIsNull(row,8))
4020 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4022 if (!MSI_RecordIsNull(row,9))
4025 LPCWSTR icon = MSI_RecordGetString(row, 9);
4027 path = build_icon_path(package, icon);
4028 index = MSI_RecordGetInteger(row,10);
4030 /* no value means 0 */
4031 if (index == MSI_NULL_INTEGER)
4034 IShellLinkW_SetIconLocation(sl, path, index);
4038 if (!MSI_RecordIsNull(row,11))
4039 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4041 if (!MSI_RecordIsNull(row,12))
4043 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
4044 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
4046 IShellLinkW_SetWorkingDirectory(sl, path);
4050 link_file = get_link_file(package, row);
4052 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
4053 IPersistFile_Save(pf, link_file, FALSE);
4055 msi_free(link_file);
4059 IPersistFile_Release( pf );
4061 IShellLinkW_Release( sl );
4063 return ERROR_SUCCESS;
4066 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
4071 static const WCHAR Query[] =
4072 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4073 '`','S','h','o','r','t','c','u','t','`',0};
4075 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4076 if (rc != ERROR_SUCCESS)
4077 return ERROR_SUCCESS;
4079 res = CoInitialize( NULL );
4081 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
4082 msiobj_release(&view->hdr);
4090 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
4092 MSIPACKAGE *package = param;
4097 component = MSI_RecordGetString( row, 4 );
4098 comp = get_loaded_component( package, component );
4100 return ERROR_SUCCESS;
4104 TRACE("component is disabled\n");
4105 return ERROR_SUCCESS;
4108 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4110 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4111 comp->Action = comp->Installed;
4112 return ERROR_SUCCESS;
4114 comp->Action = INSTALLSTATE_ABSENT;
4116 ui_actiondata( package, szRemoveShortcuts, row );
4118 link_file = get_link_file( package, row );
4120 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
4121 if (!DeleteFileW( link_file ))
4123 WARN("Failed to remove shortcut file %u\n", GetLastError());
4125 msi_free( link_file );
4127 return ERROR_SUCCESS;
4130 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4134 static const WCHAR query[] =
4135 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4136 '`','S','h','o','r','t','c','u','t','`',0};
4138 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4139 if (rc != ERROR_SUCCESS)
4140 return ERROR_SUCCESS;
4142 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
4143 msiobj_release( &view->hdr );
4148 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
4150 MSIPACKAGE* package = param;
4158 FileName = MSI_RecordGetString(row,1);
4161 ERR("Unable to get FileName\n");
4162 return ERROR_SUCCESS;
4165 FilePath = build_icon_path(package,FileName);
4167 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4169 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4170 FILE_ATTRIBUTE_NORMAL, NULL);
4172 if (the_file == INVALID_HANDLE_VALUE)
4174 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4176 return ERROR_SUCCESS;
4183 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4184 if (rc != ERROR_SUCCESS)
4186 ERR("Failed to get stream\n");
4187 CloseHandle(the_file);
4188 DeleteFileW(FilePath);
4191 WriteFile(the_file,buffer,sz,&write,NULL);
4192 } while (sz == 1024);
4195 CloseHandle(the_file);
4197 return ERROR_SUCCESS;
4200 static UINT msi_publish_icons(MSIPACKAGE *package)
4205 static const WCHAR query[]= {
4206 'S','E','L','E','C','T',' ','*',' ',
4207 'F','R','O','M',' ','`','I','c','o','n','`',0};
4209 r = MSI_DatabaseOpenViewW(package->db, query, &view);
4210 if (r == ERROR_SUCCESS)
4212 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
4213 msiobj_release(&view->hdr);
4216 return ERROR_SUCCESS;
4219 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
4225 MSISOURCELISTINFO *info;
4227 r = RegCreateKeyW(hkey, szSourceList, &source);
4228 if (r != ERROR_SUCCESS)
4231 RegCloseKey(source);
4233 buffer = strrchrW(package->PackagePath, '\\') + 1;
4234 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4235 package->Context, MSICODE_PRODUCT,
4236 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4237 if (r != ERROR_SUCCESS)
4240 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4241 package->Context, MSICODE_PRODUCT,
4242 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4243 if (r != ERROR_SUCCESS)
4246 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4247 package->Context, MSICODE_PRODUCT,
4248 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4249 if (r != ERROR_SUCCESS)
4252 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4254 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4255 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4256 info->options, info->value);
4258 MsiSourceListSetInfoW(package->ProductCode, NULL,
4259 info->context, info->options,
4260 info->property, info->value);
4263 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4265 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4266 disk->context, disk->options,
4267 disk->disk_id, disk->volume_label, disk->disk_prompt);
4270 return ERROR_SUCCESS;
4273 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4275 MSIHANDLE hdb, suminfo;
4276 WCHAR guids[MAX_PATH];
4277 WCHAR packcode[SQUISH_GUID_SIZE];
4284 static const WCHAR szProductLanguage[] =
4285 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4286 static const WCHAR szARPProductIcon[] =
4287 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4288 static const WCHAR szProductVersion[] =
4289 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4290 static const WCHAR szAssignment[] =
4291 {'A','s','s','i','g','n','m','e','n','t',0};
4292 static const WCHAR szAdvertiseFlags[] =
4293 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4294 static const WCHAR szClients[] =
4295 {'C','l','i','e','n','t','s',0};
4296 static const WCHAR szColon[] = {':',0};
4298 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4299 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4302 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4303 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4306 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4308 buffer = msi_dup_property(package->db, szARPProductIcon);
4311 LPWSTR path = build_icon_path(package,buffer);
4312 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4317 buffer = msi_dup_property(package->db, szProductVersion);
4320 DWORD verdword = msi_version_str_to_dword(buffer);
4321 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4325 msi_reg_set_val_dword(hkey, szAssignment, 0);
4326 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4327 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4328 msi_reg_set_val_str(hkey, szClients, szColon);
4330 hdb = alloc_msihandle(&package->db->hdr);
4332 return ERROR_NOT_ENOUGH_MEMORY;
4334 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4335 MsiCloseHandle(hdb);
4336 if (r != ERROR_SUCCESS)
4340 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4341 NULL, guids, &size);
4342 if (r != ERROR_SUCCESS)
4345 ptr = strchrW(guids, ';');
4347 squash_guid(guids, packcode);
4348 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4351 MsiCloseHandle(suminfo);
4352 return ERROR_SUCCESS;
4355 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4360 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4362 upgrade = msi_dup_property(package->db, szUpgradeCode);
4364 return ERROR_SUCCESS;
4366 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4367 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4369 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4371 if (r != ERROR_SUCCESS)
4373 WARN("failed to open upgrade code key\n");
4375 return ERROR_SUCCESS;
4377 squash_guid(package->ProductCode, squashed_pc);
4378 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4381 return ERROR_SUCCESS;
4384 static BOOL msi_check_publish(MSIPACKAGE *package)
4386 MSIFEATURE *feature;
4388 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4390 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4397 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4399 MSIFEATURE *feature;
4401 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4403 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4410 static UINT msi_publish_patches( MSIPACKAGE *package )
4412 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4413 WCHAR patch_squashed[GUID_SIZE];
4414 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4416 MSIPATCHINFO *patch;
4418 WCHAR *p, *all_patches = NULL;
4421 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4422 if (r != ERROR_SUCCESS)
4423 return ERROR_FUNCTION_FAILED;
4425 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4426 if (res != ERROR_SUCCESS)
4428 r = ERROR_FUNCTION_FAILED;
4432 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4433 if (r != ERROR_SUCCESS)
4436 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4438 squash_guid( patch->patchcode, patch_squashed );
4439 len += strlenW( patch_squashed ) + 1;
4442 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4446 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4450 squash_guid( patch->patchcode, p );
4451 p += strlenW( p ) + 1;
4453 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4454 (const BYTE *)patch->transforms,
4455 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4456 if (res != ERROR_SUCCESS)
4459 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4460 if (r != ERROR_SUCCESS)
4463 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4464 (const BYTE *)patch->localfile,
4465 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4466 RegCloseKey( patch_key );
4467 if (res != ERROR_SUCCESS)
4470 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4471 if (res != ERROR_SUCCESS)
4474 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4475 RegCloseKey( patch_key );
4476 if (res != ERROR_SUCCESS)
4480 all_patches[len] = 0;
4481 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4482 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4483 if (res != ERROR_SUCCESS)
4486 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4487 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4488 if (res != ERROR_SUCCESS)
4489 r = ERROR_FUNCTION_FAILED;
4492 RegCloseKey( product_patches_key );
4493 RegCloseKey( patches_key );
4494 RegCloseKey( product_key );
4495 msi_free( all_patches );
4500 * 99% of the work done here is only done for
4501 * advertised installs. However this is where the
4502 * Icon table is processed and written out
4503 * so that is what I am going to do here.
4505 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4508 HKEY hukey = NULL, hudkey = NULL;
4511 if (!list_empty(&package->patches))
4513 rc = msi_publish_patches(package);
4514 if (rc != ERROR_SUCCESS)
4518 /* FIXME: also need to publish if the product is in advertise mode */
4519 if (!msi_check_publish(package))
4520 return ERROR_SUCCESS;
4522 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4524 if (rc != ERROR_SUCCESS)
4527 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4528 NULL, &hudkey, TRUE);
4529 if (rc != ERROR_SUCCESS)
4532 rc = msi_publish_upgrade_code(package);
4533 if (rc != ERROR_SUCCESS)
4536 rc = msi_publish_product_properties(package, hukey);
4537 if (rc != ERROR_SUCCESS)
4540 rc = msi_publish_sourcelist(package, hukey);
4541 if (rc != ERROR_SUCCESS)
4544 rc = msi_publish_icons(package);
4547 uirow = MSI_CreateRecord( 1 );
4548 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4549 ui_actiondata( package, szPublishProduct, uirow );
4550 msiobj_release( &uirow->hdr );
4553 RegCloseKey(hudkey);
4558 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4560 WCHAR *filename, *ptr, *folder, *ret;
4561 const WCHAR *dirprop;
4563 filename = msi_dup_record_field( row, 2 );
4564 if (filename && (ptr = strchrW( filename, '|' )))
4569 dirprop = MSI_RecordGetString( row, 3 );
4572 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4574 folder = msi_dup_property( package->db, dirprop );
4577 folder = msi_dup_property( package->db, szWindowsFolder );
4581 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4582 msi_free( filename );
4586 ret = build_directory_name( 2, folder, ptr );
4588 msi_free( filename );
4593 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4595 MSIPACKAGE *package = param;
4596 LPCWSTR component, section, key, value, identifier;
4597 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4602 component = MSI_RecordGetString(row, 8);
4603 comp = get_loaded_component(package,component);
4605 return ERROR_SUCCESS;
4609 TRACE("component is disabled\n");
4610 return ERROR_SUCCESS;
4613 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4615 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4616 comp->Action = comp->Installed;
4617 return ERROR_SUCCESS;
4619 comp->Action = INSTALLSTATE_LOCAL;
4621 identifier = MSI_RecordGetString(row,1);
4622 section = MSI_RecordGetString(row,4);
4623 key = MSI_RecordGetString(row,5);
4624 value = MSI_RecordGetString(row,6);
4625 action = MSI_RecordGetInteger(row,7);
4627 deformat_string(package,section,&deformated_section);
4628 deformat_string(package,key,&deformated_key);
4629 deformat_string(package,value,&deformated_value);
4631 fullname = get_ini_file_name(package, row);
4635 TRACE("Adding value %s to section %s in %s\n",
4636 debugstr_w(deformated_key), debugstr_w(deformated_section),
4637 debugstr_w(fullname));
4638 WritePrivateProfileStringW(deformated_section, deformated_key,
4639 deformated_value, fullname);
4641 else if (action == 1)
4644 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4645 returned, 10, fullname);
4646 if (returned[0] == 0)
4648 TRACE("Adding value %s to section %s in %s\n",
4649 debugstr_w(deformated_key), debugstr_w(deformated_section),
4650 debugstr_w(fullname));
4652 WritePrivateProfileStringW(deformated_section, deformated_key,
4653 deformated_value, fullname);
4656 else if (action == 3)
4657 FIXME("Append to existing section not yet implemented\n");
4659 uirow = MSI_CreateRecord(4);
4660 MSI_RecordSetStringW(uirow,1,identifier);
4661 MSI_RecordSetStringW(uirow,2,deformated_section);
4662 MSI_RecordSetStringW(uirow,3,deformated_key);
4663 MSI_RecordSetStringW(uirow,4,deformated_value);
4664 ui_actiondata(package,szWriteIniValues,uirow);
4665 msiobj_release( &uirow->hdr );
4668 msi_free(deformated_key);
4669 msi_free(deformated_value);
4670 msi_free(deformated_section);
4671 return ERROR_SUCCESS;
4674 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4678 static const WCHAR ExecSeqQuery[] =
4679 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4680 '`','I','n','i','F','i','l','e','`',0};
4682 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4683 if (rc != ERROR_SUCCESS)
4685 TRACE("no IniFile table\n");
4686 return ERROR_SUCCESS;
4689 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4690 msiobj_release(&view->hdr);
4694 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4696 MSIPACKAGE *package = param;
4697 LPCWSTR component, section, key, value, identifier;
4698 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4703 component = MSI_RecordGetString( row, 8 );
4704 comp = get_loaded_component( package, component );
4706 return ERROR_SUCCESS;
4710 TRACE("component is disabled\n");
4711 return ERROR_SUCCESS;
4714 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4716 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4717 comp->Action = comp->Installed;
4718 return ERROR_SUCCESS;
4720 comp->Action = INSTALLSTATE_ABSENT;
4722 identifier = MSI_RecordGetString( row, 1 );
4723 section = MSI_RecordGetString( row, 4 );
4724 key = MSI_RecordGetString( row, 5 );
4725 value = MSI_RecordGetString( row, 6 );
4726 action = MSI_RecordGetInteger( row, 7 );
4728 deformat_string( package, section, &deformated_section );
4729 deformat_string( package, key, &deformated_key );
4730 deformat_string( package, value, &deformated_value );
4732 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4734 filename = get_ini_file_name( package, row );
4736 TRACE("Removing key %s from section %s in %s\n",
4737 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4739 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4741 WARN("Unable to remove key %u\n", GetLastError());
4743 msi_free( filename );
4746 FIXME("Unsupported action %d\n", action);
4749 uirow = MSI_CreateRecord( 4 );
4750 MSI_RecordSetStringW( uirow, 1, identifier );
4751 MSI_RecordSetStringW( uirow, 2, deformated_section );
4752 MSI_RecordSetStringW( uirow, 3, deformated_key );
4753 MSI_RecordSetStringW( uirow, 4, deformated_value );
4754 ui_actiondata( package, szRemoveIniValues, uirow );
4755 msiobj_release( &uirow->hdr );
4757 msi_free( deformated_key );
4758 msi_free( deformated_value );
4759 msi_free( deformated_section );
4760 return ERROR_SUCCESS;
4763 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4765 MSIPACKAGE *package = param;
4766 LPCWSTR component, section, key, value, identifier;
4767 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4772 component = MSI_RecordGetString( row, 8 );
4773 comp = get_loaded_component( package, component );
4775 return ERROR_SUCCESS;
4779 TRACE("component is disabled\n");
4780 return ERROR_SUCCESS;
4783 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4785 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4786 comp->Action = comp->Installed;
4787 return ERROR_SUCCESS;
4789 comp->Action = INSTALLSTATE_LOCAL;
4791 identifier = MSI_RecordGetString( row, 1 );
4792 section = MSI_RecordGetString( row, 4 );
4793 key = MSI_RecordGetString( row, 5 );
4794 value = MSI_RecordGetString( row, 6 );
4795 action = MSI_RecordGetInteger( row, 7 );
4797 deformat_string( package, section, &deformated_section );
4798 deformat_string( package, key, &deformated_key );
4799 deformat_string( package, value, &deformated_value );
4801 if (action == msidbIniFileActionRemoveLine)
4803 filename = get_ini_file_name( package, row );
4805 TRACE("Removing key %s from section %s in %s\n",
4806 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4808 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4810 WARN("Unable to remove key %u\n", GetLastError());
4812 msi_free( filename );
4815 FIXME("Unsupported action %d\n", action);
4817 uirow = MSI_CreateRecord( 4 );
4818 MSI_RecordSetStringW( uirow, 1, identifier );
4819 MSI_RecordSetStringW( uirow, 2, deformated_section );
4820 MSI_RecordSetStringW( uirow, 3, deformated_key );
4821 MSI_RecordSetStringW( uirow, 4, deformated_value );
4822 ui_actiondata( package, szRemoveIniValues, uirow );
4823 msiobj_release( &uirow->hdr );
4825 msi_free( deformated_key );
4826 msi_free( deformated_value );
4827 msi_free( deformated_section );
4828 return ERROR_SUCCESS;
4831 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4835 static const WCHAR query[] =
4836 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4837 '`','I','n','i','F','i','l','e','`',0};
4838 static const WCHAR remove_query[] =
4839 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4840 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4842 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4843 if (rc == ERROR_SUCCESS)
4845 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4846 msiobj_release( &view->hdr );
4847 if (rc != ERROR_SUCCESS)
4851 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4852 if (rc == ERROR_SUCCESS)
4854 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4855 msiobj_release( &view->hdr );
4856 if (rc != ERROR_SUCCESS)
4860 return ERROR_SUCCESS;
4863 static void register_dll( const WCHAR *dll, BOOL unregister )
4867 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4870 HRESULT (WINAPI *func_ptr)( void );
4871 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4873 func_ptr = (void *)GetProcAddress( hmod, func );
4876 HRESULT hr = func_ptr();
4878 WARN("failed to register dll 0x%08x\n", hr);
4881 WARN("entry point %s not found\n", func);
4882 FreeLibrary( hmod );
4885 WARN("failed to load library %u\n", GetLastError());
4888 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4890 MSIPACKAGE *package = param;
4895 filename = MSI_RecordGetString(row,1);
4896 file = get_loaded_file( package, filename );
4900 ERR("Unable to find file id %s\n",debugstr_w(filename));
4901 return ERROR_SUCCESS;
4904 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4906 register_dll( file->TargetPath, FALSE );
4908 uirow = MSI_CreateRecord( 2 );
4909 MSI_RecordSetStringW( uirow, 1, filename );
4910 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4911 ui_actiondata( package, szSelfRegModules, uirow );
4912 msiobj_release( &uirow->hdr );
4914 return ERROR_SUCCESS;
4917 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4921 static const WCHAR ExecSeqQuery[] =
4922 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4923 '`','S','e','l','f','R','e','g','`',0};
4925 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4926 if (rc != ERROR_SUCCESS)
4928 TRACE("no SelfReg table\n");
4929 return ERROR_SUCCESS;
4932 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4933 msiobj_release(&view->hdr);
4935 return ERROR_SUCCESS;
4938 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4940 MSIPACKAGE *package = param;
4945 filename = MSI_RecordGetString( row, 1 );
4946 file = get_loaded_file( package, filename );
4950 ERR("Unable to find file id %s\n", debugstr_w(filename));
4951 return ERROR_SUCCESS;
4954 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4956 register_dll( file->TargetPath, TRUE );
4958 uirow = MSI_CreateRecord( 2 );
4959 MSI_RecordSetStringW( uirow, 1, filename );
4960 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4961 ui_actiondata( package, szSelfUnregModules, uirow );
4962 msiobj_release( &uirow->hdr );
4964 return ERROR_SUCCESS;
4967 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4971 static const WCHAR query[] =
4972 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4973 '`','S','e','l','f','R','e','g','`',0};
4975 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4976 if (rc != ERROR_SUCCESS)
4978 TRACE("no SelfReg table\n");
4979 return ERROR_SUCCESS;
4982 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4983 msiobj_release( &view->hdr );
4985 return ERROR_SUCCESS;
4988 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4990 MSIFEATURE *feature;
4992 HKEY hkey = NULL, userdata = NULL;
4994 if (!msi_check_publish(package))
4995 return ERROR_SUCCESS;
4997 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4999 if (rc != ERROR_SUCCESS)
5002 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
5004 if (rc != ERROR_SUCCESS)
5007 /* here the guids are base 85 encoded */
5008 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5014 BOOL absent = FALSE;
5017 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
5018 feature->ActionRequest != INSTALLSTATE_SOURCE &&
5019 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
5022 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
5026 if (feature->Feature_Parent)
5027 size += strlenW( feature->Feature_Parent )+2;
5029 data = msi_alloc(size * sizeof(WCHAR));
5032 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
5034 MSICOMPONENT* component = cl->component;
5038 if (component->ComponentId)
5040 TRACE("From %s\n",debugstr_w(component->ComponentId));
5041 CLSIDFromString(component->ComponentId, &clsid);
5042 encode_base85_guid(&clsid,buf);
5043 TRACE("to %s\n",debugstr_w(buf));
5048 if (feature->Feature_Parent)
5050 static const WCHAR sep[] = {'\2',0};
5052 strcatW(data,feature->Feature_Parent);
5055 msi_reg_set_val_str( userdata, feature->Feature, data );
5059 if (feature->Feature_Parent)
5060 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
5063 size += sizeof(WCHAR);
5064 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
5065 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
5069 size += 2*sizeof(WCHAR);
5070 data = msi_alloc(size);
5073 if (feature->Feature_Parent)
5074 strcpyW( &data[1], feature->Feature_Parent );
5075 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
5081 uirow = MSI_CreateRecord( 1 );
5082 MSI_RecordSetStringW( uirow, 1, feature->Feature );
5083 ui_actiondata( package, szPublishFeatures, uirow);
5084 msiobj_release( &uirow->hdr );
5085 /* FIXME: call ui_progress? */
5090 RegCloseKey(userdata);
5094 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
5100 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
5102 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
5104 if (r == ERROR_SUCCESS)
5106 RegDeleteValueW(hkey, feature->Feature);
5110 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
5112 if (r == ERROR_SUCCESS)
5114 RegDeleteValueW(hkey, feature->Feature);
5118 uirow = MSI_CreateRecord( 1 );
5119 MSI_RecordSetStringW( uirow, 1, feature->Feature );
5120 ui_actiondata( package, szUnpublishFeatures, uirow );
5121 msiobj_release( &uirow->hdr );
5123 return ERROR_SUCCESS;
5126 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
5128 MSIFEATURE *feature;
5130 if (!msi_check_unpublish(package))
5131 return ERROR_SUCCESS;
5133 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5135 msi_unpublish_feature(package, feature);
5138 return ERROR_SUCCESS;
5141 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
5145 WCHAR date[9], *val, *buffer;
5146 const WCHAR *prop, *key;
5148 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
5149 static const WCHAR szWindowsInstaller[] =
5150 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
5151 static const WCHAR modpath_fmt[] =
5152 {'M','s','i','E','x','e','c','.','e','x','e',' ',
5153 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
5154 static const WCHAR szModifyPath[] =
5155 {'M','o','d','i','f','y','P','a','t','h',0};
5156 static const WCHAR szUninstallString[] =
5157 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5158 static const WCHAR szEstimatedSize[] =
5159 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5160 static const WCHAR szProductLanguage[] =
5161 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
5162 static const WCHAR szProductVersion[] =
5163 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
5164 static const WCHAR szDisplayVersion[] =
5165 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5166 static const WCHAR szInstallSource[] =
5167 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5168 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
5169 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5170 static const WCHAR szAuthorizedCDFPrefix[] =
5171 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5172 static const WCHAR szARPCONTACT[] =
5173 {'A','R','P','C','O','N','T','A','C','T',0};
5174 static const WCHAR szContact[] =
5175 {'C','o','n','t','a','c','t',0};
5176 static const WCHAR szARPCOMMENTS[] =
5177 {'A','R','P','C','O','M','M','E','N','T','S',0};
5178 static const WCHAR szComments[] =
5179 {'C','o','m','m','e','n','t','s',0};
5180 static const WCHAR szProductName[] =
5181 {'P','r','o','d','u','c','t','N','a','m','e',0};
5182 static const WCHAR szDisplayName[] =
5183 {'D','i','s','p','l','a','y','N','a','m','e',0};
5184 static const WCHAR szARPHELPLINK[] =
5185 {'A','R','P','H','E','L','P','L','I','N','K',0};
5186 static const WCHAR szHelpLink[] =
5187 {'H','e','l','p','L','i','n','k',0};
5188 static const WCHAR szARPHELPTELEPHONE[] =
5189 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5190 static const WCHAR szHelpTelephone[] =
5191 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5192 static const WCHAR szARPINSTALLLOCATION[] =
5193 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5194 static const WCHAR szInstallLocation[] =
5195 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
5196 static const WCHAR szManufacturer[] =
5197 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5198 static const WCHAR szPublisher[] =
5199 {'P','u','b','l','i','s','h','e','r',0};
5200 static const WCHAR szARPREADME[] =
5201 {'A','R','P','R','E','A','D','M','E',0};
5202 static const WCHAR szReadme[] =
5203 {'R','e','a','d','M','e',0};
5204 static const WCHAR szARPSIZE[] =
5205 {'A','R','P','S','I','Z','E',0};
5206 static const WCHAR szSize[] =
5207 {'S','i','z','e',0};
5208 static const WCHAR szARPURLINFOABOUT[] =
5209 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5210 static const WCHAR szURLInfoAbout[] =
5211 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5212 static const WCHAR szARPURLUPDATEINFO[] =
5213 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5214 static const WCHAR szURLUpdateInfo[] =
5215 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5217 static const WCHAR *propval[] = {
5218 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
5219 szARPCONTACT, szContact,
5220 szARPCOMMENTS, szComments,
5221 szProductName, szDisplayName,
5222 szARPHELPLINK, szHelpLink,
5223 szARPHELPTELEPHONE, szHelpTelephone,
5224 szARPINSTALLLOCATION, szInstallLocation,
5225 cszSourceDir, szInstallSource,
5226 szManufacturer, szPublisher,
5227 szARPREADME, szReadme,
5229 szARPURLINFOABOUT, szURLInfoAbout,
5230 szARPURLUPDATEINFO, szURLUpdateInfo,
5233 const WCHAR **p = propval;
5239 val = msi_dup_property(package->db, prop);
5240 msi_reg_set_val_str(hkey, key, val);
5244 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5246 size = deformat_string(package, modpath_fmt, &buffer);
5247 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5248 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5251 /* FIXME: Write real Estimated Size when we have it */
5252 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5254 GetLocalTime(&systime);
5255 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5256 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5258 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5259 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5261 buffer = msi_dup_property(package->db, szProductVersion);
5262 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5265 DWORD verdword = msi_version_str_to_dword(buffer);
5267 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5268 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5269 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5273 return ERROR_SUCCESS;
5276 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5278 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5280 LPWSTR upgrade_code;
5285 /* FIXME: also need to publish if the product is in advertise mode */
5286 if (!msi_check_publish(package))
5287 return ERROR_SUCCESS;
5289 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
5290 if (rc != ERROR_SUCCESS)
5293 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5294 NULL, &props, TRUE);
5295 if (rc != ERROR_SUCCESS)
5298 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5299 msi_free( package->db->localfile );
5300 package->db->localfile = NULL;
5302 rc = msi_publish_install_properties(package, hkey);
5303 if (rc != ERROR_SUCCESS)
5306 rc = msi_publish_install_properties(package, props);
5307 if (rc != ERROR_SUCCESS)
5310 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5313 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5314 squash_guid(package->ProductCode, squashed_pc);
5315 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5316 RegCloseKey(upgrade);
5317 msi_free(upgrade_code);
5321 uirow = MSI_CreateRecord( 1 );
5322 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5323 ui_actiondata( package, szRegisterProduct, uirow );
5324 msiobj_release( &uirow->hdr );
5327 return ERROR_SUCCESS;
5330 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5332 return execute_script(package,INSTALL_SCRIPT);
5335 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5337 WCHAR *upgrade, **features;
5338 BOOL full_uninstall = TRUE;
5339 MSIFEATURE *feature;
5340 MSIPATCHINFO *patch;
5342 static const WCHAR szUpgradeCode[] =
5343 {'U','p','g','r','a','d','e','C','o','d','e',0};
5345 features = msi_split_string(remove, ',');
5348 ERR("REMOVE feature list is empty!\n");
5349 return ERROR_FUNCTION_FAILED;
5352 if (!strcmpW( features[0], szAll ))
5353 full_uninstall = TRUE;
5356 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5358 if (feature->Action != INSTALLSTATE_ABSENT)
5359 full_uninstall = FALSE;
5364 if (!full_uninstall)
5365 return ERROR_SUCCESS;
5367 MSIREG_DeleteProductKey(package->ProductCode);
5368 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5369 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5371 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5372 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5373 MSIREG_DeleteUserProductKey(package->ProductCode);
5374 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5376 upgrade = msi_dup_property(package->db, szUpgradeCode);
5379 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5380 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5384 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5386 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5389 return ERROR_SUCCESS;
5392 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5397 /* turn off scheduling */
5398 package->script->CurrentlyScripting= FALSE;
5400 /* first do the same as an InstallExecute */
5401 rc = ACTION_InstallExecute(package);
5402 if (rc != ERROR_SUCCESS)
5405 /* then handle Commit Actions */
5406 rc = execute_script(package,COMMIT_SCRIPT);
5407 if (rc != ERROR_SUCCESS)
5410 remove = msi_dup_property(package->db, szRemove);
5412 rc = msi_unpublish_product(package, remove);
5418 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5420 static const WCHAR RunOnce[] = {
5421 'S','o','f','t','w','a','r','e','\\',
5422 'M','i','c','r','o','s','o','f','t','\\',
5423 'W','i','n','d','o','w','s','\\',
5424 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5425 'R','u','n','O','n','c','e',0};
5426 static const WCHAR InstallRunOnce[] = {
5427 'S','o','f','t','w','a','r','e','\\',
5428 'M','i','c','r','o','s','o','f','t','\\',
5429 'W','i','n','d','o','w','s','\\',
5430 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5431 'I','n','s','t','a','l','l','e','r','\\',
5432 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5434 static const WCHAR msiexec_fmt[] = {
5436 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5437 '\"','%','s','\"',0};
5438 static const WCHAR install_fmt[] = {
5439 '/','I',' ','\"','%','s','\"',' ',
5440 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5441 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5442 WCHAR buffer[256], sysdir[MAX_PATH];
5444 WCHAR squished_pc[100];
5446 squash_guid(package->ProductCode,squished_pc);
5448 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5449 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5450 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5453 msi_reg_set_val_str( hkey, squished_pc, buffer );
5456 TRACE("Reboot command %s\n",debugstr_w(buffer));
5458 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5459 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5461 msi_reg_set_val_str( hkey, squished_pc, buffer );
5464 return ERROR_INSTALL_SUSPEND;
5467 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5473 * We are currently doing what should be done here in the top level Install
5474 * however for Administrative and uninstalls this step will be needed
5476 if (!package->PackagePath)
5477 return ERROR_SUCCESS;
5479 msi_set_sourcedir_props(package, TRUE);
5481 attrib = GetFileAttributesW(package->db->path);
5482 if (attrib == INVALID_FILE_ATTRIBUTES)
5488 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5489 package->Context, MSICODE_PRODUCT,
5490 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5491 if (rc == ERROR_MORE_DATA)
5493 prompt = msi_alloc(size * sizeof(WCHAR));
5494 MsiSourceListGetInfoW(package->ProductCode, NULL,
5495 package->Context, MSICODE_PRODUCT,
5496 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5499 prompt = strdupW(package->db->path);
5501 msg = generate_error_string(package,1302,1,prompt);
5502 while(attrib == INVALID_FILE_ATTRIBUTES)
5504 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5507 rc = ERROR_INSTALL_USEREXIT;
5510 attrib = GetFileAttributesW(package->db->path);
5516 return ERROR_SUCCESS;
5521 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5524 LPWSTR buffer, productid = NULL;
5525 UINT i, rc = ERROR_SUCCESS;
5528 static const WCHAR szPropKeys[][80] =
5530 {'P','r','o','d','u','c','t','I','D',0},
5531 {'U','S','E','R','N','A','M','E',0},
5532 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5536 static const WCHAR szRegKeys[][80] =
5538 {'P','r','o','d','u','c','t','I','D',0},
5539 {'R','e','g','O','w','n','e','r',0},
5540 {'R','e','g','C','o','m','p','a','n','y',0},
5544 if (msi_check_unpublish(package))
5546 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5550 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5554 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5556 if (rc != ERROR_SUCCESS)
5559 for( i = 0; szPropKeys[i][0]; i++ )
5561 buffer = msi_dup_property( package->db, szPropKeys[i] );
5562 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5567 uirow = MSI_CreateRecord( 1 );
5568 MSI_RecordSetStringW( uirow, 1, productid );
5569 ui_actiondata( package, szRegisterUser, uirow );
5570 msiobj_release( &uirow->hdr );
5572 msi_free(productid);
5578 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5582 package->script->InWhatSequence |= SEQUENCE_EXEC;
5583 rc = ACTION_ProcessExecSequence(package,FALSE);
5588 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5590 MSIPACKAGE *package = param;
5591 LPCWSTR compgroupid, component, feature, qualifier, text;
5592 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5601 feature = MSI_RecordGetString(rec, 5);
5602 feat = get_loaded_feature(package, feature);
5604 return ERROR_SUCCESS;
5606 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5607 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5608 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5610 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5611 feat->Action = feat->Installed;
5612 return ERROR_SUCCESS;
5615 component = MSI_RecordGetString(rec, 3);
5616 comp = get_loaded_component(package, component);
5618 return ERROR_SUCCESS;
5620 compgroupid = MSI_RecordGetString(rec,1);
5621 qualifier = MSI_RecordGetString(rec,2);
5623 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5624 if (rc != ERROR_SUCCESS)
5627 advertise = create_component_advertise_string( package, comp, feature );
5628 text = MSI_RecordGetString( rec, 4 );
5631 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5632 strcpyW( p, advertise );
5634 msi_free( advertise );
5637 existing = msi_reg_get_val_str( hkey, qualifier );
5639 sz = strlenW( advertise ) + 1;
5642 for (p = existing; *p; p += len)
5644 len = strlenW( p ) + 1;
5645 if (strcmpW( advertise, p )) sz += len;
5648 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5650 rc = ERROR_OUTOFMEMORY;
5656 for (p = existing; *p; p += len)
5658 len = strlenW( p ) + 1;
5659 if (strcmpW( advertise, p ))
5661 memcpy( q, p, len * sizeof(WCHAR) );
5666 strcpyW( q, advertise );
5667 q[strlenW( q ) + 1] = 0;
5669 msi_reg_set_val_multi_str( hkey, qualifier, output );
5674 msi_free( advertise );
5675 msi_free( existing );
5678 uirow = MSI_CreateRecord( 2 );
5679 MSI_RecordSetStringW( uirow, 1, compgroupid );
5680 MSI_RecordSetStringW( uirow, 2, qualifier);
5681 ui_actiondata( package, szPublishComponents, uirow);
5682 msiobj_release( &uirow->hdr );
5683 /* FIXME: call ui_progress? */
5689 * At present I am ignorning the advertised components part of this and only
5690 * focusing on the qualified component sets
5692 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5696 static const WCHAR ExecSeqQuery[] =
5697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5698 '`','P','u','b','l','i','s','h',
5699 'C','o','m','p','o','n','e','n','t','`',0};
5701 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5702 if (rc != ERROR_SUCCESS)
5703 return ERROR_SUCCESS;
5705 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5706 msiobj_release(&view->hdr);
5711 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5713 static const WCHAR szInstallerComponents[] = {
5714 'S','o','f','t','w','a','r','e','\\',
5715 'M','i','c','r','o','s','o','f','t','\\',
5716 'I','n','s','t','a','l','l','e','r','\\',
5717 'C','o','m','p','o','n','e','n','t','s','\\',0};
5719 MSIPACKAGE *package = param;
5720 LPCWSTR compgroupid, component, feature, qualifier;
5724 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5727 feature = MSI_RecordGetString( rec, 5 );
5728 feat = get_loaded_feature( package, feature );
5730 return ERROR_SUCCESS;
5732 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5734 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5735 feat->Action = feat->Installed;
5736 return ERROR_SUCCESS;
5739 component = MSI_RecordGetString( rec, 3 );
5740 comp = get_loaded_component( package, component );
5742 return ERROR_SUCCESS;
5744 compgroupid = MSI_RecordGetString( rec, 1 );
5745 qualifier = MSI_RecordGetString( rec, 2 );
5747 squash_guid( compgroupid, squashed );
5748 strcpyW( keypath, szInstallerComponents );
5749 strcatW( keypath, squashed );
5751 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5752 if (res != ERROR_SUCCESS)
5754 WARN("Unable to delete component key %d\n", res);
5757 uirow = MSI_CreateRecord( 2 );
5758 MSI_RecordSetStringW( uirow, 1, compgroupid );
5759 MSI_RecordSetStringW( uirow, 2, qualifier );
5760 ui_actiondata( package, szUnpublishComponents, uirow );
5761 msiobj_release( &uirow->hdr );
5763 return ERROR_SUCCESS;
5766 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5770 static const WCHAR query[] =
5771 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5772 '`','P','u','b','l','i','s','h',
5773 'C','o','m','p','o','n','e','n','t','`',0};
5775 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5776 if (rc != ERROR_SUCCESS)
5777 return ERROR_SUCCESS;
5779 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5780 msiobj_release( &view->hdr );
5785 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5787 MSIPACKAGE *package = param;
5790 SC_HANDLE hscm, service = NULL;
5792 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5793 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5794 DWORD serv_type, start_type, err_control;
5795 SERVICE_DESCRIPTIONW sd = {NULL};
5797 static const WCHAR query[] =
5798 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5799 '`','C','o','m','p','o','n','e','n','t','`',' ',
5800 'W','H','E','R','E',' ',
5801 '`','C','o','m','p','o','n','e','n','t','`',' ',
5802 '=','\'','%','s','\'',0};
5804 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5807 ERR("Failed to open the SC Manager!\n");
5811 comp = MSI_RecordGetString( rec, 12 );
5812 if (!get_loaded_component( package, comp ))
5815 start_type = MSI_RecordGetInteger(rec, 5);
5816 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5819 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5820 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5821 serv_type = MSI_RecordGetInteger(rec, 4);
5822 err_control = MSI_RecordGetInteger(rec, 6);
5823 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5824 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5825 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5826 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5827 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5828 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5830 /* fetch the service path */
5831 row = MSI_QueryGetRecord(package->db, query, comp);
5834 ERR("Control query failed!\n");
5837 key = MSI_RecordGetString(row, 6);
5839 file = get_loaded_file(package, key);
5840 msiobj_release(&row->hdr);
5843 ERR("Failed to load the service file\n");
5847 if (!args || !args[0]) image_path = file->TargetPath;
5850 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5851 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5852 return ERROR_OUTOFMEMORY;
5854 strcpyW(image_path, file->TargetPath);
5855 strcatW(image_path, szSpace);
5856 strcatW(image_path, args);
5858 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5859 start_type, err_control, image_path, load_order,
5860 NULL, depends, serv_name, pass);
5864 if (GetLastError() != ERROR_SERVICE_EXISTS)
5865 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5867 else if (sd.lpDescription)
5869 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5870 WARN("failed to set service description %u\n", GetLastError());
5873 if (image_path != file->TargetPath) msi_free(image_path);
5875 CloseServiceHandle(service);
5876 CloseServiceHandle(hscm);
5879 msi_free(sd.lpDescription);
5880 msi_free(load_order);
5881 msi_free(serv_name);
5886 return ERROR_SUCCESS;
5889 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5893 static const WCHAR ExecSeqQuery[] =
5894 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5895 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5897 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5898 if (rc != ERROR_SUCCESS)
5899 return ERROR_SUCCESS;
5901 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5902 msiobj_release(&view->hdr);
5907 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5908 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5910 LPCWSTR *vector, *temp_vector;
5914 static const WCHAR separator[] = {'[','~',']',0};
5917 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5922 vector = msi_alloc(sizeof(LPWSTR));
5930 vector[*numargs - 1] = p;
5932 if ((q = strstrW(p, separator)))
5936 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5942 vector = temp_vector;
5951 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5953 MSIPACKAGE *package = param;
5956 SC_HANDLE scm = NULL, service = NULL;
5957 LPCWSTR component, *vector = NULL;
5958 LPWSTR name, args, display_name = NULL;
5959 DWORD event, numargs, len;
5960 UINT r = ERROR_FUNCTION_FAILED;
5962 component = MSI_RecordGetString(rec, 6);
5963 comp = get_loaded_component(package, component);
5965 return ERROR_SUCCESS;
5969 TRACE("component is disabled\n");
5970 return ERROR_SUCCESS;
5973 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5975 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5976 comp->Action = comp->Installed;
5977 return ERROR_SUCCESS;
5979 comp->Action = INSTALLSTATE_LOCAL;
5981 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5982 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5983 event = MSI_RecordGetInteger(rec, 3);
5985 if (!(event & msidbServiceControlEventStart))
5991 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5994 ERR("Failed to open the service control manager\n");
5999 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6000 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6002 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6003 GetServiceDisplayNameW( scm, name, display_name, &len );
6006 service = OpenServiceW(scm, name, SERVICE_START);
6009 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
6013 vector = msi_service_args_to_vector(args, &numargs);
6015 if (!StartServiceW(service, numargs, vector) &&
6016 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
6018 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
6025 uirow = MSI_CreateRecord( 2 );
6026 MSI_RecordSetStringW( uirow, 1, display_name );
6027 MSI_RecordSetStringW( uirow, 2, name );
6028 ui_actiondata( package, szStartServices, uirow );
6029 msiobj_release( &uirow->hdr );
6031 CloseServiceHandle(service);
6032 CloseServiceHandle(scm);
6037 msi_free(display_name);
6041 static UINT ACTION_StartServices( MSIPACKAGE *package )
6046 static const WCHAR query[] = {
6047 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6048 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6050 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6051 if (rc != ERROR_SUCCESS)
6052 return ERROR_SUCCESS;
6054 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
6055 msiobj_release(&view->hdr);
6060 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6062 DWORD i, needed, count;
6063 ENUM_SERVICE_STATUSW *dependencies;
6067 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6068 0, &needed, &count))
6071 if (GetLastError() != ERROR_MORE_DATA)
6074 dependencies = msi_alloc(needed);
6078 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6079 needed, &needed, &count))
6082 for (i = 0; i < count; i++)
6084 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6085 SERVICE_STOP | SERVICE_QUERY_STATUS);
6089 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
6096 msi_free(dependencies);
6100 static UINT stop_service( LPCWSTR name )
6102 SC_HANDLE scm = NULL, service = NULL;
6103 SERVICE_STATUS status;
6104 SERVICE_STATUS_PROCESS ssp;
6107 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6110 WARN("Failed to open the SCM: %d\n", GetLastError());
6114 service = OpenServiceW(scm, name,
6116 SERVICE_QUERY_STATUS |
6117 SERVICE_ENUMERATE_DEPENDENTS);
6120 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
6124 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
6125 sizeof(SERVICE_STATUS_PROCESS), &needed))
6127 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
6131 if (ssp.dwCurrentState == SERVICE_STOPPED)
6134 stop_service_dependents(scm, service);
6136 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6137 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
6140 CloseServiceHandle(service);
6141 CloseServiceHandle(scm);
6143 return ERROR_SUCCESS;
6146 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6148 MSIPACKAGE *package = param;
6152 LPWSTR name = NULL, display_name = NULL;
6156 event = MSI_RecordGetInteger( rec, 3 );
6157 if (!(event & msidbServiceControlEventStop))
6158 return ERROR_SUCCESS;
6160 component = MSI_RecordGetString( rec, 6 );
6161 comp = get_loaded_component( package, component );
6163 return ERROR_SUCCESS;
6167 TRACE("component is disabled\n");
6168 return ERROR_SUCCESS;
6171 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6173 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6174 comp->Action = comp->Installed;
6175 return ERROR_SUCCESS;
6177 comp->Action = INSTALLSTATE_ABSENT;
6179 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6182 ERR("Failed to open the service control manager\n");
6187 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6188 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6190 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6191 GetServiceDisplayNameW( scm, name, display_name, &len );
6193 CloseServiceHandle( scm );
6195 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6196 stop_service( name );
6199 uirow = MSI_CreateRecord( 2 );
6200 MSI_RecordSetStringW( uirow, 1, display_name );
6201 MSI_RecordSetStringW( uirow, 2, name );
6202 ui_actiondata( package, szStopServices, uirow );
6203 msiobj_release( &uirow->hdr );
6206 msi_free( display_name );
6207 return ERROR_SUCCESS;
6210 static UINT ACTION_StopServices( MSIPACKAGE *package )
6215 static const WCHAR query[] = {
6216 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6217 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6219 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6220 if (rc != ERROR_SUCCESS)
6221 return ERROR_SUCCESS;
6223 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6224 msiobj_release(&view->hdr);
6229 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6231 MSIPACKAGE *package = param;
6235 LPWSTR name = NULL, display_name = NULL;
6237 SC_HANDLE scm = NULL, service = NULL;
6239 event = MSI_RecordGetInteger( rec, 3 );
6240 if (!(event & msidbServiceControlEventDelete))
6241 return ERROR_SUCCESS;
6243 component = MSI_RecordGetString(rec, 6);
6244 comp = get_loaded_component(package, component);
6246 return ERROR_SUCCESS;
6250 TRACE("component is disabled\n");
6251 return ERROR_SUCCESS;
6254 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6256 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6257 comp->Action = comp->Installed;
6258 return ERROR_SUCCESS;
6260 comp->Action = INSTALLSTATE_ABSENT;
6262 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6263 stop_service( name );
6265 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6268 WARN("Failed to open the SCM: %d\n", GetLastError());
6273 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6274 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6276 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6277 GetServiceDisplayNameW( scm, name, display_name, &len );
6280 service = OpenServiceW( scm, name, DELETE );
6283 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6287 if (!DeleteService( service ))
6288 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6291 uirow = MSI_CreateRecord( 2 );
6292 MSI_RecordSetStringW( uirow, 1, display_name );
6293 MSI_RecordSetStringW( uirow, 2, name );
6294 ui_actiondata( package, szDeleteServices, uirow );
6295 msiobj_release( &uirow->hdr );
6297 CloseServiceHandle( service );
6298 CloseServiceHandle( scm );
6300 msi_free( display_name );
6302 return ERROR_SUCCESS;
6305 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6310 static const WCHAR query[] = {
6311 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6312 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6314 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6315 if (rc != ERROR_SUCCESS)
6316 return ERROR_SUCCESS;
6318 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6319 msiobj_release( &view->hdr );
6324 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6326 MSIPACKAGE *package = param;
6327 LPWSTR driver, driver_path, ptr;
6328 WCHAR outpath[MAX_PATH];
6329 MSIFILE *driver_file = NULL, *setup_file = NULL;
6332 LPCWSTR desc, file_key, component;
6334 UINT r = ERROR_SUCCESS;
6336 static const WCHAR driver_fmt[] = {
6337 'D','r','i','v','e','r','=','%','s',0};
6338 static const WCHAR setup_fmt[] = {
6339 'S','e','t','u','p','=','%','s',0};
6340 static const WCHAR usage_fmt[] = {
6341 'F','i','l','e','U','s','a','g','e','=','1',0};
6343 component = MSI_RecordGetString( rec, 2 );
6344 comp = get_loaded_component( package, component );
6346 return ERROR_SUCCESS;
6350 TRACE("component is disabled\n");
6351 return ERROR_SUCCESS;
6354 desc = MSI_RecordGetString(rec, 3);
6356 file_key = MSI_RecordGetString( rec, 4 );
6357 if (file_key) driver_file = get_loaded_file( package, file_key );
6359 file_key = MSI_RecordGetString( rec, 5 );
6360 if (file_key) setup_file = get_loaded_file( package, file_key );
6364 ERR("ODBC Driver entry not found!\n");
6365 return ERROR_FUNCTION_FAILED;
6368 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6370 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6371 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6373 driver = msi_alloc(len * sizeof(WCHAR));
6375 return ERROR_OUTOFMEMORY;
6378 lstrcpyW(ptr, desc);
6379 ptr += lstrlenW(ptr) + 1;
6381 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6386 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6390 lstrcpyW(ptr, usage_fmt);
6391 ptr += lstrlenW(ptr) + 1;
6394 driver_path = strdupW(driver_file->TargetPath);
6395 ptr = strrchrW(driver_path, '\\');
6396 if (ptr) *ptr = '\0';
6398 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6399 NULL, ODBC_INSTALL_COMPLETE, &usage))
6401 ERR("Failed to install SQL driver!\n");
6402 r = ERROR_FUNCTION_FAILED;
6405 uirow = MSI_CreateRecord( 5 );
6406 MSI_RecordSetStringW( uirow, 1, desc );
6407 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6408 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6409 ui_actiondata( package, szInstallODBC, uirow );
6410 msiobj_release( &uirow->hdr );
6413 msi_free(driver_path);
6418 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6420 MSIPACKAGE *package = param;
6421 LPWSTR translator, translator_path, ptr;
6422 WCHAR outpath[MAX_PATH];
6423 MSIFILE *translator_file = NULL, *setup_file = NULL;
6426 LPCWSTR desc, file_key, component;
6428 UINT r = ERROR_SUCCESS;
6430 static const WCHAR translator_fmt[] = {
6431 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6432 static const WCHAR setup_fmt[] = {
6433 'S','e','t','u','p','=','%','s',0};
6435 component = MSI_RecordGetString( rec, 2 );
6436 comp = get_loaded_component( package, component );
6438 return ERROR_SUCCESS;
6442 TRACE("component is disabled\n");
6443 return ERROR_SUCCESS;
6446 desc = MSI_RecordGetString(rec, 3);
6448 file_key = MSI_RecordGetString( rec, 4 );
6449 if (file_key) translator_file = get_loaded_file( package, file_key );
6451 file_key = MSI_RecordGetString( rec, 5 );
6452 if (file_key) setup_file = get_loaded_file( package, file_key );
6454 if (!translator_file)
6456 ERR("ODBC Translator entry not found!\n");
6457 return ERROR_FUNCTION_FAILED;
6460 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6462 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6464 translator = msi_alloc(len * sizeof(WCHAR));
6466 return ERROR_OUTOFMEMORY;
6469 lstrcpyW(ptr, desc);
6470 ptr += lstrlenW(ptr) + 1;
6472 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6477 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6482 translator_path = strdupW(translator_file->TargetPath);
6483 ptr = strrchrW(translator_path, '\\');
6484 if (ptr) *ptr = '\0';
6486 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6487 NULL, ODBC_INSTALL_COMPLETE, &usage))
6489 ERR("Failed to install SQL translator!\n");
6490 r = ERROR_FUNCTION_FAILED;
6493 uirow = MSI_CreateRecord( 5 );
6494 MSI_RecordSetStringW( uirow, 1, desc );
6495 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6496 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6497 ui_actiondata( package, szInstallODBC, uirow );
6498 msiobj_release( &uirow->hdr );
6500 msi_free(translator);
6501 msi_free(translator_path);
6506 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6508 MSIPACKAGE *package = param;
6511 LPCWSTR desc, driver, component;
6512 WORD request = ODBC_ADD_SYS_DSN;
6515 UINT r = ERROR_SUCCESS;
6518 static const WCHAR attrs_fmt[] = {
6519 'D','S','N','=','%','s',0 };
6521 component = MSI_RecordGetString( rec, 2 );
6522 comp = get_loaded_component( package, component );
6524 return ERROR_SUCCESS;
6528 TRACE("component is disabled\n");
6529 return ERROR_SUCCESS;
6532 desc = MSI_RecordGetString(rec, 3);
6533 driver = MSI_RecordGetString(rec, 4);
6534 registration = MSI_RecordGetInteger(rec, 5);
6536 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6537 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6539 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6540 attrs = msi_alloc(len * sizeof(WCHAR));
6542 return ERROR_OUTOFMEMORY;
6544 len = sprintfW(attrs, attrs_fmt, desc);
6547 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6549 ERR("Failed to install SQL data source!\n");
6550 r = ERROR_FUNCTION_FAILED;
6553 uirow = MSI_CreateRecord( 5 );
6554 MSI_RecordSetStringW( uirow, 1, desc );
6555 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6556 MSI_RecordSetInteger( uirow, 3, request );
6557 ui_actiondata( package, szInstallODBC, uirow );
6558 msiobj_release( &uirow->hdr );
6565 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6570 static const WCHAR driver_query[] = {
6571 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6572 'O','D','B','C','D','r','i','v','e','r',0 };
6574 static const WCHAR translator_query[] = {
6575 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6576 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6578 static const WCHAR source_query[] = {
6579 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6580 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6582 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6583 if (rc != ERROR_SUCCESS)
6584 return ERROR_SUCCESS;
6586 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6587 msiobj_release(&view->hdr);
6589 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6590 if (rc != ERROR_SUCCESS)
6591 return ERROR_SUCCESS;
6593 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6594 msiobj_release(&view->hdr);
6596 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6597 if (rc != ERROR_SUCCESS)
6598 return ERROR_SUCCESS;
6600 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6601 msiobj_release(&view->hdr);
6606 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6608 MSIPACKAGE *package = param;
6612 LPCWSTR desc, component;
6614 component = MSI_RecordGetString( rec, 2 );
6615 comp = get_loaded_component( package, component );
6617 return ERROR_SUCCESS;
6621 TRACE("component is disabled\n");
6622 return ERROR_SUCCESS;
6625 desc = MSI_RecordGetString( rec, 3 );
6626 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6628 WARN("Failed to remove ODBC driver\n");
6632 FIXME("Usage count reached 0\n");
6635 uirow = MSI_CreateRecord( 2 );
6636 MSI_RecordSetStringW( uirow, 1, desc );
6637 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6638 ui_actiondata( package, szRemoveODBC, uirow );
6639 msiobj_release( &uirow->hdr );
6641 return ERROR_SUCCESS;
6644 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6646 MSIPACKAGE *package = param;
6650 LPCWSTR desc, component;
6652 component = MSI_RecordGetString( rec, 2 );
6653 comp = get_loaded_component( package, component );
6655 return ERROR_SUCCESS;
6659 TRACE("component is disabled\n");
6660 return ERROR_SUCCESS;
6663 desc = MSI_RecordGetString( rec, 3 );
6664 if (!SQLRemoveTranslatorW( desc, &usage ))
6666 WARN("Failed to remove ODBC translator\n");
6670 FIXME("Usage count reached 0\n");
6673 uirow = MSI_CreateRecord( 2 );
6674 MSI_RecordSetStringW( uirow, 1, desc );
6675 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6676 ui_actiondata( package, szRemoveODBC, uirow );
6677 msiobj_release( &uirow->hdr );
6679 return ERROR_SUCCESS;
6682 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6684 MSIPACKAGE *package = param;
6688 LPCWSTR desc, driver, component;
6689 WORD request = ODBC_REMOVE_SYS_DSN;
6693 static const WCHAR attrs_fmt[] = {
6694 'D','S','N','=','%','s',0 };
6696 component = MSI_RecordGetString( rec, 2 );
6697 comp = get_loaded_component( package, component );
6699 return ERROR_SUCCESS;
6703 TRACE("component is disabled\n");
6704 return ERROR_SUCCESS;
6707 desc = MSI_RecordGetString( rec, 3 );
6708 driver = MSI_RecordGetString( rec, 4 );
6709 registration = MSI_RecordGetInteger( rec, 5 );
6711 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6712 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6714 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6715 attrs = msi_alloc( len * sizeof(WCHAR) );
6717 return ERROR_OUTOFMEMORY;
6719 FIXME("Use ODBCSourceAttribute table\n");
6721 len = sprintfW( attrs, attrs_fmt, desc );
6724 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6726 WARN("Failed to remove ODBC data source\n");
6730 uirow = MSI_CreateRecord( 3 );
6731 MSI_RecordSetStringW( uirow, 1, desc );
6732 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6733 MSI_RecordSetInteger( uirow, 3, request );
6734 ui_actiondata( package, szRemoveODBC, uirow );
6735 msiobj_release( &uirow->hdr );
6737 return ERROR_SUCCESS;
6740 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6745 static const WCHAR driver_query[] = {
6746 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6747 'O','D','B','C','D','r','i','v','e','r',0 };
6749 static const WCHAR translator_query[] = {
6750 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6751 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6753 static const WCHAR source_query[] = {
6754 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6755 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6757 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6758 if (rc != ERROR_SUCCESS)
6759 return ERROR_SUCCESS;
6761 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6762 msiobj_release( &view->hdr );
6764 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6765 if (rc != ERROR_SUCCESS)
6766 return ERROR_SUCCESS;
6768 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6769 msiobj_release( &view->hdr );
6771 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6772 if (rc != ERROR_SUCCESS)
6773 return ERROR_SUCCESS;
6775 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6776 msiobj_release( &view->hdr );
6781 #define ENV_ACT_SETALWAYS 0x1
6782 #define ENV_ACT_SETABSENT 0x2
6783 #define ENV_ACT_REMOVE 0x4
6784 #define ENV_ACT_REMOVEMATCH 0x8
6786 #define ENV_MOD_MACHINE 0x20000000
6787 #define ENV_MOD_APPEND 0x40000000
6788 #define ENV_MOD_PREFIX 0x80000000
6789 #define ENV_MOD_MASK 0xC0000000
6791 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6793 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6795 LPCWSTR cptr = *name;
6797 static const WCHAR prefix[] = {'[','~',']',0};
6798 static const int prefix_len = 3;
6804 *flags |= ENV_ACT_SETALWAYS;
6805 else if (*cptr == '+')
6806 *flags |= ENV_ACT_SETABSENT;
6807 else if (*cptr == '-')
6808 *flags |= ENV_ACT_REMOVE;
6809 else if (*cptr == '!')
6810 *flags |= ENV_ACT_REMOVEMATCH;
6811 else if (*cptr == '*')
6812 *flags |= ENV_MOD_MACHINE;
6822 ERR("Missing environment variable\n");
6823 return ERROR_FUNCTION_FAILED;
6828 LPCWSTR ptr = *value;
6829 if (!strncmpW(ptr, prefix, prefix_len))
6831 if (ptr[prefix_len] == szSemiColon[0])
6833 *flags |= ENV_MOD_APPEND;
6834 *value += lstrlenW(prefix);
6841 else if (lstrlenW(*value) >= prefix_len)
6843 ptr += lstrlenW(ptr) - prefix_len;
6844 if (!strcmpW( ptr, prefix ))
6846 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6848 *flags |= ENV_MOD_PREFIX;
6849 /* the "[~]" will be removed by deformat_string */;
6859 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6860 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6861 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6862 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6864 ERR("Invalid flags: %08x\n", *flags);
6865 return ERROR_FUNCTION_FAILED;
6869 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6871 return ERROR_SUCCESS;
6874 static UINT open_env_key( DWORD flags, HKEY *key )
6876 static const WCHAR user_env[] =
6877 {'E','n','v','i','r','o','n','m','e','n','t',0};
6878 static const WCHAR machine_env[] =
6879 {'S','y','s','t','e','m','\\',
6880 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6881 'C','o','n','t','r','o','l','\\',
6882 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6883 'E','n','v','i','r','o','n','m','e','n','t',0};
6888 if (flags & ENV_MOD_MACHINE)
6891 root = HKEY_LOCAL_MACHINE;
6896 root = HKEY_CURRENT_USER;
6899 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6900 if (res != ERROR_SUCCESS)
6902 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6903 return ERROR_FUNCTION_FAILED;
6906 return ERROR_SUCCESS;
6909 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6911 MSIPACKAGE *package = param;
6912 LPCWSTR name, value, component;
6913 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6914 DWORD flags, type, size;
6921 component = MSI_RecordGetString(rec, 4);
6922 comp = get_loaded_component(package, component);
6924 return ERROR_SUCCESS;
6928 TRACE("component is disabled\n");
6929 return ERROR_SUCCESS;
6932 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6934 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6935 comp->Action = comp->Installed;
6936 return ERROR_SUCCESS;
6938 comp->Action = INSTALLSTATE_LOCAL;
6940 name = MSI_RecordGetString(rec, 2);
6941 value = MSI_RecordGetString(rec, 3);
6943 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6945 res = env_parse_flags(&name, &value, &flags);
6946 if (res != ERROR_SUCCESS || !value)
6949 if (value && !deformat_string(package, value, &deformatted))
6951 res = ERROR_OUTOFMEMORY;
6955 value = deformatted;
6957 res = open_env_key( flags, &env );
6958 if (res != ERROR_SUCCESS)
6961 if (flags & ENV_MOD_MACHINE)
6962 action |= 0x20000000;
6966 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6967 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6968 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6971 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6975 /* Nothing to do. */
6978 res = ERROR_SUCCESS;
6982 /* If we are appending but the string was empty, strip ; */
6983 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6985 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6986 newval = strdupW(value);
6989 res = ERROR_OUTOFMEMORY;
6997 /* Contrary to MSDN, +-variable to [~];path works */
6998 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
7000 res = ERROR_SUCCESS;
7004 data = msi_alloc(size);
7008 return ERROR_OUTOFMEMORY;
7011 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
7012 if (res != ERROR_SUCCESS)
7015 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
7018 res = RegDeleteValueW(env, name);
7019 if (res != ERROR_SUCCESS)
7020 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
7024 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
7025 if (flags & ENV_MOD_MASK)
7029 if (flags & ENV_MOD_APPEND) multiplier++;
7030 if (flags & ENV_MOD_PREFIX) multiplier++;
7031 mod_size = lstrlenW(value) * multiplier;
7032 size += mod_size * sizeof(WCHAR);
7035 newval = msi_alloc(size);
7039 res = ERROR_OUTOFMEMORY;
7043 if (flags & ENV_MOD_PREFIX)
7045 lstrcpyW(newval, value);
7046 ptr = newval + lstrlenW(value);
7047 action |= 0x80000000;
7050 lstrcpyW(ptr, data);
7052 if (flags & ENV_MOD_APPEND)
7054 lstrcatW(newval, value);
7055 action |= 0x40000000;
7058 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
7059 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
7062 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7066 uirow = MSI_CreateRecord( 3 );
7067 MSI_RecordSetStringW( uirow, 1, name );
7068 MSI_RecordSetStringW( uirow, 2, newval );
7069 MSI_RecordSetInteger( uirow, 3, action );
7070 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
7071 msiobj_release( &uirow->hdr );
7073 if (env) RegCloseKey(env);
7074 msi_free(deformatted);
7080 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7084 static const WCHAR ExecSeqQuery[] =
7085 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7086 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7087 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7088 if (rc != ERROR_SUCCESS)
7089 return ERROR_SUCCESS;
7091 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7092 msiobj_release(&view->hdr);
7097 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7099 MSIPACKAGE *package = param;
7100 LPCWSTR name, value, component;
7101 LPWSTR deformatted = NULL;
7110 component = MSI_RecordGetString( rec, 4 );
7111 comp = get_loaded_component( package, component );
7113 return ERROR_SUCCESS;
7117 TRACE("component is disabled\n");
7118 return ERROR_SUCCESS;
7121 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
7123 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
7124 comp->Action = comp->Installed;
7125 return ERROR_SUCCESS;
7127 comp->Action = INSTALLSTATE_ABSENT;
7129 name = MSI_RecordGetString( rec, 2 );
7130 value = MSI_RecordGetString( rec, 3 );
7132 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7134 r = env_parse_flags( &name, &value, &flags );
7135 if (r != ERROR_SUCCESS)
7138 if (!(flags & ENV_ACT_REMOVE))
7140 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7141 return ERROR_SUCCESS;
7144 if (value && !deformat_string( package, value, &deformatted ))
7145 return ERROR_OUTOFMEMORY;
7147 value = deformatted;
7149 r = open_env_key( flags, &env );
7150 if (r != ERROR_SUCCESS)
7156 if (flags & ENV_MOD_MACHINE)
7157 action |= 0x20000000;
7159 TRACE("Removing %s\n", debugstr_w(name));
7161 res = RegDeleteValueW( env, name );
7162 if (res != ERROR_SUCCESS)
7164 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
7169 uirow = MSI_CreateRecord( 3 );
7170 MSI_RecordSetStringW( uirow, 1, name );
7171 MSI_RecordSetStringW( uirow, 2, value );
7172 MSI_RecordSetInteger( uirow, 3, action );
7173 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
7174 msiobj_release( &uirow->hdr );
7176 if (env) RegCloseKey( env );
7177 msi_free( deformatted );
7181 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7185 static const WCHAR query[] =
7186 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7187 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7189 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
7190 if (rc != ERROR_SUCCESS)
7191 return ERROR_SUCCESS;
7193 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7194 msiobj_release( &view->hdr );
7199 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7201 LPWSTR key, template, id;
7202 UINT r = ERROR_SUCCESS;
7204 id = msi_dup_property( package->db, szProductID );
7208 return ERROR_SUCCESS;
7210 template = msi_dup_property( package->db, szPIDTemplate );
7211 key = msi_dup_property( package->db, szPIDKEY );
7213 if (key && template)
7215 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7216 r = msi_set_property( package->db, szProductID, key );
7218 msi_free( template );
7223 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7226 package->need_reboot = 1;
7227 return ERROR_SUCCESS;
7230 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7232 static const WCHAR szAvailableFreeReg[] =
7233 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7235 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7237 TRACE("%p %d kilobytes\n", package, space);
7239 uirow = MSI_CreateRecord( 1 );
7240 MSI_RecordSetInteger( uirow, 1, space );
7241 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7242 msiobj_release( &uirow->hdr );
7244 return ERROR_SUCCESS;
7247 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7249 FIXME("%p\n", package);
7250 return ERROR_SUCCESS;
7253 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7255 FIXME("%p\n", package);
7256 return ERROR_SUCCESS;
7259 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7264 static const WCHAR driver_query[] = {
7265 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7266 'O','D','B','C','D','r','i','v','e','r',0 };
7268 static const WCHAR translator_query[] = {
7269 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7270 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7272 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7273 if (r == ERROR_SUCCESS)
7276 r = MSI_IterateRecords( view, &count, NULL, package );
7277 msiobj_release( &view->hdr );
7278 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7281 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7282 if (r == ERROR_SUCCESS)
7285 r = MSI_IterateRecords( view, &count, NULL, package );
7286 msiobj_release( &view->hdr );
7287 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7290 return ERROR_SUCCESS;
7293 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7295 MSIPACKAGE *package = param;
7296 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7299 if ((value = msi_dup_property( package->db, property )))
7301 FIXME("remove %s\n", debugstr_w(value));
7304 return ERROR_SUCCESS;
7307 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7312 static const WCHAR query[] =
7313 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7314 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7316 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7317 if (r == ERROR_SUCCESS)
7319 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7320 msiobj_release( &view->hdr );
7322 return ERROR_SUCCESS;
7325 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7327 MSIPACKAGE *package = param;
7328 int attributes = MSI_RecordGetInteger( rec, 5 );
7330 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7332 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7333 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7334 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7335 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7339 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7341 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7342 if (r != ERROR_SUCCESS)
7343 return ERROR_SUCCESS;
7347 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7348 if (r != ERROR_SUCCESS)
7349 return ERROR_SUCCESS;
7351 RegCloseKey( hkey );
7353 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7354 debugstr_w(upgrade_code), debugstr_w(version_min),
7355 debugstr_w(version_max), debugstr_w(language));
7357 return ERROR_SUCCESS;
7360 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7365 static const WCHAR query[] =
7366 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7368 if (msi_get_property_int( package->db, szInstalled, 0 ))
7370 TRACE("product is installed, skipping action\n");
7371 return ERROR_SUCCESS;
7373 if (msi_get_property_int( package->db, szPreselected, 0 ))
7375 TRACE("Preselected property is set, not migrating feature states\n");
7376 return ERROR_SUCCESS;
7379 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7380 if (r == ERROR_SUCCESS)
7382 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7383 msiobj_release( &view->hdr );
7385 return ERROR_SUCCESS;
7388 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7389 LPCSTR action, LPCWSTR table )
7391 static const WCHAR query[] = {
7392 'S','E','L','E','C','T',' ','*',' ',
7393 'F','R','O','M',' ','`','%','s','`',0 };
7394 MSIQUERY *view = NULL;
7398 r = MSI_OpenQuery( package->db, &view, query, table );
7399 if (r == ERROR_SUCCESS)
7401 r = MSI_IterateRecords(view, &count, NULL, package);
7402 msiobj_release(&view->hdr);
7406 FIXME("%s -> %u ignored %s table values\n",
7407 action, count, debugstr_w(table));
7409 return ERROR_SUCCESS;
7412 static UINT ACTION_BindImage( MSIPACKAGE *package )
7414 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7415 return msi_unimplemented_action_stub( package, "BindImage", table );
7418 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7420 static const WCHAR table[] = {
7421 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7422 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7425 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7427 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7428 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7431 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7433 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7434 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7437 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7439 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7440 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7443 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7445 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7446 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7449 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7453 const WCHAR *action;
7454 UINT (*handler)(MSIPACKAGE *);
7458 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7459 { szAppSearch, ACTION_AppSearch },
7460 { szBindImage, ACTION_BindImage },
7461 { szCCPSearch, ACTION_CCPSearch },
7462 { szCostFinalize, ACTION_CostFinalize },
7463 { szCostInitialize, ACTION_CostInitialize },
7464 { szCreateFolders, ACTION_CreateFolders },
7465 { szCreateShortcuts, ACTION_CreateShortcuts },
7466 { szDeleteServices, ACTION_DeleteServices },
7467 { szDisableRollback, ACTION_DisableRollback },
7468 { szDuplicateFiles, ACTION_DuplicateFiles },
7469 { szExecuteAction, ACTION_ExecuteAction },
7470 { szFileCost, ACTION_FileCost },
7471 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7472 { szForceReboot, ACTION_ForceReboot },
7473 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7474 { szInstallExecute, ACTION_InstallExecute },
7475 { szInstallExecuteAgain, ACTION_InstallExecute },
7476 { szInstallFiles, ACTION_InstallFiles},
7477 { szInstallFinalize, ACTION_InstallFinalize },
7478 { szInstallInitialize, ACTION_InstallInitialize },
7479 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7480 { szInstallValidate, ACTION_InstallValidate },
7481 { szIsolateComponents, ACTION_IsolateComponents },
7482 { szLaunchConditions, ACTION_LaunchConditions },
7483 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7484 { szMoveFiles, ACTION_MoveFiles },
7485 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7486 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7487 { szInstallODBC, ACTION_InstallODBC },
7488 { szInstallServices, ACTION_InstallServices },
7489 { szPatchFiles, ACTION_PatchFiles },
7490 { szProcessComponents, ACTION_ProcessComponents },
7491 { szPublishComponents, ACTION_PublishComponents },
7492 { szPublishFeatures, ACTION_PublishFeatures },
7493 { szPublishProduct, ACTION_PublishProduct },
7494 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7495 { szRegisterComPlus, ACTION_RegisterComPlus},
7496 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7497 { szRegisterFonts, ACTION_RegisterFonts },
7498 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7499 { szRegisterProduct, ACTION_RegisterProduct },
7500 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7501 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7502 { szRegisterUser, ACTION_RegisterUser },
7503 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7504 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7505 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7506 { szRemoveFiles, ACTION_RemoveFiles },
7507 { szRemoveFolders, ACTION_RemoveFolders },
7508 { szRemoveIniValues, ACTION_RemoveIniValues },
7509 { szRemoveODBC, ACTION_RemoveODBC },
7510 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7511 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7512 { szResolveSource, ACTION_ResolveSource },
7513 { szRMCCPSearch, ACTION_RMCCPSearch },
7514 { szScheduleReboot, ACTION_ScheduleReboot },
7515 { szSelfRegModules, ACTION_SelfRegModules },
7516 { szSelfUnregModules, ACTION_SelfUnregModules },
7517 { szSetODBCFolders, ACTION_SetODBCFolders },
7518 { szStartServices, ACTION_StartServices },
7519 { szStopServices, ACTION_StopServices },
7520 { szUnpublishComponents, ACTION_UnpublishComponents },
7521 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7522 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7523 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7524 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7525 { szUnregisterFonts, ACTION_UnregisterFonts },
7526 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7527 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7528 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7529 { szValidateProductID, ACTION_ValidateProductID },
7530 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7531 { szWriteIniValues, ACTION_WriteIniValues },
7532 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7536 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7542 while (StandardActions[i].action != NULL)
7544 if (!strcmpW( StandardActions[i].action, action ))
7546 ui_actionstart( package, action );
7547 if (StandardActions[i].handler)
7549 ui_actioninfo( package, action, TRUE, 0 );
7550 *rc = StandardActions[i].handler( package );
7551 ui_actioninfo( package, action, FALSE, *rc );
7555 FIXME("unhandled standard action %s\n", debugstr_w(action));
7556 *rc = ERROR_SUCCESS;
7566 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7568 UINT rc = ERROR_SUCCESS;
7571 TRACE("Performing action (%s)\n", debugstr_w(action));
7573 handled = ACTION_HandleStandardAction(package, action, &rc);
7576 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7580 WARN("unhandled msi action %s\n", debugstr_w(action));
7581 rc = ERROR_FUNCTION_NOT_CALLED;
7587 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7589 UINT rc = ERROR_SUCCESS;
7590 BOOL handled = FALSE;
7592 TRACE("Performing action (%s)\n", debugstr_w(action));
7594 handled = ACTION_HandleStandardAction(package, action, &rc);
7597 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7599 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7604 WARN("unhandled msi action %s\n", debugstr_w(action));
7605 rc = ERROR_FUNCTION_NOT_CALLED;
7611 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7613 UINT rc = ERROR_SUCCESS;
7616 static const WCHAR ExecSeqQuery[] =
7617 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7618 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7619 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7620 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7621 static const WCHAR UISeqQuery[] =
7622 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7623 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7624 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7625 ' ', '=',' ','%','i',0};
7627 if (needs_ui_sequence(package))
7628 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7630 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7634 LPCWSTR action, cond;
7636 TRACE("Running the actions\n");
7638 /* check conditions */
7639 cond = MSI_RecordGetString(row, 2);
7641 /* this is a hack to skip errors in the condition code */
7642 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7644 msiobj_release(&row->hdr);
7645 return ERROR_SUCCESS;
7648 action = MSI_RecordGetString(row, 1);
7651 ERR("failed to fetch action\n");
7652 msiobj_release(&row->hdr);
7653 return ERROR_FUNCTION_FAILED;
7656 if (needs_ui_sequence(package))
7657 rc = ACTION_PerformUIAction(package, action, -1);
7659 rc = ACTION_PerformAction(package, action, -1);
7661 msiobj_release(&row->hdr);
7667 /****************************************************
7668 * TOP level entry points
7669 *****************************************************/
7671 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7672 LPCWSTR szCommandLine )
7677 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7678 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7680 msi_set_property( package->db, szAction, szInstall );
7682 package->script->InWhatSequence = SEQUENCE_INSTALL;
7689 dir = strdupW(szPackagePath);
7690 p = strrchrW(dir, '\\');
7694 file = szPackagePath + (p - dir);
7699 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7700 GetCurrentDirectoryW(MAX_PATH, dir);
7701 lstrcatW(dir, szBackSlash);
7702 file = szPackagePath;
7705 msi_free( package->PackagePath );
7706 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7707 if (!package->PackagePath)
7710 return ERROR_OUTOFMEMORY;
7713 lstrcpyW(package->PackagePath, dir);
7714 lstrcatW(package->PackagePath, file);
7717 msi_set_sourcedir_props(package, FALSE);
7720 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7721 if (rc != ERROR_SUCCESS)
7724 msi_apply_transforms( package );
7725 msi_apply_patches( package );
7727 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7729 TRACE("setting reinstall property\n");
7730 msi_set_property( package->db, szReinstall, szAll );
7733 /* properties may have been added by a transform */
7734 msi_clone_properties( package );
7736 msi_parse_command_line( package, szCommandLine, FALSE );
7737 msi_adjust_privilege_properties( package );
7738 msi_set_context( package );
7740 if (needs_ui_sequence( package))
7742 package->script->InWhatSequence |= SEQUENCE_UI;
7743 rc = ACTION_ProcessUISequence(package);
7744 ui_exists = ui_sequence_exists(package);
7745 if (rc == ERROR_SUCCESS || !ui_exists)
7747 package->script->InWhatSequence |= SEQUENCE_EXEC;
7748 rc = ACTION_ProcessExecSequence(package, ui_exists);
7752 rc = ACTION_ProcessExecSequence(package, FALSE);
7754 package->script->CurrentlyScripting = FALSE;
7756 /* process the ending type action */
7757 if (rc == ERROR_SUCCESS)
7758 ACTION_PerformActionSequence(package, -1);
7759 else if (rc == ERROR_INSTALL_USEREXIT)
7760 ACTION_PerformActionSequence(package, -2);
7761 else if (rc == ERROR_INSTALL_SUSPEND)
7762 ACTION_PerformActionSequence(package, -4);
7764 ACTION_PerformActionSequence(package, -3);
7766 /* finish up running custom actions */
7767 ACTION_FinishCustomActions(package);
7769 if (rc == ERROR_SUCCESS && package->need_reboot)
7770 return ERROR_SUCCESS_REBOOT_REQUIRED;