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 szPatchFiles[] =
119 {'P','a','t','c','h','F','i','l','e','s',0};
120 static const WCHAR szPublishComponents[] =
121 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
122 static const WCHAR szRegisterComPlus[] =
123 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
124 static const WCHAR szRegisterUser[] =
125 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
126 static const WCHAR szRemoveEnvironmentStrings[] =
127 {'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};
128 static const WCHAR szRemoveExistingProducts[] =
129 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
130 static const WCHAR szRemoveFolders[] =
131 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
132 static const WCHAR szRemoveIniValues[] =
133 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
134 static const WCHAR szRemoveODBC[] =
135 {'R','e','m','o','v','e','O','D','B','C',0};
136 static const WCHAR szRemoveRegistryValues[] =
137 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
138 static const WCHAR szRemoveShortcuts[] =
139 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
140 static const WCHAR szRMCCPSearch[] =
141 {'R','M','C','C','P','S','e','a','r','c','h',0};
142 static const WCHAR szScheduleReboot[] =
143 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
144 static const WCHAR szSelfUnregModules[] =
145 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
146 static const WCHAR szSetODBCFolders[] =
147 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
148 static const WCHAR szStartServices[] =
149 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
150 static const WCHAR szStopServices[] =
151 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
152 static const WCHAR szUnpublishComponents[] =
153 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
154 static const WCHAR szUnpublishFeatures[] =
155 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
156 static const WCHAR szUnregisterComPlus[] =
157 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
158 static const WCHAR szUnregisterTypeLibraries[] =
159 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
160 static const WCHAR szValidateProductID[] =
161 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
162 static const WCHAR szWriteEnvironmentStrings[] =
163 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
165 /********************************************************
167 ********************************************************/
169 void msi_feature_set_state( MSIPACKAGE *package, MSIFEATURE *feature, INSTALLSTATE state )
171 if (!package->ProductCode)
173 feature->ActionRequest = state;
174 feature->Action = state;
176 else if (state == INSTALLSTATE_ABSENT)
178 switch (feature->Installed)
180 case INSTALLSTATE_ABSENT:
181 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
182 feature->Action = INSTALLSTATE_UNKNOWN;
185 feature->ActionRequest = state;
186 feature->Action = state;
189 else if (state == INSTALLSTATE_SOURCE)
191 switch (feature->Installed)
193 case INSTALLSTATE_ABSENT:
194 case INSTALLSTATE_SOURCE:
195 feature->ActionRequest = state;
196 feature->Action = state;
198 case INSTALLSTATE_LOCAL:
199 feature->ActionRequest = INSTALLSTATE_LOCAL;
200 feature->Action = INSTALLSTATE_LOCAL;
203 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
204 feature->Action = INSTALLSTATE_UNKNOWN;
209 feature->ActionRequest = state;
210 feature->Action = state;
214 void msi_component_set_state( MSIPACKAGE *package, MSICOMPONENT *comp, INSTALLSTATE state )
216 if (!package->ProductCode)
218 comp->ActionRequest = state;
219 comp->Action = state;
221 else if (state == INSTALLSTATE_ABSENT)
223 switch (comp->Installed)
225 case INSTALLSTATE_LOCAL:
226 case INSTALLSTATE_SOURCE:
227 case INSTALLSTATE_DEFAULT:
228 comp->ActionRequest = state;
229 comp->Action = state;
232 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
233 comp->Action = INSTALLSTATE_UNKNOWN;
236 else if (state == INSTALLSTATE_SOURCE)
238 if (comp->Installed == INSTALLSTATE_ABSENT ||
239 (comp->Installed == INSTALLSTATE_SOURCE && comp->hasLocalFeature))
241 comp->ActionRequest = state;
242 comp->Action = state;
246 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
247 comp->Action = INSTALLSTATE_UNKNOWN;
252 comp->ActionRequest = state;
253 comp->Action = state;
257 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
259 static const WCHAR Query_t[] =
260 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
261 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
262 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
263 ' ','\'','%','s','\'',0};
266 row = MSI_QueryGetRecord( package->db, Query_t, action );
269 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
270 msiobj_release(&row->hdr);
273 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
277 static const WCHAR template_s[]=
278 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
280 static const WCHAR template_e[]=
281 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
282 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
284 static const WCHAR format[] =
285 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
289 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
291 sprintfW(message,template_s,timet,action);
293 sprintfW(message,template_e,timet,action,rc);
295 row = MSI_CreateRecord(1);
296 MSI_RecordSetStringW(row,1,message);
298 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
299 msiobj_release(&row->hdr);
309 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
311 enum parse_state state = state_quote;
314 int ignore, in_quotes = 0, count = 0, len = 0;
316 for (p = str; *p; p++)
321 case state_whitespace:
325 if (!count) goto done;
331 if (in_quotes) count--;
336 if (!count) in_quotes = 0;
348 if (in_quotes) count--;
352 state = state_whitespace;
353 if (!count) goto done;
357 if (!count) in_quotes = 0;
368 if (in_quotes) count--;
372 state = state_whitespace;
373 if (!count || !len) goto done;
378 if (!count) in_quotes = 0;
387 if (!ignore) *out++ = *p;
391 if (!len) *value = 0;
398 static void remove_quotes( WCHAR *str )
401 int len = strlenW( str );
403 while ((p = strchrW( p, '"' )))
405 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
410 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
420 return ERROR_SUCCESS;
425 while (*ptr == ' ') ptr++;
428 ptr2 = strchrW( ptr, '=' );
429 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
432 if (!len) return ERROR_INVALID_COMMAND_LINE;
434 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
435 memcpy( prop, ptr, len * sizeof(WCHAR) );
437 if (!preserve_case) struprW( prop );
440 while (*ptr2 == ' ') ptr2++;
443 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
444 len = parse_prop( ptr2, val, "es );
447 WARN("unbalanced quotes\n");
450 return ERROR_INVALID_COMMAND_LINE;
452 remove_quotes( val );
453 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
455 r = msi_set_property( package->db, prop, val );
456 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
457 msi_reset_folders( package, TRUE );
465 return ERROR_SUCCESS;
469 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
472 LPWSTR p, *ret = NULL;
478 /* count the number of substrings */
479 for ( pc = str, count = 0; pc; count++ )
481 pc = strchrW( pc, sep );
486 /* allocate space for an array of substring pointers and the substrings */
487 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
488 (lstrlenW(str)+1) * sizeof(WCHAR) );
492 /* copy the string and set the pointers */
493 p = (LPWSTR) &ret[count+1];
495 for( count = 0; (ret[count] = p); count++ )
497 p = strchrW( p, sep );
505 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
507 static const WCHAR szSystemLanguageID[] =
508 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
510 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
511 UINT ret = ERROR_FUNCTION_FAILED;
513 prod_code = msi_dup_property( package->db, szProductCode );
514 patch_product = msi_get_suminfo_product( patch );
516 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
518 if ( strstrW( patch_product, prod_code ) )
523 si = MSI_GetSummaryInformationW( patch, 0 );
526 ERR("no summary information!\n");
530 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
533 ERR("no template property!\n");
534 msiobj_release( &si->hdr );
541 msiobj_release( &si->hdr );
545 langid = msi_dup_property( package->db, szSystemLanguageID );
548 msiobj_release( &si->hdr );
552 p = strchrW( template, ';' );
553 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
555 TRACE("applicable transform\n");
559 /* FIXME: check platform */
561 msiobj_release( &si->hdr );
565 msi_free( patch_product );
566 msi_free( prod_code );
567 msi_free( template );
573 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
574 MSIDATABASE *patch_db, LPCWSTR name )
576 UINT ret = ERROR_FUNCTION_FAILED;
577 IStorage *stg = NULL;
580 TRACE("%p %s\n", package, debugstr_w(name) );
584 ERR("expected a colon in %s\n", debugstr_w(name));
585 return ERROR_FUNCTION_FAILED;
588 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
591 ret = msi_check_transform_applicable( package, stg );
592 if (ret == ERROR_SUCCESS)
593 msi_table_apply_transform( package->db, stg );
595 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
596 IStorage_Release( stg );
599 ERR("failed to open substorage %s\n", debugstr_w(name));
601 return ERROR_SUCCESS;
604 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
606 LPWSTR guid_list, *guids, product_code;
607 UINT i, ret = ERROR_FUNCTION_FAILED;
609 product_code = msi_dup_property( package->db, szProductCode );
612 /* FIXME: the property ProductCode should be written into the DB somewhere */
613 ERR("no product code to check\n");
614 return ERROR_SUCCESS;
617 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
618 guids = msi_split_string( guid_list, ';' );
619 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
621 if (!strcmpW( guids[i], product_code ))
625 msi_free( guid_list );
626 msi_free( product_code );
631 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
634 MSIRECORD *rec = NULL;
639 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
640 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
641 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
642 '`','S','o','u','r','c','e','`',' ','I','S',' ',
643 'N','O','T',' ','N','U','L','L',0};
645 r = MSI_DatabaseOpenViewW(package->db, query, &view);
646 if (r != ERROR_SUCCESS)
649 r = MSI_ViewExecute(view, 0);
650 if (r != ERROR_SUCCESS)
653 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
655 prop = MSI_RecordGetString(rec, 1);
656 patch = msi_dup_property(package->db, szPatch);
657 msi_set_property(package->db, prop, patch);
662 if (rec) msiobj_release(&rec->hdr);
663 msiobj_release(&view->hdr);
668 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
671 UINT r = ERROR_SUCCESS;
674 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
676 return ERROR_OUTOFMEMORY;
678 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
682 return ERROR_OUTOFMEMORY;
688 msi_free( pi->patchcode );
690 return ERROR_PATCH_PACKAGE_INVALID;
693 p = strchrW( p + 1, '}' );
696 msi_free( pi->patchcode );
698 return ERROR_PATCH_PACKAGE_INVALID;
703 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
707 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
709 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
712 msi_free( pi->patchcode );
714 return ERROR_OUTOFMEMORY;
721 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
723 UINT i, r = ERROR_SUCCESS;
726 /* apply substorage transforms */
727 substorage = msi_split_string( patch->transforms, ';' );
728 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
729 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
731 msi_free( substorage );
732 if (r != ERROR_SUCCESS)
735 msi_set_media_source_prop( package );
738 * There might be a CAB file in the patch package,
739 * so append it to the list of storages to search for streams.
741 append_storage_to_db( package->db, patch_db->storage );
743 patch->state = MSIPATCHSTATE_APPLIED;
744 list_add_tail( &package->patches, &patch->entry );
745 return ERROR_SUCCESS;
748 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
750 static const WCHAR dotmsp[] = {'.','m','s','p',0};
751 MSIDATABASE *patch_db = NULL;
752 WCHAR localfile[MAX_PATH];
754 MSIPATCHINFO *patch = NULL;
755 UINT r = ERROR_SUCCESS;
757 TRACE("%p %s\n", package, debugstr_w( file ) );
759 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
760 if ( r != ERROR_SUCCESS )
762 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
766 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
769 msiobj_release( &patch_db->hdr );
770 return ERROR_FUNCTION_FAILED;
773 r = msi_check_patch_applicable( package, si );
774 if (r != ERROR_SUCCESS)
776 TRACE("patch not applicable\n");
781 r = msi_parse_patch_summary( si, &patch );
782 if ( r != ERROR_SUCCESS )
785 r = msi_get_local_package_name( localfile, dotmsp );
786 if ( r != ERROR_SUCCESS )
789 TRACE("copying to local package %s\n", debugstr_w(localfile));
791 if (!CopyFileW( file, localfile, FALSE ))
793 ERR("Unable to copy package (%s -> %s) (error %u)\n",
794 debugstr_w(file), debugstr_w(localfile), GetLastError());
798 patch->localfile = strdupW( localfile );
800 r = msi_apply_patch_db( package, patch_db, patch );
801 if ( r != ERROR_SUCCESS )
802 WARN("patch failed to apply %u\n", r);
805 msiobj_release( &si->hdr );
806 msiobj_release( &patch_db->hdr );
807 if (patch && r != ERROR_SUCCESS)
809 if (patch->localfile)
810 DeleteFileW( patch->localfile );
812 msi_free( patch->patchcode );
813 msi_free( patch->transforms );
814 msi_free( patch->localfile );
820 /* get the PATCH property, and apply all the patches it specifies */
821 static UINT msi_apply_patches( MSIPACKAGE *package )
823 LPWSTR patch_list, *patches;
824 UINT i, r = ERROR_SUCCESS;
826 patch_list = msi_dup_property( package->db, szPatch );
828 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
830 patches = msi_split_string( patch_list, ';' );
831 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
832 r = msi_apply_patch_package( package, patches[i] );
835 msi_free( patch_list );
840 static UINT msi_apply_transforms( MSIPACKAGE *package )
842 static const WCHAR szTransforms[] = {
843 'T','R','A','N','S','F','O','R','M','S',0 };
844 LPWSTR xform_list, *xforms;
845 UINT i, r = ERROR_SUCCESS;
847 xform_list = msi_dup_property( package->db, szTransforms );
848 xforms = msi_split_string( xform_list, ';' );
850 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
852 if (xforms[i][0] == ':')
853 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
858 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
861 WCHAR *p = strrchrW( package->PackagePath, '\\' );
862 DWORD len = p - package->PackagePath + 1;
864 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
867 msi_free( xform_list );
868 return ERROR_OUTOFMEMORY;
870 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
871 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
873 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
874 if (transform != xforms[i]) msi_free( transform );
879 msi_free( xform_list );
884 static BOOL ui_sequence_exists( MSIPACKAGE *package )
889 static const WCHAR ExecSeqQuery [] =
890 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
891 '`','I','n','s','t','a','l','l',
892 'U','I','S','e','q','u','e','n','c','e','`',
893 ' ','W','H','E','R','E',' ',
894 '`','S','e','q','u','e','n','c','e','`',' ',
895 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
896 '`','S','e','q','u','e','n','c','e','`',0};
898 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
899 if (rc == ERROR_SUCCESS)
901 msiobj_release(&view->hdr);
908 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
910 LPWSTR source, check;
912 if (msi_get_property_int( package->db, szInstalled, 0 ))
916 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
917 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
925 db = msi_dup_property( package->db, szOriginalDatabase );
927 return ERROR_OUTOFMEMORY;
929 p = strrchrW( db, '\\' );
932 p = strrchrW( db, '/' );
936 return ERROR_SUCCESS;
941 source = msi_alloc( len * sizeof(WCHAR) );
942 lstrcpynW( source, db, len );
946 check = msi_dup_property( package->db, cszSourceDir );
947 if (!check || replace)
949 UINT r = msi_set_property( package->db, cszSourceDir, source );
950 if (r == ERROR_SUCCESS)
951 msi_reset_folders( package, TRUE );
955 check = msi_dup_property( package->db, cszSOURCEDIR );
956 if (!check || replace)
957 msi_set_property( package->db, cszSOURCEDIR, source );
962 return ERROR_SUCCESS;
965 static BOOL needs_ui_sequence(MSIPACKAGE *package)
967 INT level = msi_get_property_int(package->db, szUILevel, 0);
968 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
971 UINT msi_set_context(MSIPACKAGE *package)
975 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
977 num = msi_get_property_int(package->db, szAllUsers, 0);
978 if (num == 1 || num == 2)
979 package->Context = MSIINSTALLCONTEXT_MACHINE;
981 return ERROR_SUCCESS;
984 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
987 LPCWSTR cond, action;
988 MSIPACKAGE *package = param;
990 action = MSI_RecordGetString(row,1);
993 ERR("Error is retrieving action name\n");
994 return ERROR_FUNCTION_FAILED;
997 /* check conditions */
998 cond = MSI_RecordGetString(row,2);
1000 /* this is a hack to skip errors in the condition code */
1001 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1003 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
1004 return ERROR_SUCCESS;
1007 if (needs_ui_sequence(package))
1008 rc = ACTION_PerformUIAction(package, action, -1);
1010 rc = ACTION_PerformAction(package, action, -1);
1012 msi_dialog_check_messages( NULL );
1014 if (package->CurrentInstallState != ERROR_SUCCESS)
1015 rc = package->CurrentInstallState;
1017 if (rc == ERROR_FUNCTION_NOT_CALLED)
1020 if (rc != ERROR_SUCCESS)
1021 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
1026 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
1030 static const WCHAR query[] =
1031 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1033 ' ','W','H','E','R','E',' ',
1034 '`','S','e','q','u','e','n','c','e','`',' ',
1035 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1036 '`','S','e','q','u','e','n','c','e','`',0};
1038 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
1040 r = MSI_OpenQuery( package->db, &view, query, szTable );
1041 if (r == ERROR_SUCCESS)
1043 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
1044 msiobj_release(&view->hdr);
1050 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1054 static const WCHAR ExecSeqQuery[] =
1055 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1056 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1057 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1058 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1059 'O','R','D','E','R',' ', 'B','Y',' ',
1060 '`','S','e','q','u','e','n','c','e','`',0 };
1061 static const WCHAR IVQuery[] =
1062 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1063 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1064 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1065 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1066 ' ','\'', 'I','n','s','t','a','l','l',
1067 'V','a','l','i','d','a','t','e','\'', 0};
1070 if (package->script->ExecuteSequenceRun)
1072 TRACE("Execute Sequence already Run\n");
1073 return ERROR_SUCCESS;
1076 package->script->ExecuteSequenceRun = TRUE;
1078 /* get the sequence number */
1081 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
1083 return ERROR_FUNCTION_FAILED;
1084 seq = MSI_RecordGetInteger(row,1);
1085 msiobj_release(&row->hdr);
1088 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1089 if (rc == ERROR_SUCCESS)
1091 TRACE("Running the actions\n");
1093 msi_set_property(package->db, cszSourceDir, NULL);
1095 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1096 msiobj_release(&view->hdr);
1102 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1106 static const WCHAR ExecSeqQuery [] =
1107 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1108 '`','I','n','s','t','a','l','l',
1109 'U','I','S','e','q','u','e','n','c','e','`',
1110 ' ','W','H','E','R','E',' ',
1111 '`','S','e','q','u','e','n','c','e','`',' ',
1112 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1113 '`','S','e','q','u','e','n','c','e','`',0};
1115 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1116 if (rc == ERROR_SUCCESS)
1118 TRACE("Running the actions\n");
1120 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1121 msiobj_release(&view->hdr);
1127 /********************************************************
1128 * ACTION helper functions and functions that perform the actions
1129 *******************************************************/
1130 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1131 UINT* rc, UINT script, BOOL force )
1136 arc = ACTION_CustomAction(package, action, script, force);
1138 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1147 * Actual Action Handlers
1150 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1152 MSIPACKAGE *package = param;
1153 LPCWSTR dir, component;
1159 component = MSI_RecordGetString(row, 2);
1161 return ERROR_SUCCESS;
1163 comp = get_loaded_component(package, component);
1165 return ERROR_SUCCESS;
1169 TRACE("component is disabled\n");
1170 return ERROR_SUCCESS;
1173 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1175 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1176 comp->Action = comp->Installed;
1177 return ERROR_SUCCESS;
1179 comp->Action = INSTALLSTATE_LOCAL;
1181 dir = MSI_RecordGetString(row,1);
1184 ERR("Unable to get folder id\n");
1185 return ERROR_SUCCESS;
1188 uirow = MSI_CreateRecord(1);
1189 MSI_RecordSetStringW(uirow, 1, dir);
1190 ui_actiondata(package, szCreateFolders, uirow);
1191 msiobj_release(&uirow->hdr);
1193 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1196 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1197 return ERROR_SUCCESS;
1200 TRACE("Folder is %s\n",debugstr_w(full_path));
1202 if (folder->State == 0)
1203 create_full_pathW(full_path);
1207 msi_free(full_path);
1208 return ERROR_SUCCESS;
1211 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1213 static const WCHAR query[] =
1214 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1215 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1219 /* create all the empty folders specified in the CreateFolder table */
1220 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1221 if (rc != ERROR_SUCCESS)
1222 return ERROR_SUCCESS;
1224 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1225 msiobj_release(&view->hdr);
1230 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1232 MSIPACKAGE *package = param;
1233 LPCWSTR dir, component;
1239 component = MSI_RecordGetString(row, 2);
1241 return ERROR_SUCCESS;
1243 comp = get_loaded_component(package, component);
1245 return ERROR_SUCCESS;
1249 TRACE("component is disabled\n");
1250 return ERROR_SUCCESS;
1253 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1255 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1256 comp->Action = comp->Installed;
1257 return ERROR_SUCCESS;
1259 comp->Action = INSTALLSTATE_ABSENT;
1261 dir = MSI_RecordGetString( row, 1 );
1264 ERR("Unable to get folder id\n");
1265 return ERROR_SUCCESS;
1268 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1271 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1272 return ERROR_SUCCESS;
1275 TRACE("folder is %s\n", debugstr_w(full_path));
1277 uirow = MSI_CreateRecord( 1 );
1278 MSI_RecordSetStringW( uirow, 1, dir );
1279 ui_actiondata( package, szRemoveFolders, uirow );
1280 msiobj_release( &uirow->hdr );
1282 RemoveDirectoryW( full_path );
1285 msi_free( full_path );
1286 return ERROR_SUCCESS;
1289 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1291 static const WCHAR query[] =
1292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1293 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1298 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1299 if (rc != ERROR_SUCCESS)
1300 return ERROR_SUCCESS;
1302 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1303 msiobj_release( &view->hdr );
1308 static UINT load_component( MSIRECORD *row, LPVOID param )
1310 MSIPACKAGE *package = param;
1313 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1315 return ERROR_FUNCTION_FAILED;
1317 list_add_tail( &package->components, &comp->entry );
1319 /* fill in the data */
1320 comp->Component = msi_dup_record_field( row, 1 );
1322 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1324 comp->ComponentId = msi_dup_record_field( row, 2 );
1325 comp->Directory = msi_dup_record_field( row, 3 );
1326 comp->Attributes = MSI_RecordGetInteger(row,4);
1327 comp->Condition = msi_dup_record_field( row, 5 );
1328 comp->KeyPath = msi_dup_record_field( row, 6 );
1330 comp->Installed = INSTALLSTATE_UNKNOWN;
1331 comp->Action = INSTALLSTATE_UNKNOWN;
1332 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1334 comp->assembly = load_assembly( package, comp );
1335 return ERROR_SUCCESS;
1338 static UINT load_all_components( MSIPACKAGE *package )
1340 static const WCHAR query[] = {
1341 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1342 '`','C','o','m','p','o','n','e','n','t','`',0 };
1346 if (!list_empty(&package->components))
1347 return ERROR_SUCCESS;
1349 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1350 if (r != ERROR_SUCCESS)
1353 r = MSI_IterateRecords(view, NULL, load_component, package);
1354 msiobj_release(&view->hdr);
1359 MSIPACKAGE *package;
1360 MSIFEATURE *feature;
1363 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1367 cl = msi_alloc( sizeof (*cl) );
1369 return ERROR_NOT_ENOUGH_MEMORY;
1370 cl->component = comp;
1371 list_add_tail( &feature->Components, &cl->entry );
1373 return ERROR_SUCCESS;
1376 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1380 fl = msi_alloc( sizeof(*fl) );
1382 return ERROR_NOT_ENOUGH_MEMORY;
1383 fl->feature = child;
1384 list_add_tail( &parent->Children, &fl->entry );
1386 return ERROR_SUCCESS;
1389 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1391 _ilfs* ilfs = param;
1395 component = MSI_RecordGetString(row,1);
1397 /* check to see if the component is already loaded */
1398 comp = get_loaded_component( ilfs->package, component );
1401 ERR("unknown component %s\n", debugstr_w(component));
1402 return ERROR_FUNCTION_FAILED;
1405 add_feature_component( ilfs->feature, comp );
1406 comp->Enabled = TRUE;
1408 return ERROR_SUCCESS;
1411 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1413 MSIFEATURE *feature;
1418 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1420 if ( !strcmpW( feature->Feature, name ) )
1427 static UINT load_feature(MSIRECORD * row, LPVOID param)
1429 MSIPACKAGE* package = param;
1430 MSIFEATURE* feature;
1431 static const WCHAR Query1[] =
1432 {'S','E','L','E','C','T',' ',
1433 '`','C','o','m','p','o','n','e','n','t','_','`',
1434 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1435 'C','o','m','p','o','n','e','n','t','s','`',' ',
1436 'W','H','E','R','E',' ',
1437 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1442 /* fill in the data */
1444 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1446 return ERROR_NOT_ENOUGH_MEMORY;
1448 list_init( &feature->Children );
1449 list_init( &feature->Components );
1451 feature->Feature = msi_dup_record_field( row, 1 );
1453 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1455 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1456 feature->Title = msi_dup_record_field( row, 3 );
1457 feature->Description = msi_dup_record_field( row, 4 );
1459 if (!MSI_RecordIsNull(row,5))
1460 feature->Display = MSI_RecordGetInteger(row,5);
1462 feature->Level= MSI_RecordGetInteger(row,6);
1463 feature->Directory = msi_dup_record_field( row, 7 );
1464 feature->Attributes = MSI_RecordGetInteger(row,8);
1466 feature->Installed = INSTALLSTATE_UNKNOWN;
1467 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1469 list_add_tail( &package->features, &feature->entry );
1471 /* load feature components */
1473 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1474 if (rc != ERROR_SUCCESS)
1475 return ERROR_SUCCESS;
1477 ilfs.package = package;
1478 ilfs.feature = feature;
1480 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1481 msiobj_release(&view->hdr);
1483 return ERROR_SUCCESS;
1486 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1488 MSIPACKAGE* package = param;
1489 MSIFEATURE *parent, *child;
1491 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1493 return ERROR_FUNCTION_FAILED;
1495 if (!child->Feature_Parent)
1496 return ERROR_SUCCESS;
1498 parent = find_feature_by_name( package, child->Feature_Parent );
1500 return ERROR_FUNCTION_FAILED;
1502 add_feature_child( parent, child );
1503 return ERROR_SUCCESS;
1506 static UINT load_all_features( MSIPACKAGE *package )
1508 static const WCHAR query[] = {
1509 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1510 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1511 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1515 if (!list_empty(&package->features))
1516 return ERROR_SUCCESS;
1518 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1519 if (r != ERROR_SUCCESS)
1522 r = MSI_IterateRecords( view, NULL, load_feature, package );
1523 if (r != ERROR_SUCCESS)
1526 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1527 msiobj_release( &view->hdr );
1532 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1543 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1545 static const WCHAR query[] = {
1546 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1547 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1548 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1549 MSIQUERY *view = NULL;
1550 MSIRECORD *row = NULL;
1553 TRACE("%s\n", debugstr_w(file->File));
1555 r = MSI_OpenQuery(package->db, &view, query, file->File);
1556 if (r != ERROR_SUCCESS)
1559 r = MSI_ViewExecute(view, NULL);
1560 if (r != ERROR_SUCCESS)
1563 r = MSI_ViewFetch(view, &row);
1564 if (r != ERROR_SUCCESS)
1567 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1568 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1569 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1570 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1571 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1574 if (view) msiobj_release(&view->hdr);
1575 if (row) msiobj_release(&row->hdr);
1579 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1582 static const WCHAR query[] = {
1583 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1584 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1585 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1587 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1590 WARN("query failed\n");
1591 return ERROR_FUNCTION_FAILED;
1594 file->disk_id = MSI_RecordGetInteger( row, 1 );
1595 msiobj_release( &row->hdr );
1596 return ERROR_SUCCESS;
1599 static UINT load_file(MSIRECORD *row, LPVOID param)
1601 MSIPACKAGE* package = param;
1605 /* fill in the data */
1607 file = msi_alloc_zero( sizeof (MSIFILE) );
1609 return ERROR_NOT_ENOUGH_MEMORY;
1611 file->File = msi_dup_record_field( row, 1 );
1613 component = MSI_RecordGetString( row, 2 );
1614 file->Component = get_loaded_component( package, component );
1616 if (!file->Component)
1618 WARN("Component not found: %s\n", debugstr_w(component));
1619 msi_free(file->File);
1621 return ERROR_SUCCESS;
1624 file->FileName = msi_dup_record_field( row, 3 );
1625 reduce_to_longfilename( file->FileName );
1627 file->ShortName = msi_dup_record_field( row, 3 );
1628 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1630 file->FileSize = MSI_RecordGetInteger( row, 4 );
1631 file->Version = msi_dup_record_field( row, 5 );
1632 file->Language = msi_dup_record_field( row, 6 );
1633 file->Attributes = MSI_RecordGetInteger( row, 7 );
1634 file->Sequence = MSI_RecordGetInteger( row, 8 );
1636 file->state = msifs_invalid;
1638 /* if the compressed bits are not set in the file attributes,
1639 * then read the information from the package word count property
1641 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1643 file->IsCompressed = FALSE;
1645 else if (file->Attributes &
1646 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1648 file->IsCompressed = TRUE;
1650 else if (file->Attributes & msidbFileAttributesNoncompressed)
1652 file->IsCompressed = FALSE;
1656 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1659 load_file_hash(package, file);
1660 load_file_disk_id(package, file);
1662 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1664 list_add_tail( &package->files, &file->entry );
1666 return ERROR_SUCCESS;
1669 static UINT load_all_files(MSIPACKAGE *package)
1673 static const WCHAR Query[] =
1674 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1675 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1676 '`','S','e','q','u','e','n','c','e','`', 0};
1678 if (!list_empty(&package->files))
1679 return ERROR_SUCCESS;
1681 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1682 if (rc != ERROR_SUCCESS)
1683 return ERROR_SUCCESS;
1685 rc = MSI_IterateRecords(view, NULL, load_file, package);
1686 msiobj_release(&view->hdr);
1688 return ERROR_SUCCESS;
1691 static UINT load_folder( MSIRECORD *row, LPVOID param )
1693 MSIPACKAGE *package = param;
1694 static WCHAR szEmpty[] = { 0 };
1695 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1698 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1700 return ERROR_NOT_ENOUGH_MEMORY;
1702 folder->Directory = msi_dup_record_field( row, 1 );
1704 TRACE("%s\n", debugstr_w(folder->Directory));
1706 p = msi_dup_record_field(row, 3);
1708 /* split src and target dir */
1710 src_short = folder_split_path( p, ':' );
1712 /* split the long and short paths */
1713 tgt_long = folder_split_path( tgt_short, '|' );
1714 src_long = folder_split_path( src_short, '|' );
1716 /* check for no-op dirs */
1717 if (tgt_short && !strcmpW( szDot, tgt_short ))
1718 tgt_short = szEmpty;
1719 if (src_short && !strcmpW( szDot, src_short ))
1720 src_short = szEmpty;
1723 tgt_long = tgt_short;
1726 src_short = tgt_short;
1727 src_long = tgt_long;
1731 src_long = src_short;
1733 /* FIXME: use the target short path too */
1734 folder->TargetDefault = strdupW(tgt_long);
1735 folder->SourceShortPath = strdupW(src_short);
1736 folder->SourceLongPath = strdupW(src_long);
1739 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1740 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1741 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1743 folder->Parent = msi_dup_record_field( row, 2 );
1745 folder->Property = msi_dup_property( package->db, folder->Directory );
1747 list_add_tail( &package->folders, &folder->entry );
1749 TRACE("returning %p\n", folder);
1751 return ERROR_SUCCESS;
1754 static UINT load_all_folders( MSIPACKAGE *package )
1756 static const WCHAR query[] = {
1757 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1758 '`','D','i','r','e','c','t','o','r','y','`',0 };
1762 if (!list_empty(&package->folders))
1763 return ERROR_SUCCESS;
1765 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1766 if (r != ERROR_SUCCESS)
1769 r = MSI_IterateRecords(view, NULL, load_folder, package);
1770 msiobj_release(&view->hdr);
1775 * I am not doing any of the costing functionality yet.
1776 * Mostly looking at doing the Component and Feature loading
1778 * The native MSI does A LOT of modification to tables here. Mostly adding
1779 * a lot of temporary columns to the Feature and Component tables.
1781 * note: Native msi also tracks the short filename. But I am only going to
1782 * track the long ones. Also looking at this directory table
1783 * it appears that the directory table does not get the parents
1784 * resolved base on property only based on their entries in the
1787 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1789 static const WCHAR szCosting[] =
1790 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1792 msi_set_property( package->db, szCosting, szZero );
1793 msi_set_property( package->db, cszRootDrive, c_colon );
1795 load_all_folders( package );
1796 load_all_components( package );
1797 load_all_features( package );
1798 load_all_files( package );
1800 return ERROR_SUCCESS;
1803 static UINT execute_script(MSIPACKAGE *package, UINT script )
1806 UINT rc = ERROR_SUCCESS;
1808 TRACE("Executing Script %i\n",script);
1810 if (!package->script)
1812 ERR("no script!\n");
1813 return ERROR_FUNCTION_FAILED;
1816 for (i = 0; i < package->script->ActionCount[script]; i++)
1819 action = package->script->Actions[script][i];
1820 ui_actionstart(package, action);
1821 TRACE("Executing Action (%s)\n",debugstr_w(action));
1822 rc = ACTION_PerformAction(package, action, script);
1823 if (rc != ERROR_SUCCESS)
1826 msi_free_action_script(package, script);
1830 static UINT ACTION_FileCost(MSIPACKAGE *package)
1832 return ERROR_SUCCESS;
1835 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1841 state = MsiQueryProductStateW(package->ProductCode);
1843 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1845 if (!comp->Enabled || !comp->ComponentId)
1848 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1849 comp->Installed = INSTALLSTATE_ABSENT;
1852 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1853 package->Context, comp->ComponentId,
1855 if (r != ERROR_SUCCESS)
1856 comp->Installed = INSTALLSTATE_ABSENT;
1861 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1863 MSIFEATURE *feature;
1866 state = MsiQueryProductStateW(package->ProductCode);
1868 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1870 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1871 feature->Installed = INSTALLSTATE_ABSENT;
1874 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1880 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1882 return (feature->Level > 0 && feature->Level <= level);
1885 static BOOL process_state_property(MSIPACKAGE* package, int level,
1886 LPCWSTR property, INSTALLSTATE state)
1889 MSIFEATURE *feature;
1891 override = msi_dup_property( package->db, property );
1895 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1897 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1900 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1902 if (!strcmpiW( override, szAll ))
1903 msi_feature_set_state(package, feature, state);
1906 LPWSTR ptr = override;
1907 LPWSTR ptr2 = strchrW(override,',');
1911 int len = ptr2 - ptr;
1913 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1914 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1916 msi_feature_set_state(package, feature, state);
1922 ptr2 = strchrW(ptr,',');
1934 static BOOL process_overrides( MSIPACKAGE *package, int level )
1936 static const WCHAR szAddLocal[] =
1937 {'A','D','D','L','O','C','A','L',0};
1938 static const WCHAR szAddSource[] =
1939 {'A','D','D','S','O','U','R','C','E',0};
1940 static const WCHAR szAdvertise[] =
1941 {'A','D','V','E','R','T','I','S','E',0};
1944 /* all these activation/deactivation things happen in order and things
1945 * later on the list override things earlier on the list.
1947 * 0 INSTALLLEVEL processing
1960 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1961 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1962 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1963 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1964 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1967 msi_set_property( package->db, szPreselected, szOne );
1972 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1975 static const WCHAR szlevel[] =
1976 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1977 MSICOMPONENT* component;
1978 MSIFEATURE *feature;
1980 TRACE("Checking Install Level\n");
1982 level = msi_get_property_int(package->db, szlevel, 1);
1984 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1986 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1988 if (!is_feature_selected( feature, level )) continue;
1990 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1992 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1993 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1994 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1995 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1997 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
2001 /* disable child features of unselected parent features */
2002 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2006 if (is_feature_selected( feature, level )) continue;
2008 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
2009 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
2012 else /* preselected */
2014 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2016 if (!is_feature_selected( feature, level )) continue;
2018 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2020 msi_feature_set_state(package, feature, feature->Installed);
2026 * now we want to enable or disable components based on feature
2028 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2032 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
2033 debugstr_w(feature->Feature), feature->Level, feature->Installed,
2034 feature->ActionRequest, feature->Action);
2036 if (!is_feature_selected( feature, level )) continue;
2038 /* features with components that have compressed files are made local */
2039 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2041 if (!cl->component->Enabled) continue;
2043 if (cl->component->ForceLocalState &&
2044 feature->ActionRequest == INSTALLSTATE_SOURCE)
2046 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
2051 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2053 component = cl->component;
2055 if (!component->Enabled) continue;
2057 switch (feature->ActionRequest)
2059 case INSTALLSTATE_ABSENT:
2060 component->anyAbsent = 1;
2062 case INSTALLSTATE_ADVERTISED:
2063 component->hasAdvertiseFeature = 1;
2065 case INSTALLSTATE_SOURCE:
2066 component->hasSourceFeature = 1;
2068 case INSTALLSTATE_LOCAL:
2069 component->hasLocalFeature = 1;
2071 case INSTALLSTATE_DEFAULT:
2072 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2073 component->hasAdvertiseFeature = 1;
2074 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2075 component->hasSourceFeature = 1;
2077 component->hasLocalFeature = 1;
2085 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2087 if (!component->Enabled) continue;
2089 /* check if it's local or source */
2090 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2091 (component->hasLocalFeature || component->hasSourceFeature))
2093 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2094 !component->ForceLocalState)
2095 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2097 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2101 /* if any feature is local, the component must be local too */
2102 if (component->hasLocalFeature)
2104 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2108 if (component->hasSourceFeature)
2110 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2114 if (component->hasAdvertiseFeature)
2116 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2120 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2121 if (component->anyAbsent)
2122 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2125 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2127 if (!component->Enabled) continue;
2129 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2131 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2132 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2135 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2136 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2139 return ERROR_SUCCESS;
2142 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2144 MSIPACKAGE *package = param;
2149 name = MSI_RecordGetString(row,1);
2151 f = get_loaded_folder(package, name);
2152 if (!f) return ERROR_SUCCESS;
2154 /* reset the ResolvedTarget */
2155 msi_free(f->ResolvedTarget);
2156 f->ResolvedTarget = NULL;
2158 /* This helper function now does ALL the work */
2159 TRACE("Dir %s ...\n",debugstr_w(name));
2160 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2161 TRACE("resolves to %s\n",debugstr_w(path));
2164 return ERROR_SUCCESS;
2167 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2169 MSIPACKAGE *package = param;
2171 MSIFEATURE *feature;
2173 name = MSI_RecordGetString( row, 1 );
2175 feature = get_loaded_feature( package, name );
2177 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2181 Condition = MSI_RecordGetString(row,3);
2183 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2185 int level = MSI_RecordGetInteger(row,2);
2186 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2187 feature->Level = level;
2190 return ERROR_SUCCESS;
2193 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2195 static const WCHAR name[] = {'\\',0};
2196 VS_FIXEDFILEINFO *ptr, *ret;
2198 DWORD versize, handle;
2201 TRACE("%s\n", debugstr_w(filename));
2203 versize = GetFileVersionInfoSizeW( filename, &handle );
2207 version = msi_alloc( versize );
2211 GetFileVersionInfoW( filename, 0, versize, version );
2213 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2215 msi_free( version );
2219 ret = msi_alloc( sz );
2220 memcpy( ret, ptr, sz );
2222 msi_free( version );
2226 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2230 msi_parse_version_string( version, &ms, &ls );
2232 if (fi->dwFileVersionMS > ms) return 1;
2233 else if (fi->dwFileVersionMS < ms) return -1;
2234 else if (fi->dwFileVersionLS > ls) return 1;
2235 else if (fi->dwFileVersionLS < ls) return -1;
2239 static DWORD get_disk_file_size( LPCWSTR filename )
2244 TRACE("%s\n", debugstr_w(filename));
2246 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2247 if (file == INVALID_HANDLE_VALUE)
2248 return INVALID_FILE_SIZE;
2250 size = GetFileSize( file, NULL );
2251 CloseHandle( file );
2255 static BOOL hash_matches( MSIFILE *file )
2258 MSIFILEHASHINFO hash;
2260 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2261 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2262 if (r != ERROR_SUCCESS)
2265 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2268 static WCHAR *get_temp_dir( void )
2271 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2273 GetTempPathW( MAX_PATH, tmp );
2276 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2277 if (CreateDirectoryW( dir, NULL )) break;
2279 return strdupW( dir );
2282 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2284 MSIASSEMBLY *assembly = file->Component->assembly;
2286 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2288 msi_free( file->TargetPath );
2289 if (assembly && !assembly->application)
2291 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2292 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2293 track_tempfile( package, file->TargetPath );
2297 WCHAR *dir = resolve_folder( package, file->Component->Directory, FALSE, FALSE, TRUE, NULL );
2298 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2302 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2305 static UINT set_file_install_states( MSIPACKAGE *package )
2307 VS_FIXEDFILEINFO *file_version;
2310 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2312 MSICOMPONENT *comp = file->Component;
2315 if (!comp->Enabled) continue;
2317 if (file->IsCompressed)
2318 comp->ForceLocalState = TRUE;
2320 set_target_path( package, file );
2322 if ((comp->assembly && !comp->assembly->installed) ||
2323 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2325 file->state = msifs_missing;
2326 comp->Cost += file->FileSize;
2329 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2331 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2332 HIWORD(file_version->dwFileVersionMS),
2333 LOWORD(file_version->dwFileVersionMS),
2334 HIWORD(file_version->dwFileVersionLS),
2335 LOWORD(file_version->dwFileVersionLS));
2337 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2339 file->state = msifs_overwrite;
2340 comp->Cost += file->FileSize;
2344 TRACE("Destination file version equal or greater, not overwriting\n");
2345 file->state = msifs_present;
2347 msi_free( file_version );
2350 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2352 file->state = msifs_overwrite;
2353 comp->Cost += file->FileSize - file_size;
2356 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2358 TRACE("File hashes match, not overwriting\n");
2359 file->state = msifs_present;
2362 file->state = msifs_overwrite;
2363 comp->Cost += file->FileSize - file_size;
2366 return ERROR_SUCCESS;
2370 * A lot is done in this function aside from just the costing.
2371 * The costing needs to be implemented at some point but for now I am going
2372 * to focus on the directory building
2375 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2377 static const WCHAR ExecSeqQuery[] =
2378 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2379 '`','D','i','r','e','c','t','o','r','y','`',0};
2380 static const WCHAR ConditionQuery[] =
2381 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2382 '`','C','o','n','d','i','t','i','o','n','`',0};
2383 static const WCHAR szCosting[] =
2384 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2385 static const WCHAR szlevel[] =
2386 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2387 static const WCHAR szOutOfDiskSpace[] =
2388 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2390 UINT rc = ERROR_SUCCESS;
2394 TRACE("Building Directory properties\n");
2396 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2397 if (rc == ERROR_SUCCESS)
2399 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2401 msiobj_release(&view->hdr);
2404 TRACE("Evaluating component conditions\n");
2405 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2407 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2409 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2410 comp->Enabled = FALSE;
2413 comp->Enabled = TRUE;
2416 /* read components states from the registry */
2417 ACTION_GetComponentInstallStates(package);
2418 ACTION_GetFeatureInstallStates(package);
2420 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2422 TRACE("Evaluating feature conditions\n");
2424 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2425 if (rc == ERROR_SUCCESS)
2427 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2428 msiobj_release( &view->hdr );
2432 TRACE("Calculating file install states\n");
2433 set_file_install_states( package );
2435 msi_set_property( package->db, szCosting, szOne );
2436 /* set default run level if not set */
2437 level = msi_dup_property( package->db, szlevel );
2439 msi_set_property( package->db, szlevel, szOne );
2442 /* FIXME: check volume disk space */
2443 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2445 return MSI_SetFeatureStates(package);
2448 /* OK this value is "interpreted" and then formatted based on the
2449 first few characters */
2450 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2455 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2461 LPWSTR deformated = NULL;
2464 deformat_string(package, &value[2], &deformated);
2466 /* binary value type */
2470 *size = (strlenW(ptr)/2)+1;
2472 *size = strlenW(ptr)/2;
2474 data = msi_alloc(*size);
2480 /* if uneven pad with a zero in front */
2486 data[count] = (BYTE)strtol(byte,NULL,0);
2488 TRACE("Uneven byte count\n");
2496 data[count] = (BYTE)strtol(byte,NULL,0);
2499 msi_free(deformated);
2501 TRACE("Data %i bytes(%i)\n",*size,count);
2508 deformat_string(package, &value[1], &deformated);
2511 *size = sizeof(DWORD);
2512 data = msi_alloc(*size);
2518 if ( (*p < '0') || (*p > '9') )
2524 if (deformated[0] == '-')
2527 TRACE("DWORD %i\n",*(LPDWORD)data);
2529 msi_free(deformated);
2534 static const WCHAR szMulti[] = {'[','~',']',0};
2543 *type=REG_EXPAND_SZ;
2551 if (strstrW(value, szMulti))
2552 *type = REG_MULTI_SZ;
2554 /* remove initial delimiter */
2555 if (!strncmpW(value, szMulti, 3))
2558 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2560 /* add double NULL terminator */
2561 if (*type == REG_MULTI_SZ)
2563 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2564 data = msi_realloc_zero(data, *size);
2570 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2577 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2579 *root_key = HKEY_LOCAL_MACHINE;
2584 *root_key = HKEY_CURRENT_USER;
2589 *root_key = HKEY_CLASSES_ROOT;
2593 *root_key = HKEY_CURRENT_USER;
2597 *root_key = HKEY_LOCAL_MACHINE;
2601 *root_key = HKEY_USERS;
2605 ERR("Unknown root %i\n", root);
2612 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2614 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2615 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2617 if (is_64bit && package->platform == PLATFORM_INTEL &&
2618 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2623 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2624 path_32node = msi_alloc( size );
2628 memcpy( path_32node, path, len * sizeof(WCHAR) );
2629 path_32node[len] = 0;
2630 strcatW( path_32node, szWow6432Node );
2631 strcatW( path_32node, szBackSlash );
2632 strcatW( path_32node, path + len );
2636 return strdupW( path );
2639 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2641 MSIPACKAGE *package = param;
2642 LPSTR value_data = NULL;
2643 HKEY root_key, hkey;
2645 LPWSTR deformated, uikey, keypath;
2646 LPCWSTR szRoot, component, name, key, value;
2650 BOOL check_first = FALSE;
2653 ui_progress(package,2,0,0,0);
2655 component = MSI_RecordGetString(row, 6);
2656 comp = get_loaded_component(package,component);
2658 return ERROR_SUCCESS;
2662 TRACE("component is disabled\n");
2663 return ERROR_SUCCESS;
2666 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2668 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2669 comp->Action = comp->Installed;
2670 return ERROR_SUCCESS;
2672 comp->Action = INSTALLSTATE_LOCAL;
2674 name = MSI_RecordGetString(row, 4);
2675 if( MSI_RecordIsNull(row,5) && name )
2677 /* null values can have special meanings */
2678 if (name[0]=='-' && name[1] == 0)
2679 return ERROR_SUCCESS;
2680 else if ((name[0]=='+' && name[1] == 0) ||
2681 (name[0] == '*' && name[1] == 0))
2686 root = MSI_RecordGetInteger(row,2);
2687 key = MSI_RecordGetString(row, 3);
2689 szRoot = get_root_key( package, root, &root_key );
2691 return ERROR_SUCCESS;
2693 deformat_string(package, key , &deformated);
2694 size = strlenW(deformated) + strlenW(szRoot) + 1;
2695 uikey = msi_alloc(size*sizeof(WCHAR));
2696 strcpyW(uikey,szRoot);
2697 strcatW(uikey,deformated);
2699 keypath = get_keypath( package, root_key, deformated );
2700 msi_free( deformated );
2701 if (RegCreateKeyW( root_key, keypath, &hkey ))
2703 ERR("Could not create key %s\n", debugstr_w(keypath));
2705 return ERROR_SUCCESS;
2708 value = MSI_RecordGetString(row,5);
2710 value_data = parse_value(package, value, &type, &size);
2713 value_data = (LPSTR)strdupW(szEmpty);
2714 size = sizeof(szEmpty);
2718 deformat_string(package, name, &deformated);
2722 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2724 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2729 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2730 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2732 TRACE("value %s of %s checked already exists\n",
2733 debugstr_w(deformated), debugstr_w(uikey));
2737 TRACE("Checked and setting value %s of %s\n",
2738 debugstr_w(deformated), debugstr_w(uikey));
2739 if (deformated || size)
2740 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2745 uirow = MSI_CreateRecord(3);
2746 MSI_RecordSetStringW(uirow,2,deformated);
2747 MSI_RecordSetStringW(uirow,1,uikey);
2748 if (type == REG_SZ || type == REG_EXPAND_SZ)
2749 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2750 ui_actiondata(package,szWriteRegistryValues,uirow);
2751 msiobj_release( &uirow->hdr );
2753 msi_free(value_data);
2754 msi_free(deformated);
2757 return ERROR_SUCCESS;
2760 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2764 static const WCHAR ExecSeqQuery[] =
2765 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2766 '`','R','e','g','i','s','t','r','y','`',0 };
2768 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2769 if (rc != ERROR_SUCCESS)
2770 return ERROR_SUCCESS;
2772 /* increment progress bar each time action data is sent */
2773 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2775 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2777 msiobj_release(&view->hdr);
2781 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2785 DWORD num_subkeys, num_values;
2789 if ((res = RegDeleteTreeW( hkey_root, key )))
2791 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2796 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2798 if ((res = RegDeleteValueW( hkey, value )))
2800 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2802 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2803 NULL, NULL, NULL, NULL );
2804 RegCloseKey( hkey );
2805 if (!res && !num_subkeys && !num_values)
2807 TRACE("Removing empty key %s\n", debugstr_w(key));
2808 RegDeleteKeyW( hkey_root, key );
2812 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2816 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2818 MSIPACKAGE *package = param;
2819 LPCWSTR component, name, key_str, root_key_str;
2820 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2823 BOOL delete_key = FALSE;
2828 ui_progress( package, 2, 0, 0, 0 );
2830 component = MSI_RecordGetString( row, 6 );
2831 comp = get_loaded_component( package, component );
2833 return ERROR_SUCCESS;
2837 TRACE("component is disabled\n");
2838 return ERROR_SUCCESS;
2841 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2843 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2844 comp->Action = comp->Installed;
2845 return ERROR_SUCCESS;
2847 comp->Action = INSTALLSTATE_ABSENT;
2849 name = MSI_RecordGetString( row, 4 );
2850 if (MSI_RecordIsNull( row, 5 ) && name )
2852 if (name[0] == '+' && !name[1])
2853 return ERROR_SUCCESS;
2854 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2861 root = MSI_RecordGetInteger( row, 2 );
2862 key_str = MSI_RecordGetString( row, 3 );
2864 root_key_str = get_root_key( package, root, &hkey_root );
2866 return ERROR_SUCCESS;
2868 deformat_string( package, key_str, &deformated_key );
2869 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2870 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2871 strcpyW( ui_key_str, root_key_str );
2872 strcatW( ui_key_str, deformated_key );
2874 deformat_string( package, name, &deformated_name );
2876 keypath = get_keypath( package, hkey_root, deformated_key );
2877 msi_free( deformated_key );
2878 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2879 msi_free( keypath );
2881 uirow = MSI_CreateRecord( 2 );
2882 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2883 MSI_RecordSetStringW( uirow, 2, deformated_name );
2885 ui_actiondata( package, szRemoveRegistryValues, uirow );
2886 msiobj_release( &uirow->hdr );
2888 msi_free( ui_key_str );
2889 msi_free( deformated_name );
2890 return ERROR_SUCCESS;
2893 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2895 MSIPACKAGE *package = param;
2896 LPCWSTR component, name, key_str, root_key_str;
2897 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2900 BOOL delete_key = FALSE;
2905 ui_progress( package, 2, 0, 0, 0 );
2907 component = MSI_RecordGetString( row, 5 );
2908 comp = get_loaded_component( package, component );
2910 return ERROR_SUCCESS;
2914 TRACE("component is disabled\n");
2915 return ERROR_SUCCESS;
2918 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2920 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2921 comp->Action = comp->Installed;
2922 return ERROR_SUCCESS;
2924 comp->Action = INSTALLSTATE_LOCAL;
2926 if ((name = MSI_RecordGetString( row, 4 )))
2928 if (name[0] == '-' && !name[1])
2935 root = MSI_RecordGetInteger( row, 2 );
2936 key_str = MSI_RecordGetString( row, 3 );
2938 root_key_str = get_root_key( package, root, &hkey_root );
2940 return ERROR_SUCCESS;
2942 deformat_string( package, key_str, &deformated_key );
2943 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2944 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2945 strcpyW( ui_key_str, root_key_str );
2946 strcatW( ui_key_str, deformated_key );
2948 deformat_string( package, name, &deformated_name );
2950 keypath = get_keypath( package, hkey_root, deformated_key );
2951 msi_free( deformated_key );
2952 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2953 msi_free( keypath );
2955 uirow = MSI_CreateRecord( 2 );
2956 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2957 MSI_RecordSetStringW( uirow, 2, deformated_name );
2959 ui_actiondata( package, szRemoveRegistryValues, uirow );
2960 msiobj_release( &uirow->hdr );
2962 msi_free( ui_key_str );
2963 msi_free( deformated_name );
2964 return ERROR_SUCCESS;
2967 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2971 static const WCHAR registry_query[] =
2972 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2973 '`','R','e','g','i','s','t','r','y','`',0 };
2974 static const WCHAR remove_registry_query[] =
2975 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2976 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2978 /* increment progress bar each time action data is sent */
2979 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2981 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2982 if (rc == ERROR_SUCCESS)
2984 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2985 msiobj_release( &view->hdr );
2986 if (rc != ERROR_SUCCESS)
2990 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2991 if (rc == ERROR_SUCCESS)
2993 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2994 msiobj_release( &view->hdr );
2995 if (rc != ERROR_SUCCESS)
2999 return ERROR_SUCCESS;
3002 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3004 package->script->CurrentlyScripting = TRUE;
3006 return ERROR_SUCCESS;
3010 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3015 static const WCHAR q1[]=
3016 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3017 '`','R','e','g','i','s','t','r','y','`',0};
3020 MSIFEATURE *feature;
3023 TRACE("InstallValidate\n");
3025 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3026 if (rc == ERROR_SUCCESS)
3028 MSI_IterateRecords( view, &progress, NULL, package );
3029 msiobj_release( &view->hdr );
3030 total += progress * REG_PROGRESS_VALUE;
3033 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3034 total += COMPONENT_PROGRESS_VALUE;
3036 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3037 total += file->FileSize;
3039 ui_progress(package,0,total,0,0);
3041 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3043 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3044 debugstr_w(feature->Feature), feature->Installed,
3045 feature->ActionRequest, feature->Action);
3048 return ERROR_SUCCESS;
3051 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3053 MSIPACKAGE* package = param;
3054 LPCWSTR cond = NULL;
3055 LPCWSTR message = NULL;
3058 static const WCHAR title[]=
3059 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3061 cond = MSI_RecordGetString(row,1);
3063 r = MSI_EvaluateConditionW(package,cond);
3064 if (r == MSICONDITION_FALSE)
3066 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3069 message = MSI_RecordGetString(row,2);
3070 deformat_string(package,message,&deformated);
3071 MessageBoxW(NULL,deformated,title,MB_OK);
3072 msi_free(deformated);
3075 return ERROR_INSTALL_FAILURE;
3078 return ERROR_SUCCESS;
3081 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3084 MSIQUERY * view = NULL;
3085 static const WCHAR ExecSeqQuery[] =
3086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3087 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3089 TRACE("Checking launch conditions\n");
3091 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3092 if (rc != ERROR_SUCCESS)
3093 return ERROR_SUCCESS;
3095 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3096 msiobj_release(&view->hdr);
3101 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3105 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
3107 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3109 MSIRECORD * row = 0;
3111 LPWSTR deformated,buffer,deformated_name;
3113 static const WCHAR ExecSeqQuery[] =
3114 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3115 '`','R','e','g','i','s','t','r','y','`',' ',
3116 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3117 ' ','=',' ' ,'\'','%','s','\'',0 };
3118 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3119 static const WCHAR fmt2[]=
3120 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3122 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3126 root = MSI_RecordGetInteger(row,2);
3127 key = MSI_RecordGetString(row, 3);
3128 name = MSI_RecordGetString(row, 4);
3129 deformat_string(package, key , &deformated);
3130 deformat_string(package, name, &deformated_name);
3132 len = strlenW(deformated) + 6;
3133 if (deformated_name)
3134 len+=strlenW(deformated_name);
3136 buffer = msi_alloc( len *sizeof(WCHAR));
3138 if (deformated_name)
3139 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3141 sprintfW(buffer,fmt,root,deformated);
3143 msi_free(deformated);
3144 msi_free(deformated_name);
3145 msiobj_release(&row->hdr);
3149 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3151 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3156 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3159 return strdupW( file->TargetPath );
3164 static HKEY openSharedDLLsKey(void)
3167 static const WCHAR path[] =
3168 {'S','o','f','t','w','a','r','e','\\',
3169 'M','i','c','r','o','s','o','f','t','\\',
3170 'W','i','n','d','o','w','s','\\',
3171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3172 'S','h','a','r','e','d','D','L','L','s',0};
3174 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3178 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3183 DWORD sz = sizeof(count);
3186 hkey = openSharedDLLsKey();
3187 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3188 if (rc != ERROR_SUCCESS)
3194 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3198 hkey = openSharedDLLsKey();
3200 msi_reg_set_val_dword( hkey, path, count );
3202 RegDeleteValueW(hkey,path);
3208 * Return TRUE if the count should be written out and FALSE if not
3210 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3212 MSIFEATURE *feature;
3216 /* only refcount DLLs */
3217 if (comp->KeyPath == NULL ||
3218 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3219 comp->Attributes & msidbComponentAttributesODBCDataSource)
3223 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3224 write = (count > 0);
3226 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3230 /* increment counts */
3231 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3235 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3238 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3240 if ( cl->component == comp )
3245 /* decrement counts */
3246 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3250 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3253 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3255 if ( cl->component == comp )
3260 /* ref count all the files in the component */
3265 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3267 if (file->Component == comp)
3268 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3272 /* add a count for permanent */
3273 if (comp->Attributes & msidbComponentAttributesPermanent)
3276 comp->RefCount = count;
3279 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3282 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3284 WCHAR squished_pc[GUID_SIZE];
3285 WCHAR squished_cc[GUID_SIZE];
3292 squash_guid(package->ProductCode,squished_pc);
3293 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3295 msi_set_sourcedir_props(package, FALSE);
3297 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3301 ui_progress(package,2,0,0,0);
3302 if (!comp->ComponentId)
3305 squash_guid(comp->ComponentId,squished_cc);
3307 msi_free(comp->FullKeypath);
3308 comp->FullKeypath = resolve_keypath( package, comp );
3310 ACTION_RefCountComponent( package, comp );
3312 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3313 debugstr_w(comp->Component),
3314 debugstr_w(squished_cc),
3315 debugstr_w(comp->FullKeypath),
3317 comp->ActionRequest);
3319 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3320 comp->ActionRequest == INSTALLSTATE_SOURCE)
3322 if (!comp->FullKeypath)
3325 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3326 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3329 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3332 if (rc != ERROR_SUCCESS)
3335 if (comp->Attributes & msidbComponentAttributesPermanent)
3337 static const WCHAR szPermKey[] =
3338 { '0','0','0','0','0','0','0','0','0','0','0','0',
3339 '0','0','0','0','0','0','0','0','0','0','0','0',
3340 '0','0','0','0','0','0','0','0',0 };
3342 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3345 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3346 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3352 WCHAR source[MAX_PATH];
3353 WCHAR base[MAX_PATH];
3356 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3357 static const WCHAR query[] = {
3358 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3359 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3360 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3361 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3362 '`','D','i','s','k','I','d','`',0};
3364 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3367 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3368 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3369 ptr2 = strrchrW(source, '\\') + 1;
3370 msiobj_release(&row->hdr);
3372 lstrcpyW(base, package->PackagePath);
3373 ptr = strrchrW(base, '\\');
3376 sourcepath = resolve_file_source(package, file);
3377 ptr = sourcepath + lstrlenW(base);
3378 lstrcpyW(ptr2, ptr);
3379 msi_free(sourcepath);
3381 msi_reg_set_val_str(hkey, squished_pc, source);
3385 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3387 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3388 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3390 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3392 comp->Action = comp->ActionRequest;
3395 uirow = MSI_CreateRecord(3);
3396 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3397 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3398 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3399 ui_actiondata(package,szProcessComponents,uirow);
3400 msiobj_release( &uirow->hdr );
3403 return ERROR_SUCCESS;
3414 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3415 LPWSTR lpszName, LONG_PTR lParam)
3418 typelib_struct *tl_struct = (typelib_struct*) lParam;
3419 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3423 if (!IS_INTRESOURCE(lpszName))
3425 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3429 sz = strlenW(tl_struct->source)+4;
3430 sz *= sizeof(WCHAR);
3432 if ((INT_PTR)lpszName == 1)
3433 tl_struct->path = strdupW(tl_struct->source);
3436 tl_struct->path = msi_alloc(sz);
3437 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3440 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3441 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3444 msi_free(tl_struct->path);
3445 tl_struct->path = NULL;
3450 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3451 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3453 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3457 msi_free(tl_struct->path);
3458 tl_struct->path = NULL;
3460 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3461 ITypeLib_Release(tl_struct->ptLib);
3466 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3468 MSIPACKAGE* package = param;
3472 typelib_struct tl_struct;
3477 component = MSI_RecordGetString(row,3);
3478 comp = get_loaded_component(package,component);
3480 return ERROR_SUCCESS;
3484 TRACE("component is disabled\n");
3485 return ERROR_SUCCESS;
3488 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3490 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3491 comp->Action = comp->Installed;
3492 return ERROR_SUCCESS;
3494 comp->Action = INSTALLSTATE_LOCAL;
3496 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3498 TRACE("component has no key path\n");
3499 return ERROR_SUCCESS;
3501 ui_actiondata( package, szRegisterTypeLibraries, row );
3503 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3507 guid = MSI_RecordGetString(row,1);
3508 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3509 tl_struct.source = strdupW( file->TargetPath );
3510 tl_struct.path = NULL;
3512 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3513 (LONG_PTR)&tl_struct);
3521 helpid = MSI_RecordGetString(row,6);
3524 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3525 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3529 ERR("Failed to register type library %s\n",
3530 debugstr_w(tl_struct.path));
3532 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3534 ITypeLib_Release(tl_struct.ptLib);
3535 msi_free(tl_struct.path);
3538 ERR("Failed to load type library %s\n",
3539 debugstr_w(tl_struct.source));
3541 FreeLibrary(module);
3542 msi_free(tl_struct.source);
3546 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3549 ERR("Failed to load type library: %08x\n", hr);
3550 return ERROR_INSTALL_FAILURE;
3553 ITypeLib_Release(tlib);
3556 return ERROR_SUCCESS;
3559 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3562 * OK this is a bit confusing.. I am given a _Component key and I believe
3563 * that the file that is being registered as a type library is the "key file
3564 * of that component" which I interpret to mean "The file in the KeyPath of
3569 static const WCHAR Query[] =
3570 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3571 '`','T','y','p','e','L','i','b','`',0};
3573 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3574 if (rc != ERROR_SUCCESS)
3575 return ERROR_SUCCESS;
3577 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3578 msiobj_release(&view->hdr);
3582 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3584 MSIPACKAGE *package = param;
3585 LPCWSTR component, guid;
3593 component = MSI_RecordGetString( row, 3 );
3594 comp = get_loaded_component( package, component );
3596 return ERROR_SUCCESS;
3600 TRACE("component is disabled\n");
3601 return ERROR_SUCCESS;
3604 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3606 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3607 comp->Action = comp->Installed;
3608 return ERROR_SUCCESS;
3610 comp->Action = INSTALLSTATE_ABSENT;
3612 ui_actiondata( package, szUnregisterTypeLibraries, row );
3614 guid = MSI_RecordGetString( row, 1 );
3615 CLSIDFromString( (LPCWSTR)guid, &libid );
3616 version = MSI_RecordGetInteger( row, 4 );
3617 language = MSI_RecordGetInteger( row, 2 );
3620 syskind = SYS_WIN64;
3622 syskind = SYS_WIN32;
3625 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3628 WARN("Failed to unregister typelib: %08x\n", hr);
3631 return ERROR_SUCCESS;
3634 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3638 static const WCHAR query[] =
3639 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3640 '`','T','y','p','e','L','i','b','`',0};
3642 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3643 if (rc != ERROR_SUCCESS)
3644 return ERROR_SUCCESS;
3646 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3647 msiobj_release( &view->hdr );
3651 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3653 static const WCHAR szlnk[] = {'.','l','n','k',0};
3654 LPCWSTR directory, extension;
3655 LPWSTR link_folder, link_file, filename;
3657 directory = MSI_RecordGetString( row, 2 );
3658 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3660 /* may be needed because of a bug somewhere else */
3661 create_full_pathW( link_folder );
3663 filename = msi_dup_record_field( row, 3 );
3664 reduce_to_longfilename( filename );
3666 extension = strchrW( filename, '.' );
3667 if (!extension || strcmpiW( extension, szlnk ))
3669 int len = strlenW( filename );
3670 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3671 memcpy( filename + len, szlnk, sizeof(szlnk) );
3673 link_file = build_directory_name( 2, link_folder, filename );
3674 msi_free( link_folder );
3675 msi_free( filename );
3680 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3682 MSIPACKAGE *package = param;
3683 LPWSTR link_file, deformated, path;
3684 LPCWSTR component, target;
3686 IShellLinkW *sl = NULL;
3687 IPersistFile *pf = NULL;
3690 component = MSI_RecordGetString(row, 4);
3691 comp = get_loaded_component(package, component);
3693 return ERROR_SUCCESS;
3697 TRACE("component is disabled\n");
3698 return ERROR_SUCCESS;
3701 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3703 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3704 comp->Action = comp->Installed;
3705 return ERROR_SUCCESS;
3707 comp->Action = INSTALLSTATE_LOCAL;
3709 ui_actiondata(package,szCreateShortcuts,row);
3711 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3712 &IID_IShellLinkW, (LPVOID *) &sl );
3716 ERR("CLSID_ShellLink not available\n");
3720 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3723 ERR("QueryInterface(IID_IPersistFile) failed\n");
3727 target = MSI_RecordGetString(row, 5);
3728 if (strchrW(target, '['))
3730 deformat_string(package, target, &deformated);
3731 IShellLinkW_SetPath(sl,deformated);
3732 msi_free(deformated);
3736 FIXME("poorly handled shortcut format, advertised shortcut\n");
3737 IShellLinkW_SetPath(sl,comp->FullKeypath);
3740 if (!MSI_RecordIsNull(row,6))
3742 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3743 deformat_string(package, arguments, &deformated);
3744 IShellLinkW_SetArguments(sl,deformated);
3745 msi_free(deformated);
3748 if (!MSI_RecordIsNull(row,7))
3750 LPCWSTR description = MSI_RecordGetString(row, 7);
3751 IShellLinkW_SetDescription(sl, description);
3754 if (!MSI_RecordIsNull(row,8))
3755 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3757 if (!MSI_RecordIsNull(row,9))
3760 LPCWSTR icon = MSI_RecordGetString(row, 9);
3762 path = build_icon_path(package, icon);
3763 index = MSI_RecordGetInteger(row,10);
3765 /* no value means 0 */
3766 if (index == MSI_NULL_INTEGER)
3769 IShellLinkW_SetIconLocation(sl, path, index);
3773 if (!MSI_RecordIsNull(row,11))
3774 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3776 if (!MSI_RecordIsNull(row,12))
3778 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3779 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3781 IShellLinkW_SetWorkingDirectory(sl, path);
3785 link_file = get_link_file(package, row);
3787 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3788 IPersistFile_Save(pf, link_file, FALSE);
3790 msi_free(link_file);
3794 IPersistFile_Release( pf );
3796 IShellLinkW_Release( sl );
3798 return ERROR_SUCCESS;
3801 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3806 static const WCHAR Query[] =
3807 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3808 '`','S','h','o','r','t','c','u','t','`',0};
3810 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3811 if (rc != ERROR_SUCCESS)
3812 return ERROR_SUCCESS;
3814 res = CoInitialize( NULL );
3816 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3817 msiobj_release(&view->hdr);
3825 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3827 MSIPACKAGE *package = param;
3832 component = MSI_RecordGetString( row, 4 );
3833 comp = get_loaded_component( package, component );
3835 return ERROR_SUCCESS;
3839 TRACE("component is disabled\n");
3840 return ERROR_SUCCESS;
3843 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3845 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3846 comp->Action = comp->Installed;
3847 return ERROR_SUCCESS;
3849 comp->Action = INSTALLSTATE_ABSENT;
3851 ui_actiondata( package, szRemoveShortcuts, row );
3853 link_file = get_link_file( package, row );
3855 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3856 if (!DeleteFileW( link_file ))
3858 WARN("Failed to remove shortcut file %u\n", GetLastError());
3860 msi_free( link_file );
3862 return ERROR_SUCCESS;
3865 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3869 static const WCHAR query[] =
3870 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3871 '`','S','h','o','r','t','c','u','t','`',0};
3873 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3874 if (rc != ERROR_SUCCESS)
3875 return ERROR_SUCCESS;
3877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3878 msiobj_release( &view->hdr );
3883 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3885 MSIPACKAGE* package = param;
3893 FileName = MSI_RecordGetString(row,1);
3896 ERR("Unable to get FileName\n");
3897 return ERROR_SUCCESS;
3900 FilePath = build_icon_path(package,FileName);
3902 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3904 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3905 FILE_ATTRIBUTE_NORMAL, NULL);
3907 if (the_file == INVALID_HANDLE_VALUE)
3909 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3911 return ERROR_SUCCESS;
3918 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3919 if (rc != ERROR_SUCCESS)
3921 ERR("Failed to get stream\n");
3922 CloseHandle(the_file);
3923 DeleteFileW(FilePath);
3926 WriteFile(the_file,buffer,sz,&write,NULL);
3927 } while (sz == 1024);
3930 CloseHandle(the_file);
3932 return ERROR_SUCCESS;
3935 static UINT msi_publish_icons(MSIPACKAGE *package)
3940 static const WCHAR query[]= {
3941 'S','E','L','E','C','T',' ','*',' ',
3942 'F','R','O','M',' ','`','I','c','o','n','`',0};
3944 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3945 if (r == ERROR_SUCCESS)
3947 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3948 msiobj_release(&view->hdr);
3951 return ERROR_SUCCESS;
3954 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3960 MSISOURCELISTINFO *info;
3962 r = RegCreateKeyW(hkey, szSourceList, &source);
3963 if (r != ERROR_SUCCESS)
3966 RegCloseKey(source);
3968 buffer = strrchrW(package->PackagePath, '\\') + 1;
3969 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3970 package->Context, MSICODE_PRODUCT,
3971 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3972 if (r != ERROR_SUCCESS)
3975 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3976 package->Context, MSICODE_PRODUCT,
3977 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3978 if (r != ERROR_SUCCESS)
3981 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3982 package->Context, MSICODE_PRODUCT,
3983 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3984 if (r != ERROR_SUCCESS)
3987 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3989 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3990 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3991 info->options, info->value);
3993 MsiSourceListSetInfoW(package->ProductCode, NULL,
3994 info->context, info->options,
3995 info->property, info->value);
3998 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4000 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4001 disk->context, disk->options,
4002 disk->disk_id, disk->volume_label, disk->disk_prompt);
4005 return ERROR_SUCCESS;
4008 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4010 MSIHANDLE hdb, suminfo;
4011 WCHAR guids[MAX_PATH];
4012 WCHAR packcode[SQUISH_GUID_SIZE];
4019 static const WCHAR szProductLanguage[] =
4020 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4021 static const WCHAR szARPProductIcon[] =
4022 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4023 static const WCHAR szProductVersion[] =
4024 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4025 static const WCHAR szAssignment[] =
4026 {'A','s','s','i','g','n','m','e','n','t',0};
4027 static const WCHAR szAdvertiseFlags[] =
4028 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4029 static const WCHAR szClients[] =
4030 {'C','l','i','e','n','t','s',0};
4031 static const WCHAR szColon[] = {':',0};
4033 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4034 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4037 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4038 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4041 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4043 buffer = msi_dup_property(package->db, szARPProductIcon);
4046 LPWSTR path = build_icon_path(package,buffer);
4047 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4052 buffer = msi_dup_property(package->db, szProductVersion);
4055 DWORD verdword = msi_version_str_to_dword(buffer);
4056 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4060 msi_reg_set_val_dword(hkey, szAssignment, 0);
4061 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4062 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4063 msi_reg_set_val_str(hkey, szClients, szColon);
4065 hdb = alloc_msihandle(&package->db->hdr);
4067 return ERROR_NOT_ENOUGH_MEMORY;
4069 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4070 MsiCloseHandle(hdb);
4071 if (r != ERROR_SUCCESS)
4075 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4076 NULL, guids, &size);
4077 if (r != ERROR_SUCCESS)
4080 ptr = strchrW(guids, ';');
4082 squash_guid(guids, packcode);
4083 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4086 MsiCloseHandle(suminfo);
4087 return ERROR_SUCCESS;
4090 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4095 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4097 upgrade = msi_dup_property(package->db, szUpgradeCode);
4099 return ERROR_SUCCESS;
4101 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4103 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4104 if (r != ERROR_SUCCESS)
4109 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4110 if (r != ERROR_SUCCESS)
4114 squash_guid(package->ProductCode, squashed_pc);
4115 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4124 static BOOL msi_check_publish(MSIPACKAGE *package)
4126 MSIFEATURE *feature;
4128 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4130 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4137 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4139 MSIFEATURE *feature;
4141 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4143 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4150 static UINT msi_publish_patches( MSIPACKAGE *package )
4152 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4153 WCHAR patch_squashed[GUID_SIZE];
4154 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4156 MSIPATCHINFO *patch;
4158 WCHAR *p, *all_patches = NULL;
4161 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4162 if (r != ERROR_SUCCESS)
4163 return ERROR_FUNCTION_FAILED;
4165 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4166 if (res != ERROR_SUCCESS)
4168 r = ERROR_FUNCTION_FAILED;
4172 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4173 if (r != ERROR_SUCCESS)
4176 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4178 squash_guid( patch->patchcode, patch_squashed );
4179 len += strlenW( patch_squashed ) + 1;
4182 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4186 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4190 squash_guid( patch->patchcode, p );
4191 p += strlenW( p ) + 1;
4193 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4194 (const BYTE *)patch->transforms,
4195 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4196 if (res != ERROR_SUCCESS)
4199 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4200 if (r != ERROR_SUCCESS)
4203 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4204 (const BYTE *)patch->localfile,
4205 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4206 RegCloseKey( patch_key );
4207 if (res != ERROR_SUCCESS)
4210 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4211 if (res != ERROR_SUCCESS)
4214 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4215 RegCloseKey( patch_key );
4216 if (res != ERROR_SUCCESS)
4220 all_patches[len] = 0;
4221 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4222 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4223 if (res != ERROR_SUCCESS)
4226 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4227 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4228 if (res != ERROR_SUCCESS)
4229 r = ERROR_FUNCTION_FAILED;
4232 RegCloseKey( product_patches_key );
4233 RegCloseKey( patches_key );
4234 RegCloseKey( product_key );
4235 msi_free( all_patches );
4240 * 99% of the work done here is only done for
4241 * advertised installs. However this is where the
4242 * Icon table is processed and written out
4243 * so that is what I am going to do here.
4245 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4248 HKEY hukey = NULL, hudkey = NULL;
4251 if (!list_empty(&package->patches))
4253 rc = msi_publish_patches(package);
4254 if (rc != ERROR_SUCCESS)
4258 /* FIXME: also need to publish if the product is in advertise mode */
4259 if (!msi_check_publish(package))
4260 return ERROR_SUCCESS;
4262 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4264 if (rc != ERROR_SUCCESS)
4267 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4268 NULL, &hudkey, TRUE);
4269 if (rc != ERROR_SUCCESS)
4272 rc = msi_publish_upgrade_code(package);
4273 if (rc != ERROR_SUCCESS)
4276 rc = msi_publish_product_properties(package, hukey);
4277 if (rc != ERROR_SUCCESS)
4280 rc = msi_publish_sourcelist(package, hukey);
4281 if (rc != ERROR_SUCCESS)
4284 rc = msi_publish_icons(package);
4287 uirow = MSI_CreateRecord( 1 );
4288 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4289 ui_actiondata( package, szPublishProduct, uirow );
4290 msiobj_release( &uirow->hdr );
4293 RegCloseKey(hudkey);
4298 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4300 WCHAR *filename, *ptr, *folder, *ret;
4301 const WCHAR *dirprop;
4303 filename = msi_dup_record_field( row, 2 );
4304 if (filename && (ptr = strchrW( filename, '|' )))
4309 dirprop = MSI_RecordGetString( row, 3 );
4312 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4314 folder = msi_dup_property( package->db, dirprop );
4317 folder = msi_dup_property( package->db, szWindowsFolder );
4321 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4322 msi_free( filename );
4326 ret = build_directory_name( 2, folder, ptr );
4328 msi_free( filename );
4333 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4335 MSIPACKAGE *package = param;
4336 LPCWSTR component, section, key, value, identifier;
4337 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4342 component = MSI_RecordGetString(row, 8);
4343 comp = get_loaded_component(package,component);
4345 return ERROR_SUCCESS;
4349 TRACE("component is disabled\n");
4350 return ERROR_SUCCESS;
4353 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4355 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4356 comp->Action = comp->Installed;
4357 return ERROR_SUCCESS;
4359 comp->Action = INSTALLSTATE_LOCAL;
4361 identifier = MSI_RecordGetString(row,1);
4362 section = MSI_RecordGetString(row,4);
4363 key = MSI_RecordGetString(row,5);
4364 value = MSI_RecordGetString(row,6);
4365 action = MSI_RecordGetInteger(row,7);
4367 deformat_string(package,section,&deformated_section);
4368 deformat_string(package,key,&deformated_key);
4369 deformat_string(package,value,&deformated_value);
4371 fullname = get_ini_file_name(package, row);
4375 TRACE("Adding value %s to section %s in %s\n",
4376 debugstr_w(deformated_key), debugstr_w(deformated_section),
4377 debugstr_w(fullname));
4378 WritePrivateProfileStringW(deformated_section, deformated_key,
4379 deformated_value, fullname);
4381 else if (action == 1)
4384 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4385 returned, 10, fullname);
4386 if (returned[0] == 0)
4388 TRACE("Adding value %s to section %s in %s\n",
4389 debugstr_w(deformated_key), debugstr_w(deformated_section),
4390 debugstr_w(fullname));
4392 WritePrivateProfileStringW(deformated_section, deformated_key,
4393 deformated_value, fullname);
4396 else if (action == 3)
4397 FIXME("Append to existing section not yet implemented\n");
4399 uirow = MSI_CreateRecord(4);
4400 MSI_RecordSetStringW(uirow,1,identifier);
4401 MSI_RecordSetStringW(uirow,2,deformated_section);
4402 MSI_RecordSetStringW(uirow,3,deformated_key);
4403 MSI_RecordSetStringW(uirow,4,deformated_value);
4404 ui_actiondata(package,szWriteIniValues,uirow);
4405 msiobj_release( &uirow->hdr );
4408 msi_free(deformated_key);
4409 msi_free(deformated_value);
4410 msi_free(deformated_section);
4411 return ERROR_SUCCESS;
4414 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4418 static const WCHAR ExecSeqQuery[] =
4419 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4420 '`','I','n','i','F','i','l','e','`',0};
4422 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4423 if (rc != ERROR_SUCCESS)
4425 TRACE("no IniFile table\n");
4426 return ERROR_SUCCESS;
4429 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4430 msiobj_release(&view->hdr);
4434 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4436 MSIPACKAGE *package = param;
4437 LPCWSTR component, section, key, value, identifier;
4438 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4443 component = MSI_RecordGetString( row, 8 );
4444 comp = get_loaded_component( package, component );
4446 return ERROR_SUCCESS;
4450 TRACE("component is disabled\n");
4451 return ERROR_SUCCESS;
4454 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4456 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4457 comp->Action = comp->Installed;
4458 return ERROR_SUCCESS;
4460 comp->Action = INSTALLSTATE_ABSENT;
4462 identifier = MSI_RecordGetString( row, 1 );
4463 section = MSI_RecordGetString( row, 4 );
4464 key = MSI_RecordGetString( row, 5 );
4465 value = MSI_RecordGetString( row, 6 );
4466 action = MSI_RecordGetInteger( row, 7 );
4468 deformat_string( package, section, &deformated_section );
4469 deformat_string( package, key, &deformated_key );
4470 deformat_string( package, value, &deformated_value );
4472 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4474 filename = get_ini_file_name( package, row );
4476 TRACE("Removing key %s from section %s in %s\n",
4477 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4479 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4481 WARN("Unable to remove key %u\n", GetLastError());
4483 msi_free( filename );
4486 FIXME("Unsupported action %d\n", action);
4489 uirow = MSI_CreateRecord( 4 );
4490 MSI_RecordSetStringW( uirow, 1, identifier );
4491 MSI_RecordSetStringW( uirow, 2, deformated_section );
4492 MSI_RecordSetStringW( uirow, 3, deformated_key );
4493 MSI_RecordSetStringW( uirow, 4, deformated_value );
4494 ui_actiondata( package, szRemoveIniValues, uirow );
4495 msiobj_release( &uirow->hdr );
4497 msi_free( deformated_key );
4498 msi_free( deformated_value );
4499 msi_free( deformated_section );
4500 return ERROR_SUCCESS;
4503 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4505 MSIPACKAGE *package = param;
4506 LPCWSTR component, section, key, value, identifier;
4507 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4512 component = MSI_RecordGetString( row, 8 );
4513 comp = get_loaded_component( package, component );
4515 return ERROR_SUCCESS;
4519 TRACE("component is disabled\n");
4520 return ERROR_SUCCESS;
4523 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4525 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4526 comp->Action = comp->Installed;
4527 return ERROR_SUCCESS;
4529 comp->Action = INSTALLSTATE_LOCAL;
4531 identifier = MSI_RecordGetString( row, 1 );
4532 section = MSI_RecordGetString( row, 4 );
4533 key = MSI_RecordGetString( row, 5 );
4534 value = MSI_RecordGetString( row, 6 );
4535 action = MSI_RecordGetInteger( row, 7 );
4537 deformat_string( package, section, &deformated_section );
4538 deformat_string( package, key, &deformated_key );
4539 deformat_string( package, value, &deformated_value );
4541 if (action == msidbIniFileActionRemoveLine)
4543 filename = get_ini_file_name( package, row );
4545 TRACE("Removing key %s from section %s in %s\n",
4546 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4548 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4550 WARN("Unable to remove key %u\n", GetLastError());
4552 msi_free( filename );
4555 FIXME("Unsupported action %d\n", action);
4557 uirow = MSI_CreateRecord( 4 );
4558 MSI_RecordSetStringW( uirow, 1, identifier );
4559 MSI_RecordSetStringW( uirow, 2, deformated_section );
4560 MSI_RecordSetStringW( uirow, 3, deformated_key );
4561 MSI_RecordSetStringW( uirow, 4, deformated_value );
4562 ui_actiondata( package, szRemoveIniValues, uirow );
4563 msiobj_release( &uirow->hdr );
4565 msi_free( deformated_key );
4566 msi_free( deformated_value );
4567 msi_free( deformated_section );
4568 return ERROR_SUCCESS;
4571 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4575 static const WCHAR query[] =
4576 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4577 '`','I','n','i','F','i','l','e','`',0};
4578 static const WCHAR remove_query[] =
4579 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4580 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4582 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4583 if (rc == ERROR_SUCCESS)
4585 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4586 msiobj_release( &view->hdr );
4587 if (rc != ERROR_SUCCESS)
4591 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4592 if (rc == ERROR_SUCCESS)
4594 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4595 msiobj_release( &view->hdr );
4596 if (rc != ERROR_SUCCESS)
4600 return ERROR_SUCCESS;
4603 static void register_dll( const WCHAR *dll, BOOL unregister )
4607 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4610 HRESULT (WINAPI *func_ptr)( void );
4611 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4613 func_ptr = (void *)GetProcAddress( hmod, func );
4616 HRESULT hr = func_ptr();
4618 WARN("failed to register dll 0x%08x\n", hr);
4621 WARN("entry point %s not found\n", func);
4622 FreeLibrary( hmod );
4625 WARN("failed to load library %u\n", GetLastError());
4628 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4630 MSIPACKAGE *package = param;
4635 filename = MSI_RecordGetString(row,1);
4636 file = get_loaded_file( package, filename );
4640 ERR("Unable to find file id %s\n",debugstr_w(filename));
4641 return ERROR_SUCCESS;
4644 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4646 register_dll( file->TargetPath, FALSE );
4648 uirow = MSI_CreateRecord( 2 );
4649 MSI_RecordSetStringW( uirow, 1, filename );
4650 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4651 ui_actiondata( package, szSelfRegModules, uirow );
4652 msiobj_release( &uirow->hdr );
4654 return ERROR_SUCCESS;
4657 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4661 static const WCHAR ExecSeqQuery[] =
4662 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4663 '`','S','e','l','f','R','e','g','`',0};
4665 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4666 if (rc != ERROR_SUCCESS)
4668 TRACE("no SelfReg table\n");
4669 return ERROR_SUCCESS;
4672 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4673 msiobj_release(&view->hdr);
4675 return ERROR_SUCCESS;
4678 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4680 MSIPACKAGE *package = param;
4685 filename = MSI_RecordGetString( row, 1 );
4686 file = get_loaded_file( package, filename );
4690 ERR("Unable to find file id %s\n", debugstr_w(filename));
4691 return ERROR_SUCCESS;
4694 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4696 register_dll( file->TargetPath, TRUE );
4698 uirow = MSI_CreateRecord( 2 );
4699 MSI_RecordSetStringW( uirow, 1, filename );
4700 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4701 ui_actiondata( package, szSelfUnregModules, uirow );
4702 msiobj_release( &uirow->hdr );
4704 return ERROR_SUCCESS;
4707 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4711 static const WCHAR query[] =
4712 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4713 '`','S','e','l','f','R','e','g','`',0};
4715 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4716 if (rc != ERROR_SUCCESS)
4718 TRACE("no SelfReg table\n");
4719 return ERROR_SUCCESS;
4722 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4723 msiobj_release( &view->hdr );
4725 return ERROR_SUCCESS;
4728 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4730 MSIFEATURE *feature;
4732 HKEY hkey = NULL, userdata = NULL;
4734 if (!msi_check_publish(package))
4735 return ERROR_SUCCESS;
4737 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4739 if (rc != ERROR_SUCCESS)
4742 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4744 if (rc != ERROR_SUCCESS)
4747 /* here the guids are base 85 encoded */
4748 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4754 BOOL absent = FALSE;
4757 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4758 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4759 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4762 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4766 if (feature->Feature_Parent)
4767 size += strlenW( feature->Feature_Parent )+2;
4769 data = msi_alloc(size * sizeof(WCHAR));
4772 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4774 MSICOMPONENT* component = cl->component;
4778 if (component->ComponentId)
4780 TRACE("From %s\n",debugstr_w(component->ComponentId));
4781 CLSIDFromString(component->ComponentId, &clsid);
4782 encode_base85_guid(&clsid,buf);
4783 TRACE("to %s\n",debugstr_w(buf));
4788 if (feature->Feature_Parent)
4790 static const WCHAR sep[] = {'\2',0};
4792 strcatW(data,feature->Feature_Parent);
4795 msi_reg_set_val_str( userdata, feature->Feature, data );
4799 if (feature->Feature_Parent)
4800 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4803 size += sizeof(WCHAR);
4804 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4805 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4809 size += 2*sizeof(WCHAR);
4810 data = msi_alloc(size);
4813 if (feature->Feature_Parent)
4814 strcpyW( &data[1], feature->Feature_Parent );
4815 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4821 uirow = MSI_CreateRecord( 1 );
4822 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4823 ui_actiondata( package, szPublishFeatures, uirow);
4824 msiobj_release( &uirow->hdr );
4825 /* FIXME: call ui_progress? */
4830 RegCloseKey(userdata);
4834 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4840 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4842 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4844 if (r == ERROR_SUCCESS)
4846 RegDeleteValueW(hkey, feature->Feature);
4850 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4852 if (r == ERROR_SUCCESS)
4854 RegDeleteValueW(hkey, feature->Feature);
4858 uirow = MSI_CreateRecord( 1 );
4859 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4860 ui_actiondata( package, szUnpublishFeatures, uirow );
4861 msiobj_release( &uirow->hdr );
4863 return ERROR_SUCCESS;
4866 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4868 MSIFEATURE *feature;
4870 if (!msi_check_unpublish(package))
4871 return ERROR_SUCCESS;
4873 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4875 msi_unpublish_feature(package, feature);
4878 return ERROR_SUCCESS;
4881 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4885 WCHAR date[9], *val, *buffer;
4886 const WCHAR *prop, *key;
4888 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4889 static const WCHAR szWindowsInstaller[] =
4890 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4891 static const WCHAR modpath_fmt[] =
4892 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4893 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4894 static const WCHAR szModifyPath[] =
4895 {'M','o','d','i','f','y','P','a','t','h',0};
4896 static const WCHAR szUninstallString[] =
4897 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4898 static const WCHAR szEstimatedSize[] =
4899 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4900 static const WCHAR szProductLanguage[] =
4901 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4902 static const WCHAR szProductVersion[] =
4903 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4904 static const WCHAR szDisplayVersion[] =
4905 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4906 static const WCHAR szInstallSource[] =
4907 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4908 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4909 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4910 static const WCHAR szAuthorizedCDFPrefix[] =
4911 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4912 static const WCHAR szARPCONTACT[] =
4913 {'A','R','P','C','O','N','T','A','C','T',0};
4914 static const WCHAR szContact[] =
4915 {'C','o','n','t','a','c','t',0};
4916 static const WCHAR szARPCOMMENTS[] =
4917 {'A','R','P','C','O','M','M','E','N','T','S',0};
4918 static const WCHAR szComments[] =
4919 {'C','o','m','m','e','n','t','s',0};
4920 static const WCHAR szProductName[] =
4921 {'P','r','o','d','u','c','t','N','a','m','e',0};
4922 static const WCHAR szDisplayName[] =
4923 {'D','i','s','p','l','a','y','N','a','m','e',0};
4924 static const WCHAR szARPHELPLINK[] =
4925 {'A','R','P','H','E','L','P','L','I','N','K',0};
4926 static const WCHAR szHelpLink[] =
4927 {'H','e','l','p','L','i','n','k',0};
4928 static const WCHAR szARPHELPTELEPHONE[] =
4929 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4930 static const WCHAR szHelpTelephone[] =
4931 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4932 static const WCHAR szARPINSTALLLOCATION[] =
4933 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4934 static const WCHAR szInstallLocation[] =
4935 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4936 static const WCHAR szManufacturer[] =
4937 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4938 static const WCHAR szPublisher[] =
4939 {'P','u','b','l','i','s','h','e','r',0};
4940 static const WCHAR szARPREADME[] =
4941 {'A','R','P','R','E','A','D','M','E',0};
4942 static const WCHAR szReadme[] =
4943 {'R','e','a','d','M','e',0};
4944 static const WCHAR szARPSIZE[] =
4945 {'A','R','P','S','I','Z','E',0};
4946 static const WCHAR szSize[] =
4947 {'S','i','z','e',0};
4948 static const WCHAR szARPURLINFOABOUT[] =
4949 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4950 static const WCHAR szURLInfoAbout[] =
4951 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4952 static const WCHAR szARPURLUPDATEINFO[] =
4953 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4954 static const WCHAR szURLUpdateInfo[] =
4955 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4957 static const WCHAR *propval[] = {
4958 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4959 szARPCONTACT, szContact,
4960 szARPCOMMENTS, szComments,
4961 szProductName, szDisplayName,
4962 szARPHELPLINK, szHelpLink,
4963 szARPHELPTELEPHONE, szHelpTelephone,
4964 szARPINSTALLLOCATION, szInstallLocation,
4965 cszSourceDir, szInstallSource,
4966 szManufacturer, szPublisher,
4967 szARPREADME, szReadme,
4969 szARPURLINFOABOUT, szURLInfoAbout,
4970 szARPURLUPDATEINFO, szURLUpdateInfo,
4973 const WCHAR **p = propval;
4979 val = msi_dup_property(package->db, prop);
4980 msi_reg_set_val_str(hkey, key, val);
4984 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4986 size = deformat_string(package, modpath_fmt, &buffer);
4987 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4988 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4991 /* FIXME: Write real Estimated Size when we have it */
4992 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4994 GetLocalTime(&systime);
4995 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4996 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4998 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4999 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5001 buffer = msi_dup_property(package->db, szProductVersion);
5002 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5005 DWORD verdword = msi_version_str_to_dword(buffer);
5007 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5008 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5009 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5013 return ERROR_SUCCESS;
5016 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5018 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5020 LPWSTR upgrade_code;
5025 /* FIXME: also need to publish if the product is in advertise mode */
5026 if (!msi_check_publish(package))
5027 return ERROR_SUCCESS;
5029 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
5030 if (rc != ERROR_SUCCESS)
5033 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5034 NULL, &props, TRUE);
5035 if (rc != ERROR_SUCCESS)
5038 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5039 msi_free( package->db->localfile );
5040 package->db->localfile = NULL;
5042 rc = msi_publish_install_properties(package, hkey);
5043 if (rc != ERROR_SUCCESS)
5046 rc = msi_publish_install_properties(package, props);
5047 if (rc != ERROR_SUCCESS)
5050 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5053 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5054 squash_guid(package->ProductCode, squashed_pc);
5055 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5056 RegCloseKey(upgrade);
5057 msi_free(upgrade_code);
5061 uirow = MSI_CreateRecord( 1 );
5062 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5063 ui_actiondata( package, szRegisterProduct, uirow );
5064 msiobj_release( &uirow->hdr );
5067 return ERROR_SUCCESS;
5070 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5072 return execute_script(package,INSTALL_SCRIPT);
5075 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5077 WCHAR *upgrade, **features;
5078 BOOL full_uninstall = TRUE;
5079 MSIFEATURE *feature;
5080 MSIPATCHINFO *patch;
5082 static const WCHAR szUpgradeCode[] =
5083 {'U','p','g','r','a','d','e','C','o','d','e',0};
5085 features = msi_split_string(remove, ',');
5088 ERR("REMOVE feature list is empty!\n");
5089 return ERROR_FUNCTION_FAILED;
5092 if (!strcmpW( features[0], szAll ))
5093 full_uninstall = TRUE;
5096 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5098 if (feature->Action != INSTALLSTATE_ABSENT)
5099 full_uninstall = FALSE;
5104 if (!full_uninstall)
5105 return ERROR_SUCCESS;
5107 MSIREG_DeleteProductKey(package->ProductCode);
5108 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5109 MSIREG_DeleteUninstallKey(package);
5111 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
5113 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5114 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5118 MSIREG_DeleteUserProductKey(package->ProductCode);
5119 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5122 upgrade = msi_dup_property(package->db, szUpgradeCode);
5125 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5129 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5131 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5134 return ERROR_SUCCESS;
5137 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5142 /* turn off scheduling */
5143 package->script->CurrentlyScripting= FALSE;
5145 /* first do the same as an InstallExecute */
5146 rc = ACTION_InstallExecute(package);
5147 if (rc != ERROR_SUCCESS)
5150 /* then handle Commit Actions */
5151 rc = execute_script(package,COMMIT_SCRIPT);
5152 if (rc != ERROR_SUCCESS)
5155 remove = msi_dup_property(package->db, szRemove);
5157 rc = msi_unpublish_product(package, remove);
5163 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5165 static const WCHAR RunOnce[] = {
5166 'S','o','f','t','w','a','r','e','\\',
5167 'M','i','c','r','o','s','o','f','t','\\',
5168 'W','i','n','d','o','w','s','\\',
5169 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5170 'R','u','n','O','n','c','e',0};
5171 static const WCHAR InstallRunOnce[] = {
5172 'S','o','f','t','w','a','r','e','\\',
5173 'M','i','c','r','o','s','o','f','t','\\',
5174 'W','i','n','d','o','w','s','\\',
5175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5176 'I','n','s','t','a','l','l','e','r','\\',
5177 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5179 static const WCHAR msiexec_fmt[] = {
5181 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5182 '\"','%','s','\"',0};
5183 static const WCHAR install_fmt[] = {
5184 '/','I',' ','\"','%','s','\"',' ',
5185 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5186 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5187 WCHAR buffer[256], sysdir[MAX_PATH];
5189 WCHAR squished_pc[100];
5191 squash_guid(package->ProductCode,squished_pc);
5193 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5194 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5195 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5198 msi_reg_set_val_str( hkey, squished_pc, buffer );
5201 TRACE("Reboot command %s\n",debugstr_w(buffer));
5203 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5204 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5206 msi_reg_set_val_str( hkey, squished_pc, buffer );
5209 return ERROR_INSTALL_SUSPEND;
5212 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5218 * We are currently doing what should be done here in the top level Install
5219 * however for Administrative and uninstalls this step will be needed
5221 if (!package->PackagePath)
5222 return ERROR_SUCCESS;
5224 msi_set_sourcedir_props(package, TRUE);
5226 attrib = GetFileAttributesW(package->db->path);
5227 if (attrib == INVALID_FILE_ATTRIBUTES)
5233 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5234 package->Context, MSICODE_PRODUCT,
5235 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5236 if (rc == ERROR_MORE_DATA)
5238 prompt = msi_alloc(size * sizeof(WCHAR));
5239 MsiSourceListGetInfoW(package->ProductCode, NULL,
5240 package->Context, MSICODE_PRODUCT,
5241 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5244 prompt = strdupW(package->db->path);
5246 msg = generate_error_string(package,1302,1,prompt);
5247 while(attrib == INVALID_FILE_ATTRIBUTES)
5249 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5252 rc = ERROR_INSTALL_USEREXIT;
5255 attrib = GetFileAttributesW(package->db->path);
5261 return ERROR_SUCCESS;
5266 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5269 LPWSTR buffer, productid = NULL;
5270 UINT i, rc = ERROR_SUCCESS;
5273 static const WCHAR szPropKeys[][80] =
5275 {'P','r','o','d','u','c','t','I','D',0},
5276 {'U','S','E','R','N','A','M','E',0},
5277 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5281 static const WCHAR szRegKeys[][80] =
5283 {'P','r','o','d','u','c','t','I','D',0},
5284 {'R','e','g','O','w','n','e','r',0},
5285 {'R','e','g','C','o','m','p','a','n','y',0},
5289 if (msi_check_unpublish(package))
5291 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5295 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5299 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5301 if (rc != ERROR_SUCCESS)
5304 for( i = 0; szPropKeys[i][0]; i++ )
5306 buffer = msi_dup_property( package->db, szPropKeys[i] );
5307 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5312 uirow = MSI_CreateRecord( 1 );
5313 MSI_RecordSetStringW( uirow, 1, productid );
5314 ui_actiondata( package, szRegisterUser, uirow );
5315 msiobj_release( &uirow->hdr );
5317 msi_free(productid);
5323 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5327 package->script->InWhatSequence |= SEQUENCE_EXEC;
5328 rc = ACTION_ProcessExecSequence(package,FALSE);
5333 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5335 MSIPACKAGE *package = param;
5336 LPCWSTR compgroupid, component, feature, qualifier, text;
5337 LPWSTR advertise = NULL, output = NULL;
5345 feature = MSI_RecordGetString(rec, 5);
5346 feat = get_loaded_feature(package, feature);
5348 return ERROR_SUCCESS;
5350 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5351 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5352 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5354 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5355 feat->Action = feat->Installed;
5356 return ERROR_SUCCESS;
5359 component = MSI_RecordGetString(rec, 3);
5360 comp = get_loaded_component(package, component);
5362 return ERROR_SUCCESS;
5364 compgroupid = MSI_RecordGetString(rec,1);
5365 qualifier = MSI_RecordGetString(rec,2);
5367 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5368 if (rc != ERROR_SUCCESS)
5371 text = MSI_RecordGetString(rec,4);
5372 advertise = create_component_advertise_string(package, comp, feature);
5374 sz = strlenW(advertise);
5377 sz += lstrlenW(text);
5380 sz *= sizeof(WCHAR);
5382 output = msi_alloc_zero(sz);
5383 strcpyW(output,advertise);
5384 msi_free(advertise);
5387 strcatW(output,text);
5389 msi_reg_set_val_multi_str( hkey, qualifier, output );
5396 uirow = MSI_CreateRecord( 2 );
5397 MSI_RecordSetStringW( uirow, 1, compgroupid );
5398 MSI_RecordSetStringW( uirow, 2, qualifier);
5399 ui_actiondata( package, szPublishComponents, uirow);
5400 msiobj_release( &uirow->hdr );
5401 /* FIXME: call ui_progress? */
5407 * At present I am ignorning the advertised components part of this and only
5408 * focusing on the qualified component sets
5410 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5414 static const WCHAR ExecSeqQuery[] =
5415 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5416 '`','P','u','b','l','i','s','h',
5417 'C','o','m','p','o','n','e','n','t','`',0};
5419 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5420 if (rc != ERROR_SUCCESS)
5421 return ERROR_SUCCESS;
5423 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5424 msiobj_release(&view->hdr);
5429 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5431 static const WCHAR szInstallerComponents[] = {
5432 'S','o','f','t','w','a','r','e','\\',
5433 'M','i','c','r','o','s','o','f','t','\\',
5434 'I','n','s','t','a','l','l','e','r','\\',
5435 'C','o','m','p','o','n','e','n','t','s','\\',0};
5437 MSIPACKAGE *package = param;
5438 LPCWSTR compgroupid, component, feature, qualifier;
5442 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5445 feature = MSI_RecordGetString( rec, 5 );
5446 feat = get_loaded_feature( package, feature );
5448 return ERROR_SUCCESS;
5450 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5452 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5453 feat->Action = feat->Installed;
5454 return ERROR_SUCCESS;
5457 component = MSI_RecordGetString( rec, 3 );
5458 comp = get_loaded_component( package, component );
5460 return ERROR_SUCCESS;
5462 compgroupid = MSI_RecordGetString( rec, 1 );
5463 qualifier = MSI_RecordGetString( rec, 2 );
5465 squash_guid( compgroupid, squashed );
5466 strcpyW( keypath, szInstallerComponents );
5467 strcatW( keypath, squashed );
5469 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5470 if (res != ERROR_SUCCESS)
5472 WARN("Unable to delete component key %d\n", res);
5475 uirow = MSI_CreateRecord( 2 );
5476 MSI_RecordSetStringW( uirow, 1, compgroupid );
5477 MSI_RecordSetStringW( uirow, 2, qualifier );
5478 ui_actiondata( package, szUnpublishComponents, uirow );
5479 msiobj_release( &uirow->hdr );
5481 return ERROR_SUCCESS;
5484 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5488 static const WCHAR query[] =
5489 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5490 '`','P','u','b','l','i','s','h',
5491 'C','o','m','p','o','n','e','n','t','`',0};
5493 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5494 if (rc != ERROR_SUCCESS)
5495 return ERROR_SUCCESS;
5497 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5498 msiobj_release( &view->hdr );
5503 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5505 MSIPACKAGE *package = param;
5508 SC_HANDLE hscm, service = NULL;
5510 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5511 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5512 DWORD serv_type, start_type, err_control;
5513 SERVICE_DESCRIPTIONW sd = {NULL};
5515 static const WCHAR query[] =
5516 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5517 '`','C','o','m','p','o','n','e','n','t','`',' ',
5518 'W','H','E','R','E',' ',
5519 '`','C','o','m','p','o','n','e','n','t','`',' ',
5520 '=','\'','%','s','\'',0};
5522 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5525 ERR("Failed to open the SC Manager!\n");
5529 comp = MSI_RecordGetString( rec, 12 );
5530 if (!get_loaded_component( package, comp ))
5533 start_type = MSI_RecordGetInteger(rec, 5);
5534 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5537 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5538 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5539 serv_type = MSI_RecordGetInteger(rec, 4);
5540 err_control = MSI_RecordGetInteger(rec, 6);
5541 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5542 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5543 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5544 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5545 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5546 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5548 /* fetch the service path */
5549 row = MSI_QueryGetRecord(package->db, query, comp);
5552 ERR("Control query failed!\n");
5555 key = MSI_RecordGetString(row, 6);
5557 file = get_loaded_file(package, key);
5558 msiobj_release(&row->hdr);
5561 ERR("Failed to load the service file\n");
5565 if (!args || !args[0]) image_path = file->TargetPath;
5568 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5569 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5570 return ERROR_OUTOFMEMORY;
5572 strcpyW(image_path, file->TargetPath);
5573 strcatW(image_path, szSpace);
5574 strcatW(image_path, args);
5576 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5577 start_type, err_control, image_path, load_order,
5578 NULL, depends, serv_name, pass);
5582 if (GetLastError() != ERROR_SERVICE_EXISTS)
5583 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5585 else if (sd.lpDescription)
5587 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5588 WARN("failed to set service description %u\n", GetLastError());
5591 if (image_path != file->TargetPath) msi_free(image_path);
5593 CloseServiceHandle(service);
5594 CloseServiceHandle(hscm);
5597 msi_free(sd.lpDescription);
5598 msi_free(load_order);
5599 msi_free(serv_name);
5604 return ERROR_SUCCESS;
5607 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5611 static const WCHAR ExecSeqQuery[] =
5612 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5613 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5615 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5616 if (rc != ERROR_SUCCESS)
5617 return ERROR_SUCCESS;
5619 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5620 msiobj_release(&view->hdr);
5625 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5626 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5628 LPCWSTR *vector, *temp_vector;
5632 static const WCHAR separator[] = {'[','~',']',0};
5635 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5640 vector = msi_alloc(sizeof(LPWSTR));
5648 vector[*numargs - 1] = p;
5650 if ((q = strstrW(p, separator)))
5654 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5660 vector = temp_vector;
5669 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5671 MSIPACKAGE *package = param;
5674 SC_HANDLE scm = NULL, service = NULL;
5675 LPCWSTR component, *vector = NULL;
5676 LPWSTR name, args, display_name = NULL;
5677 DWORD event, numargs, len;
5678 UINT r = ERROR_FUNCTION_FAILED;
5680 component = MSI_RecordGetString(rec, 6);
5681 comp = get_loaded_component(package, component);
5683 return ERROR_SUCCESS;
5687 TRACE("component is disabled\n");
5688 return ERROR_SUCCESS;
5691 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5693 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5694 comp->Action = comp->Installed;
5695 return ERROR_SUCCESS;
5697 comp->Action = INSTALLSTATE_LOCAL;
5699 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5700 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5701 event = MSI_RecordGetInteger(rec, 3);
5703 if (!(event & msidbServiceControlEventStart))
5709 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5712 ERR("Failed to open the service control manager\n");
5717 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5718 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5720 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5721 GetServiceDisplayNameW( scm, name, display_name, &len );
5724 service = OpenServiceW(scm, name, SERVICE_START);
5727 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5731 vector = msi_service_args_to_vector(args, &numargs);
5733 if (!StartServiceW(service, numargs, vector) &&
5734 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5736 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5743 uirow = MSI_CreateRecord( 2 );
5744 MSI_RecordSetStringW( uirow, 1, display_name );
5745 MSI_RecordSetStringW( uirow, 2, name );
5746 ui_actiondata( package, szStartServices, uirow );
5747 msiobj_release( &uirow->hdr );
5749 CloseServiceHandle(service);
5750 CloseServiceHandle(scm);
5755 msi_free(display_name);
5759 static UINT ACTION_StartServices( MSIPACKAGE *package )
5764 static const WCHAR query[] = {
5765 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5766 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5768 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5769 if (rc != ERROR_SUCCESS)
5770 return ERROR_SUCCESS;
5772 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5773 msiobj_release(&view->hdr);
5778 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5780 DWORD i, needed, count;
5781 ENUM_SERVICE_STATUSW *dependencies;
5785 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5786 0, &needed, &count))
5789 if (GetLastError() != ERROR_MORE_DATA)
5792 dependencies = msi_alloc(needed);
5796 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5797 needed, &needed, &count))
5800 for (i = 0; i < count; i++)
5802 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5803 SERVICE_STOP | SERVICE_QUERY_STATUS);
5807 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5814 msi_free(dependencies);
5818 static UINT stop_service( LPCWSTR name )
5820 SC_HANDLE scm = NULL, service = NULL;
5821 SERVICE_STATUS status;
5822 SERVICE_STATUS_PROCESS ssp;
5825 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5828 WARN("Failed to open the SCM: %d\n", GetLastError());
5832 service = OpenServiceW(scm, name,
5834 SERVICE_QUERY_STATUS |
5835 SERVICE_ENUMERATE_DEPENDENTS);
5838 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5842 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5843 sizeof(SERVICE_STATUS_PROCESS), &needed))
5845 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5849 if (ssp.dwCurrentState == SERVICE_STOPPED)
5852 stop_service_dependents(scm, service);
5854 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5855 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5858 CloseServiceHandle(service);
5859 CloseServiceHandle(scm);
5861 return ERROR_SUCCESS;
5864 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5866 MSIPACKAGE *package = param;
5870 LPWSTR name = NULL, display_name = NULL;
5874 event = MSI_RecordGetInteger( rec, 3 );
5875 if (!(event & msidbServiceControlEventStop))
5876 return ERROR_SUCCESS;
5878 component = MSI_RecordGetString( rec, 6 );
5879 comp = get_loaded_component( package, component );
5881 return ERROR_SUCCESS;
5885 TRACE("component is disabled\n");
5886 return ERROR_SUCCESS;
5889 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5891 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5892 comp->Action = comp->Installed;
5893 return ERROR_SUCCESS;
5895 comp->Action = INSTALLSTATE_ABSENT;
5897 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5900 ERR("Failed to open the service control manager\n");
5905 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5906 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5908 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5909 GetServiceDisplayNameW( scm, name, display_name, &len );
5911 CloseServiceHandle( scm );
5913 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5914 stop_service( name );
5917 uirow = MSI_CreateRecord( 2 );
5918 MSI_RecordSetStringW( uirow, 1, display_name );
5919 MSI_RecordSetStringW( uirow, 2, name );
5920 ui_actiondata( package, szStopServices, uirow );
5921 msiobj_release( &uirow->hdr );
5924 msi_free( display_name );
5925 return ERROR_SUCCESS;
5928 static UINT ACTION_StopServices( MSIPACKAGE *package )
5933 static const WCHAR query[] = {
5934 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5935 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5937 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5938 if (rc != ERROR_SUCCESS)
5939 return ERROR_SUCCESS;
5941 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5942 msiobj_release(&view->hdr);
5947 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5949 MSIPACKAGE *package = param;
5953 LPWSTR name = NULL, display_name = NULL;
5955 SC_HANDLE scm = NULL, service = NULL;
5957 event = MSI_RecordGetInteger( rec, 3 );
5958 if (!(event & msidbServiceControlEventDelete))
5959 return ERROR_SUCCESS;
5961 component = MSI_RecordGetString(rec, 6);
5962 comp = get_loaded_component(package, component);
5964 return ERROR_SUCCESS;
5968 TRACE("component is disabled\n");
5969 return ERROR_SUCCESS;
5972 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5974 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5975 comp->Action = comp->Installed;
5976 return ERROR_SUCCESS;
5978 comp->Action = INSTALLSTATE_ABSENT;
5980 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5981 stop_service( name );
5983 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5986 WARN("Failed to open the SCM: %d\n", GetLastError());
5991 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5992 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5994 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5995 GetServiceDisplayNameW( scm, name, display_name, &len );
5998 service = OpenServiceW( scm, name, DELETE );
6001 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6005 if (!DeleteService( service ))
6006 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6009 uirow = MSI_CreateRecord( 2 );
6010 MSI_RecordSetStringW( uirow, 1, display_name );
6011 MSI_RecordSetStringW( uirow, 2, name );
6012 ui_actiondata( package, szDeleteServices, uirow );
6013 msiobj_release( &uirow->hdr );
6015 CloseServiceHandle( service );
6016 CloseServiceHandle( scm );
6018 msi_free( display_name );
6020 return ERROR_SUCCESS;
6023 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6028 static const WCHAR query[] = {
6029 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6030 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6032 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6033 if (rc != ERROR_SUCCESS)
6034 return ERROR_SUCCESS;
6036 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6037 msiobj_release( &view->hdr );
6042 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6044 MSIPACKAGE *package = param;
6045 LPWSTR driver, driver_path, ptr;
6046 WCHAR outpath[MAX_PATH];
6047 MSIFILE *driver_file = NULL, *setup_file = NULL;
6050 LPCWSTR desc, file_key, component;
6052 UINT r = ERROR_SUCCESS;
6054 static const WCHAR driver_fmt[] = {
6055 'D','r','i','v','e','r','=','%','s',0};
6056 static const WCHAR setup_fmt[] = {
6057 'S','e','t','u','p','=','%','s',0};
6058 static const WCHAR usage_fmt[] = {
6059 'F','i','l','e','U','s','a','g','e','=','1',0};
6061 component = MSI_RecordGetString( rec, 2 );
6062 comp = get_loaded_component( package, component );
6064 return ERROR_SUCCESS;
6068 TRACE("component is disabled\n");
6069 return ERROR_SUCCESS;
6072 desc = MSI_RecordGetString(rec, 3);
6074 file_key = MSI_RecordGetString( rec, 4 );
6075 if (file_key) driver_file = get_loaded_file( package, file_key );
6077 file_key = MSI_RecordGetString( rec, 5 );
6078 if (file_key) setup_file = get_loaded_file( package, file_key );
6082 ERR("ODBC Driver entry not found!\n");
6083 return ERROR_FUNCTION_FAILED;
6086 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6088 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6089 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6091 driver = msi_alloc(len * sizeof(WCHAR));
6093 return ERROR_OUTOFMEMORY;
6096 lstrcpyW(ptr, desc);
6097 ptr += lstrlenW(ptr) + 1;
6099 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6104 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6108 lstrcpyW(ptr, usage_fmt);
6109 ptr += lstrlenW(ptr) + 1;
6112 driver_path = strdupW(driver_file->TargetPath);
6113 ptr = strrchrW(driver_path, '\\');
6114 if (ptr) *ptr = '\0';
6116 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6117 NULL, ODBC_INSTALL_COMPLETE, &usage))
6119 ERR("Failed to install SQL driver!\n");
6120 r = ERROR_FUNCTION_FAILED;
6123 uirow = MSI_CreateRecord( 5 );
6124 MSI_RecordSetStringW( uirow, 1, desc );
6125 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6126 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6127 ui_actiondata( package, szInstallODBC, uirow );
6128 msiobj_release( &uirow->hdr );
6131 msi_free(driver_path);
6136 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6138 MSIPACKAGE *package = param;
6139 LPWSTR translator, translator_path, ptr;
6140 WCHAR outpath[MAX_PATH];
6141 MSIFILE *translator_file = NULL, *setup_file = NULL;
6144 LPCWSTR desc, file_key, component;
6146 UINT r = ERROR_SUCCESS;
6148 static const WCHAR translator_fmt[] = {
6149 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6150 static const WCHAR setup_fmt[] = {
6151 'S','e','t','u','p','=','%','s',0};
6153 component = MSI_RecordGetString( rec, 2 );
6154 comp = get_loaded_component( package, component );
6156 return ERROR_SUCCESS;
6160 TRACE("component is disabled\n");
6161 return ERROR_SUCCESS;
6164 desc = MSI_RecordGetString(rec, 3);
6166 file_key = MSI_RecordGetString( rec, 4 );
6167 if (file_key) translator_file = get_loaded_file( package, file_key );
6169 file_key = MSI_RecordGetString( rec, 5 );
6170 if (file_key) setup_file = get_loaded_file( package, file_key );
6172 if (!translator_file)
6174 ERR("ODBC Translator entry not found!\n");
6175 return ERROR_FUNCTION_FAILED;
6178 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6180 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6182 translator = msi_alloc(len * sizeof(WCHAR));
6184 return ERROR_OUTOFMEMORY;
6187 lstrcpyW(ptr, desc);
6188 ptr += lstrlenW(ptr) + 1;
6190 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6195 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6200 translator_path = strdupW(translator_file->TargetPath);
6201 ptr = strrchrW(translator_path, '\\');
6202 if (ptr) *ptr = '\0';
6204 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6205 NULL, ODBC_INSTALL_COMPLETE, &usage))
6207 ERR("Failed to install SQL translator!\n");
6208 r = ERROR_FUNCTION_FAILED;
6211 uirow = MSI_CreateRecord( 5 );
6212 MSI_RecordSetStringW( uirow, 1, desc );
6213 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6214 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6215 ui_actiondata( package, szInstallODBC, uirow );
6216 msiobj_release( &uirow->hdr );
6218 msi_free(translator);
6219 msi_free(translator_path);
6224 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6226 MSIPACKAGE *package = param;
6229 LPCWSTR desc, driver, component;
6230 WORD request = ODBC_ADD_SYS_DSN;
6233 UINT r = ERROR_SUCCESS;
6236 static const WCHAR attrs_fmt[] = {
6237 'D','S','N','=','%','s',0 };
6239 component = MSI_RecordGetString( rec, 2 );
6240 comp = get_loaded_component( package, component );
6242 return ERROR_SUCCESS;
6246 TRACE("component is disabled\n");
6247 return ERROR_SUCCESS;
6250 desc = MSI_RecordGetString(rec, 3);
6251 driver = MSI_RecordGetString(rec, 4);
6252 registration = MSI_RecordGetInteger(rec, 5);
6254 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6255 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6257 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6258 attrs = msi_alloc(len * sizeof(WCHAR));
6260 return ERROR_OUTOFMEMORY;
6262 len = sprintfW(attrs, attrs_fmt, desc);
6265 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6267 ERR("Failed to install SQL data source!\n");
6268 r = ERROR_FUNCTION_FAILED;
6271 uirow = MSI_CreateRecord( 5 );
6272 MSI_RecordSetStringW( uirow, 1, desc );
6273 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6274 MSI_RecordSetInteger( uirow, 3, request );
6275 ui_actiondata( package, szInstallODBC, uirow );
6276 msiobj_release( &uirow->hdr );
6283 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6288 static const WCHAR driver_query[] = {
6289 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6290 'O','D','B','C','D','r','i','v','e','r',0 };
6292 static const WCHAR translator_query[] = {
6293 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6294 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6296 static const WCHAR source_query[] = {
6297 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6298 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6300 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6301 if (rc != ERROR_SUCCESS)
6302 return ERROR_SUCCESS;
6304 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6305 msiobj_release(&view->hdr);
6307 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6308 if (rc != ERROR_SUCCESS)
6309 return ERROR_SUCCESS;
6311 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6312 msiobj_release(&view->hdr);
6314 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6315 if (rc != ERROR_SUCCESS)
6316 return ERROR_SUCCESS;
6318 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6319 msiobj_release(&view->hdr);
6324 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6326 MSIPACKAGE *package = param;
6330 LPCWSTR desc, component;
6332 component = MSI_RecordGetString( rec, 2 );
6333 comp = get_loaded_component( package, component );
6335 return ERROR_SUCCESS;
6339 TRACE("component is disabled\n");
6340 return ERROR_SUCCESS;
6343 desc = MSI_RecordGetString( rec, 3 );
6344 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6346 WARN("Failed to remove ODBC driver\n");
6350 FIXME("Usage count reached 0\n");
6353 uirow = MSI_CreateRecord( 2 );
6354 MSI_RecordSetStringW( uirow, 1, desc );
6355 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6356 ui_actiondata( package, szRemoveODBC, uirow );
6357 msiobj_release( &uirow->hdr );
6359 return ERROR_SUCCESS;
6362 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6364 MSIPACKAGE *package = param;
6368 LPCWSTR desc, component;
6370 component = MSI_RecordGetString( rec, 2 );
6371 comp = get_loaded_component( package, component );
6373 return ERROR_SUCCESS;
6377 TRACE("component is disabled\n");
6378 return ERROR_SUCCESS;
6381 desc = MSI_RecordGetString( rec, 3 );
6382 if (!SQLRemoveTranslatorW( desc, &usage ))
6384 WARN("Failed to remove ODBC translator\n");
6388 FIXME("Usage count reached 0\n");
6391 uirow = MSI_CreateRecord( 2 );
6392 MSI_RecordSetStringW( uirow, 1, desc );
6393 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6394 ui_actiondata( package, szRemoveODBC, uirow );
6395 msiobj_release( &uirow->hdr );
6397 return ERROR_SUCCESS;
6400 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6402 MSIPACKAGE *package = param;
6406 LPCWSTR desc, driver, component;
6407 WORD request = ODBC_REMOVE_SYS_DSN;
6411 static const WCHAR attrs_fmt[] = {
6412 'D','S','N','=','%','s',0 };
6414 component = MSI_RecordGetString( rec, 2 );
6415 comp = get_loaded_component( package, component );
6417 return ERROR_SUCCESS;
6421 TRACE("component is disabled\n");
6422 return ERROR_SUCCESS;
6425 desc = MSI_RecordGetString( rec, 3 );
6426 driver = MSI_RecordGetString( rec, 4 );
6427 registration = MSI_RecordGetInteger( rec, 5 );
6429 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6430 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6432 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6433 attrs = msi_alloc( len * sizeof(WCHAR) );
6435 return ERROR_OUTOFMEMORY;
6437 FIXME("Use ODBCSourceAttribute table\n");
6439 len = sprintfW( attrs, attrs_fmt, desc );
6442 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6444 WARN("Failed to remove ODBC data source\n");
6448 uirow = MSI_CreateRecord( 3 );
6449 MSI_RecordSetStringW( uirow, 1, desc );
6450 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6451 MSI_RecordSetInteger( uirow, 3, request );
6452 ui_actiondata( package, szRemoveODBC, uirow );
6453 msiobj_release( &uirow->hdr );
6455 return ERROR_SUCCESS;
6458 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6463 static const WCHAR driver_query[] = {
6464 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6465 'O','D','B','C','D','r','i','v','e','r',0 };
6467 static const WCHAR translator_query[] = {
6468 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6469 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6471 static const WCHAR source_query[] = {
6472 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6473 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6475 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6476 if (rc != ERROR_SUCCESS)
6477 return ERROR_SUCCESS;
6479 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6480 msiobj_release( &view->hdr );
6482 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6483 if (rc != ERROR_SUCCESS)
6484 return ERROR_SUCCESS;
6486 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6487 msiobj_release( &view->hdr );
6489 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6490 if (rc != ERROR_SUCCESS)
6491 return ERROR_SUCCESS;
6493 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6494 msiobj_release( &view->hdr );
6499 #define ENV_ACT_SETALWAYS 0x1
6500 #define ENV_ACT_SETABSENT 0x2
6501 #define ENV_ACT_REMOVE 0x4
6502 #define ENV_ACT_REMOVEMATCH 0x8
6504 #define ENV_MOD_MACHINE 0x20000000
6505 #define ENV_MOD_APPEND 0x40000000
6506 #define ENV_MOD_PREFIX 0x80000000
6507 #define ENV_MOD_MASK 0xC0000000
6509 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6511 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6513 LPCWSTR cptr = *name;
6515 static const WCHAR prefix[] = {'[','~',']',0};
6516 static const int prefix_len = 3;
6522 *flags |= ENV_ACT_SETALWAYS;
6523 else if (*cptr == '+')
6524 *flags |= ENV_ACT_SETABSENT;
6525 else if (*cptr == '-')
6526 *flags |= ENV_ACT_REMOVE;
6527 else if (*cptr == '!')
6528 *flags |= ENV_ACT_REMOVEMATCH;
6529 else if (*cptr == '*')
6530 *flags |= ENV_MOD_MACHINE;
6540 ERR("Missing environment variable\n");
6541 return ERROR_FUNCTION_FAILED;
6546 LPCWSTR ptr = *value;
6547 if (!strncmpW(ptr, prefix, prefix_len))
6549 if (ptr[prefix_len] == szSemiColon[0])
6551 *flags |= ENV_MOD_APPEND;
6552 *value += lstrlenW(prefix);
6559 else if (lstrlenW(*value) >= prefix_len)
6561 ptr += lstrlenW(ptr) - prefix_len;
6562 if (!strcmpW( ptr, prefix ))
6564 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6566 *flags |= ENV_MOD_PREFIX;
6567 /* the "[~]" will be removed by deformat_string */;
6577 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6578 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6579 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6580 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6582 ERR("Invalid flags: %08x\n", *flags);
6583 return ERROR_FUNCTION_FAILED;
6587 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6589 return ERROR_SUCCESS;
6592 static UINT open_env_key( DWORD flags, HKEY *key )
6594 static const WCHAR user_env[] =
6595 {'E','n','v','i','r','o','n','m','e','n','t',0};
6596 static const WCHAR machine_env[] =
6597 {'S','y','s','t','e','m','\\',
6598 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6599 'C','o','n','t','r','o','l','\\',
6600 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6601 'E','n','v','i','r','o','n','m','e','n','t',0};
6606 if (flags & ENV_MOD_MACHINE)
6609 root = HKEY_LOCAL_MACHINE;
6614 root = HKEY_CURRENT_USER;
6617 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6618 if (res != ERROR_SUCCESS)
6620 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6621 return ERROR_FUNCTION_FAILED;
6624 return ERROR_SUCCESS;
6627 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6629 MSIPACKAGE *package = param;
6630 LPCWSTR name, value, component;
6631 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6632 DWORD flags, type, size;
6639 component = MSI_RecordGetString(rec, 4);
6640 comp = get_loaded_component(package, component);
6642 return ERROR_SUCCESS;
6646 TRACE("component is disabled\n");
6647 return ERROR_SUCCESS;
6650 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6652 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6653 comp->Action = comp->Installed;
6654 return ERROR_SUCCESS;
6656 comp->Action = INSTALLSTATE_LOCAL;
6658 name = MSI_RecordGetString(rec, 2);
6659 value = MSI_RecordGetString(rec, 3);
6661 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6663 res = env_parse_flags(&name, &value, &flags);
6664 if (res != ERROR_SUCCESS || !value)
6667 if (value && !deformat_string(package, value, &deformatted))
6669 res = ERROR_OUTOFMEMORY;
6673 value = deformatted;
6675 res = open_env_key( flags, &env );
6676 if (res != ERROR_SUCCESS)
6679 if (flags & ENV_MOD_MACHINE)
6680 action |= 0x20000000;
6684 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6685 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6686 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6689 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6693 /* Nothing to do. */
6696 res = ERROR_SUCCESS;
6700 /* If we are appending but the string was empty, strip ; */
6701 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6703 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6704 newval = strdupW(value);
6707 res = ERROR_OUTOFMEMORY;
6715 /* Contrary to MSDN, +-variable to [~];path works */
6716 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6718 res = ERROR_SUCCESS;
6722 data = msi_alloc(size);
6726 return ERROR_OUTOFMEMORY;
6729 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6730 if (res != ERROR_SUCCESS)
6733 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6736 res = RegDeleteValueW(env, name);
6737 if (res != ERROR_SUCCESS)
6738 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6742 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6743 if (flags & ENV_MOD_MASK)
6747 if (flags & ENV_MOD_APPEND) multiplier++;
6748 if (flags & ENV_MOD_PREFIX) multiplier++;
6749 mod_size = lstrlenW(value) * multiplier;
6750 size += mod_size * sizeof(WCHAR);
6753 newval = msi_alloc(size);
6757 res = ERROR_OUTOFMEMORY;
6761 if (flags & ENV_MOD_PREFIX)
6763 lstrcpyW(newval, value);
6764 ptr = newval + lstrlenW(value);
6765 action |= 0x80000000;
6768 lstrcpyW(ptr, data);
6770 if (flags & ENV_MOD_APPEND)
6772 lstrcatW(newval, value);
6773 action |= 0x40000000;
6776 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6777 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6780 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6784 uirow = MSI_CreateRecord( 3 );
6785 MSI_RecordSetStringW( uirow, 1, name );
6786 MSI_RecordSetStringW( uirow, 2, newval );
6787 MSI_RecordSetInteger( uirow, 3, action );
6788 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6789 msiobj_release( &uirow->hdr );
6791 if (env) RegCloseKey(env);
6792 msi_free(deformatted);
6798 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6802 static const WCHAR ExecSeqQuery[] =
6803 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6804 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6805 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6806 if (rc != ERROR_SUCCESS)
6807 return ERROR_SUCCESS;
6809 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6810 msiobj_release(&view->hdr);
6815 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6817 MSIPACKAGE *package = param;
6818 LPCWSTR name, value, component;
6819 LPWSTR deformatted = NULL;
6828 component = MSI_RecordGetString( rec, 4 );
6829 comp = get_loaded_component( package, component );
6831 return ERROR_SUCCESS;
6835 TRACE("component is disabled\n");
6836 return ERROR_SUCCESS;
6839 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6841 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6842 comp->Action = comp->Installed;
6843 return ERROR_SUCCESS;
6845 comp->Action = INSTALLSTATE_ABSENT;
6847 name = MSI_RecordGetString( rec, 2 );
6848 value = MSI_RecordGetString( rec, 3 );
6850 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6852 r = env_parse_flags( &name, &value, &flags );
6853 if (r != ERROR_SUCCESS)
6856 if (!(flags & ENV_ACT_REMOVE))
6858 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6859 return ERROR_SUCCESS;
6862 if (value && !deformat_string( package, value, &deformatted ))
6863 return ERROR_OUTOFMEMORY;
6865 value = deformatted;
6867 r = open_env_key( flags, &env );
6868 if (r != ERROR_SUCCESS)
6874 if (flags & ENV_MOD_MACHINE)
6875 action |= 0x20000000;
6877 TRACE("Removing %s\n", debugstr_w(name));
6879 res = RegDeleteValueW( env, name );
6880 if (res != ERROR_SUCCESS)
6882 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6887 uirow = MSI_CreateRecord( 3 );
6888 MSI_RecordSetStringW( uirow, 1, name );
6889 MSI_RecordSetStringW( uirow, 2, value );
6890 MSI_RecordSetInteger( uirow, 3, action );
6891 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6892 msiobj_release( &uirow->hdr );
6894 if (env) RegCloseKey( env );
6895 msi_free( deformatted );
6899 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6903 static const WCHAR query[] =
6904 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6905 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6907 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6908 if (rc != ERROR_SUCCESS)
6909 return ERROR_SUCCESS;
6911 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6912 msiobj_release( &view->hdr );
6917 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6919 LPWSTR key, template, id;
6920 UINT r = ERROR_SUCCESS;
6922 id = msi_dup_property( package->db, szProductID );
6926 return ERROR_SUCCESS;
6928 template = msi_dup_property( package->db, szPIDTemplate );
6929 key = msi_dup_property( package->db, szPIDKEY );
6931 if (key && template)
6933 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6934 r = msi_set_property( package->db, szProductID, key );
6936 msi_free( template );
6941 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6944 package->need_reboot = 1;
6945 return ERROR_SUCCESS;
6948 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6950 static const WCHAR szAvailableFreeReg[] =
6951 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6953 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6955 TRACE("%p %d kilobytes\n", package, space);
6957 uirow = MSI_CreateRecord( 1 );
6958 MSI_RecordSetInteger( uirow, 1, space );
6959 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6960 msiobj_release( &uirow->hdr );
6962 return ERROR_SUCCESS;
6965 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6967 FIXME("%p\n", package);
6968 return ERROR_SUCCESS;
6971 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6973 FIXME("%p\n", package);
6974 return ERROR_SUCCESS;
6977 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6982 static const WCHAR driver_query[] = {
6983 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6984 'O','D','B','C','D','r','i','v','e','r',0 };
6986 static const WCHAR translator_query[] = {
6987 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6988 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6990 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6991 if (r == ERROR_SUCCESS)
6994 r = MSI_IterateRecords( view, &count, NULL, package );
6995 msiobj_release( &view->hdr );
6996 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6999 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7000 if (r == ERROR_SUCCESS)
7003 r = MSI_IterateRecords( view, &count, NULL, package );
7004 msiobj_release( &view->hdr );
7005 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7008 return ERROR_SUCCESS;
7011 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7013 MSIPACKAGE *package = param;
7014 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7017 if ((value = msi_dup_property( package->db, property )))
7019 FIXME("remove %s\n", debugstr_w(value));
7022 return ERROR_SUCCESS;
7025 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7030 static const WCHAR query[] =
7031 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7032 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7034 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7035 if (r == ERROR_SUCCESS)
7037 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7038 msiobj_release( &view->hdr );
7040 return ERROR_SUCCESS;
7043 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7045 MSIPACKAGE *package = param;
7046 int attributes = MSI_RecordGetInteger( rec, 5 );
7048 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7050 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7051 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7052 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7053 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7057 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7059 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7060 if (r != ERROR_SUCCESS)
7061 return ERROR_SUCCESS;
7065 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7066 if (r != ERROR_SUCCESS)
7067 return ERROR_SUCCESS;
7069 RegCloseKey( hkey );
7071 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7072 debugstr_w(upgrade_code), debugstr_w(version_min),
7073 debugstr_w(version_max), debugstr_w(language));
7075 return ERROR_SUCCESS;
7078 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7083 static const WCHAR query[] =
7084 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7086 if (msi_get_property_int( package->db, szInstalled, 0 ))
7088 TRACE("product is installed, skipping action\n");
7089 return ERROR_SUCCESS;
7091 if (msi_get_property_int( package->db, szPreselected, 0 ))
7093 TRACE("Preselected property is set, not migrating feature states\n");
7094 return ERROR_SUCCESS;
7097 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7098 if (r == ERROR_SUCCESS)
7100 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7101 msiobj_release( &view->hdr );
7103 return ERROR_SUCCESS;
7106 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7107 LPCSTR action, LPCWSTR table )
7109 static const WCHAR query[] = {
7110 'S','E','L','E','C','T',' ','*',' ',
7111 'F','R','O','M',' ','`','%','s','`',0 };
7112 MSIQUERY *view = NULL;
7116 r = MSI_OpenQuery( package->db, &view, query, table );
7117 if (r == ERROR_SUCCESS)
7119 r = MSI_IterateRecords(view, &count, NULL, package);
7120 msiobj_release(&view->hdr);
7124 FIXME("%s -> %u ignored %s table values\n",
7125 action, count, debugstr_w(table));
7127 return ERROR_SUCCESS;
7130 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7132 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7133 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7136 static UINT ACTION_BindImage( MSIPACKAGE *package )
7138 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7139 return msi_unimplemented_action_stub( package, "BindImage", table );
7142 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7144 static const WCHAR table[] = {
7145 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7146 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7149 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7151 static const WCHAR table[] = {
7152 'M','s','i','A','s','s','e','m','b','l','y',0 };
7153 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7156 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7158 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7159 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7162 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7164 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7165 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7168 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7170 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7171 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7174 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7176 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7177 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7180 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7184 const WCHAR *action;
7185 UINT (*handler)(MSIPACKAGE *);
7189 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7190 { szAppSearch, ACTION_AppSearch },
7191 { szBindImage, ACTION_BindImage },
7192 { szCCPSearch, ACTION_CCPSearch },
7193 { szCostFinalize, ACTION_CostFinalize },
7194 { szCostInitialize, ACTION_CostInitialize },
7195 { szCreateFolders, ACTION_CreateFolders },
7196 { szCreateShortcuts, ACTION_CreateShortcuts },
7197 { szDeleteServices, ACTION_DeleteServices },
7198 { szDisableRollback, ACTION_DisableRollback },
7199 { szDuplicateFiles, ACTION_DuplicateFiles },
7200 { szExecuteAction, ACTION_ExecuteAction },
7201 { szFileCost, ACTION_FileCost },
7202 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7203 { szForceReboot, ACTION_ForceReboot },
7204 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7205 { szInstallExecute, ACTION_InstallExecute },
7206 { szInstallExecuteAgain, ACTION_InstallExecute },
7207 { szInstallFiles, ACTION_InstallFiles},
7208 { szInstallFinalize, ACTION_InstallFinalize },
7209 { szInstallInitialize, ACTION_InstallInitialize },
7210 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7211 { szInstallValidate, ACTION_InstallValidate },
7212 { szIsolateComponents, ACTION_IsolateComponents },
7213 { szLaunchConditions, ACTION_LaunchConditions },
7214 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7215 { szMoveFiles, ACTION_MoveFiles },
7216 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7217 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7218 { szInstallODBC, ACTION_InstallODBC },
7219 { szInstallServices, ACTION_InstallServices },
7220 { szPatchFiles, ACTION_PatchFiles },
7221 { szProcessComponents, ACTION_ProcessComponents },
7222 { szPublishComponents, ACTION_PublishComponents },
7223 { szPublishFeatures, ACTION_PublishFeatures },
7224 { szPublishProduct, ACTION_PublishProduct },
7225 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7226 { szRegisterComPlus, ACTION_RegisterComPlus},
7227 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7228 { szRegisterFonts, ACTION_RegisterFonts },
7229 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7230 { szRegisterProduct, ACTION_RegisterProduct },
7231 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7232 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7233 { szRegisterUser, ACTION_RegisterUser },
7234 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7235 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7236 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7237 { szRemoveFiles, ACTION_RemoveFiles },
7238 { szRemoveFolders, ACTION_RemoveFolders },
7239 { szRemoveIniValues, ACTION_RemoveIniValues },
7240 { szRemoveODBC, ACTION_RemoveODBC },
7241 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7242 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7243 { szResolveSource, ACTION_ResolveSource },
7244 { szRMCCPSearch, ACTION_RMCCPSearch },
7245 { szScheduleReboot, ACTION_ScheduleReboot },
7246 { szSelfRegModules, ACTION_SelfRegModules },
7247 { szSelfUnregModules, ACTION_SelfUnregModules },
7248 { szSetODBCFolders, ACTION_SetODBCFolders },
7249 { szStartServices, ACTION_StartServices },
7250 { szStopServices, ACTION_StopServices },
7251 { szUnpublishComponents, ACTION_UnpublishComponents },
7252 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7253 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7254 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7255 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7256 { szUnregisterFonts, ACTION_UnregisterFonts },
7257 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7258 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7259 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7260 { szValidateProductID, ACTION_ValidateProductID },
7261 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7262 { szWriteIniValues, ACTION_WriteIniValues },
7263 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7267 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7273 while (StandardActions[i].action != NULL)
7275 if (!strcmpW( StandardActions[i].action, action ))
7277 ui_actionstart( package, action );
7278 if (StandardActions[i].handler)
7280 ui_actioninfo( package, action, TRUE, 0 );
7281 *rc = StandardActions[i].handler( package );
7282 ui_actioninfo( package, action, FALSE, *rc );
7286 FIXME("unhandled standard action %s\n", debugstr_w(action));
7287 *rc = ERROR_SUCCESS;
7297 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7299 UINT rc = ERROR_SUCCESS;
7302 TRACE("Performing action (%s)\n", debugstr_w(action));
7304 handled = ACTION_HandleStandardAction(package, action, &rc);
7307 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7311 WARN("unhandled msi action %s\n", debugstr_w(action));
7312 rc = ERROR_FUNCTION_NOT_CALLED;
7318 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7320 UINT rc = ERROR_SUCCESS;
7321 BOOL handled = FALSE;
7323 TRACE("Performing action (%s)\n", debugstr_w(action));
7325 handled = ACTION_HandleStandardAction(package, action, &rc);
7328 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7330 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7335 WARN("unhandled msi action %s\n", debugstr_w(action));
7336 rc = ERROR_FUNCTION_NOT_CALLED;
7342 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7344 UINT rc = ERROR_SUCCESS;
7347 static const WCHAR ExecSeqQuery[] =
7348 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7349 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7350 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7351 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7352 static const WCHAR UISeqQuery[] =
7353 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7354 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7355 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7356 ' ', '=',' ','%','i',0};
7358 if (needs_ui_sequence(package))
7359 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7361 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7365 LPCWSTR action, cond;
7367 TRACE("Running the actions\n");
7369 /* check conditions */
7370 cond = MSI_RecordGetString(row, 2);
7372 /* this is a hack to skip errors in the condition code */
7373 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7375 msiobj_release(&row->hdr);
7376 return ERROR_SUCCESS;
7379 action = MSI_RecordGetString(row, 1);
7382 ERR("failed to fetch action\n");
7383 msiobj_release(&row->hdr);
7384 return ERROR_FUNCTION_FAILED;
7387 if (needs_ui_sequence(package))
7388 rc = ACTION_PerformUIAction(package, action, -1);
7390 rc = ACTION_PerformAction(package, action, -1);
7392 msiobj_release(&row->hdr);
7398 /****************************************************
7399 * TOP level entry points
7400 *****************************************************/
7402 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7403 LPCWSTR szCommandLine )
7408 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7409 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7411 msi_set_property( package->db, szAction, szInstall );
7413 package->script->InWhatSequence = SEQUENCE_INSTALL;
7420 dir = strdupW(szPackagePath);
7421 p = strrchrW(dir, '\\');
7425 file = szPackagePath + (p - dir);
7430 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7431 GetCurrentDirectoryW(MAX_PATH, dir);
7432 lstrcatW(dir, szBackSlash);
7433 file = szPackagePath;
7436 msi_free( package->PackagePath );
7437 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7438 if (!package->PackagePath)
7441 return ERROR_OUTOFMEMORY;
7444 lstrcpyW(package->PackagePath, dir);
7445 lstrcatW(package->PackagePath, file);
7448 msi_set_sourcedir_props(package, FALSE);
7451 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7452 if (rc != ERROR_SUCCESS)
7455 msi_apply_transforms( package );
7456 msi_apply_patches( package );
7458 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7460 TRACE("setting reinstall property\n");
7461 msi_set_property( package->db, szReinstall, szAll );
7464 /* properties may have been added by a transform */
7465 msi_clone_properties( package );
7467 msi_parse_command_line( package, szCommandLine, FALSE );
7468 msi_adjust_privilege_properties( package );
7469 msi_set_context( package );
7471 if (needs_ui_sequence( package))
7473 package->script->InWhatSequence |= SEQUENCE_UI;
7474 rc = ACTION_ProcessUISequence(package);
7475 ui_exists = ui_sequence_exists(package);
7476 if (rc == ERROR_SUCCESS || !ui_exists)
7478 package->script->InWhatSequence |= SEQUENCE_EXEC;
7479 rc = ACTION_ProcessExecSequence(package, ui_exists);
7483 rc = ACTION_ProcessExecSequence(package, FALSE);
7485 package->script->CurrentlyScripting = FALSE;
7487 /* process the ending type action */
7488 if (rc == ERROR_SUCCESS)
7489 ACTION_PerformActionSequence(package, -1);
7490 else if (rc == ERROR_INSTALL_USEREXIT)
7491 ACTION_PerformActionSequence(package, -2);
7492 else if (rc == ERROR_INSTALL_SUSPEND)
7493 ACTION_PerformActionSequence(package, -4);
7495 ACTION_PerformActionSequence(package, -3);
7497 /* finish up running custom actions */
7498 ACTION_FinishCustomActions(package);
7500 if (rc == ERROR_SUCCESS && package->need_reboot)
7501 return ERROR_SUCCESS_REBOOT_REQUIRED;