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 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2243 msi_parse_version_string( ver1, &ms1, NULL );
2244 msi_parse_version_string( ver2, &ms2, NULL );
2246 if (ms1 > ms2) return 1;
2247 else if (ms1 < ms2) return -1;
2251 static DWORD get_disk_file_size( LPCWSTR filename )
2256 TRACE("%s\n", debugstr_w(filename));
2258 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2259 if (file == INVALID_HANDLE_VALUE)
2260 return INVALID_FILE_SIZE;
2262 size = GetFileSize( file, NULL );
2263 CloseHandle( file );
2267 static BOOL hash_matches( MSIFILE *file )
2270 MSIFILEHASHINFO hash;
2272 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2273 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2274 if (r != ERROR_SUCCESS)
2277 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2280 static WCHAR *get_temp_dir( void )
2283 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2285 GetTempPathW( MAX_PATH, tmp );
2288 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2289 if (CreateDirectoryW( dir, NULL )) break;
2291 return strdupW( dir );
2294 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2296 MSIASSEMBLY *assembly = file->Component->assembly;
2298 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2300 msi_free( file->TargetPath );
2301 if (assembly && !assembly->application)
2303 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2304 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2305 track_tempfile( package, file->TargetPath );
2309 WCHAR *dir = resolve_folder( package, file->Component->Directory, FALSE, FALSE, TRUE, NULL );
2310 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2314 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2317 static UINT set_file_install_states( MSIPACKAGE *package )
2319 VS_FIXEDFILEINFO *file_version;
2320 WCHAR *font_version;
2323 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2325 MSICOMPONENT *comp = file->Component;
2328 if (!comp->Enabled) continue;
2330 if (file->IsCompressed)
2331 comp->ForceLocalState = TRUE;
2333 set_target_path( package, file );
2335 if ((comp->assembly && !comp->assembly->installed) ||
2336 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2338 file->state = msifs_missing;
2339 comp->Cost += file->FileSize;
2344 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2346 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2347 HIWORD(file_version->dwFileVersionMS),
2348 LOWORD(file_version->dwFileVersionMS),
2349 HIWORD(file_version->dwFileVersionLS),
2350 LOWORD(file_version->dwFileVersionLS));
2352 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2354 file->state = msifs_overwrite;
2355 comp->Cost += file->FileSize;
2359 TRACE("Destination file version equal or greater, not overwriting\n");
2360 file->state = msifs_present;
2362 msi_free( file_version );
2365 else if ((font_version = font_version_from_file( file->TargetPath )))
2367 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version));
2369 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2371 file->state = msifs_overwrite;
2372 comp->Cost += file->FileSize;
2376 TRACE("Destination file version equal or greater, not overwriting\n");
2377 file->state = msifs_present;
2379 msi_free( font_version );
2383 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2385 file->state = msifs_overwrite;
2386 comp->Cost += file->FileSize - file_size;
2389 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2391 TRACE("File hashes match, not overwriting\n");
2392 file->state = msifs_present;
2395 file->state = msifs_overwrite;
2396 comp->Cost += file->FileSize - file_size;
2399 return ERROR_SUCCESS;
2403 * A lot is done in this function aside from just the costing.
2404 * The costing needs to be implemented at some point but for now I am going
2405 * to focus on the directory building
2408 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2410 static const WCHAR ExecSeqQuery[] =
2411 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2412 '`','D','i','r','e','c','t','o','r','y','`',0};
2413 static const WCHAR ConditionQuery[] =
2414 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2415 '`','C','o','n','d','i','t','i','o','n','`',0};
2416 static const WCHAR szCosting[] =
2417 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2418 static const WCHAR szlevel[] =
2419 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2420 static const WCHAR szOutOfDiskSpace[] =
2421 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2423 UINT rc = ERROR_SUCCESS;
2427 TRACE("Building Directory properties\n");
2429 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2430 if (rc == ERROR_SUCCESS)
2432 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2434 msiobj_release(&view->hdr);
2437 TRACE("Evaluating component conditions\n");
2438 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2440 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2442 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2443 comp->Enabled = FALSE;
2446 comp->Enabled = TRUE;
2449 /* read components states from the registry */
2450 ACTION_GetComponentInstallStates(package);
2451 ACTION_GetFeatureInstallStates(package);
2453 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2455 TRACE("Evaluating feature conditions\n");
2457 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2458 if (rc == ERROR_SUCCESS)
2460 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2461 msiobj_release( &view->hdr );
2465 TRACE("Calculating file install states\n");
2466 set_file_install_states( package );
2468 msi_set_property( package->db, szCosting, szOne );
2469 /* set default run level if not set */
2470 level = msi_dup_property( package->db, szlevel );
2472 msi_set_property( package->db, szlevel, szOne );
2475 /* FIXME: check volume disk space */
2476 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2478 return MSI_SetFeatureStates(package);
2481 /* OK this value is "interpreted" and then formatted based on the
2482 first few characters */
2483 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2488 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2494 LPWSTR deformated = NULL;
2497 deformat_string(package, &value[2], &deformated);
2499 /* binary value type */
2503 *size = (strlenW(ptr)/2)+1;
2505 *size = strlenW(ptr)/2;
2507 data = msi_alloc(*size);
2513 /* if uneven pad with a zero in front */
2519 data[count] = (BYTE)strtol(byte,NULL,0);
2521 TRACE("Uneven byte count\n");
2529 data[count] = (BYTE)strtol(byte,NULL,0);
2532 msi_free(deformated);
2534 TRACE("Data %i bytes(%i)\n",*size,count);
2541 deformat_string(package, &value[1], &deformated);
2544 *size = sizeof(DWORD);
2545 data = msi_alloc(*size);
2551 if ( (*p < '0') || (*p > '9') )
2557 if (deformated[0] == '-')
2560 TRACE("DWORD %i\n",*(LPDWORD)data);
2562 msi_free(deformated);
2567 static const WCHAR szMulti[] = {'[','~',']',0};
2576 *type=REG_EXPAND_SZ;
2584 if (strstrW(value, szMulti))
2585 *type = REG_MULTI_SZ;
2587 /* remove initial delimiter */
2588 if (!strncmpW(value, szMulti, 3))
2591 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2593 /* add double NULL terminator */
2594 if (*type == REG_MULTI_SZ)
2596 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2597 data = msi_realloc_zero(data, *size);
2603 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2610 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2612 *root_key = HKEY_LOCAL_MACHINE;
2617 *root_key = HKEY_CURRENT_USER;
2622 *root_key = HKEY_CLASSES_ROOT;
2626 *root_key = HKEY_CURRENT_USER;
2630 *root_key = HKEY_LOCAL_MACHINE;
2634 *root_key = HKEY_USERS;
2638 ERR("Unknown root %i\n", root);
2645 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2647 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2648 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2650 if (is_64bit && package->platform == PLATFORM_INTEL &&
2651 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2656 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2657 path_32node = msi_alloc( size );
2661 memcpy( path_32node, path, len * sizeof(WCHAR) );
2662 path_32node[len] = 0;
2663 strcatW( path_32node, szWow6432Node );
2664 strcatW( path_32node, szBackSlash );
2665 strcatW( path_32node, path + len );
2669 return strdupW( path );
2672 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2674 MSIPACKAGE *package = param;
2675 LPSTR value_data = NULL;
2676 HKEY root_key, hkey;
2678 LPWSTR deformated, uikey, keypath;
2679 LPCWSTR szRoot, component, name, key, value;
2683 BOOL check_first = FALSE;
2686 ui_progress(package,2,0,0,0);
2688 component = MSI_RecordGetString(row, 6);
2689 comp = get_loaded_component(package,component);
2691 return ERROR_SUCCESS;
2695 TRACE("component is disabled\n");
2696 return ERROR_SUCCESS;
2699 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2701 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2702 comp->Action = comp->Installed;
2703 return ERROR_SUCCESS;
2705 comp->Action = INSTALLSTATE_LOCAL;
2707 name = MSI_RecordGetString(row, 4);
2708 if( MSI_RecordIsNull(row,5) && name )
2710 /* null values can have special meanings */
2711 if (name[0]=='-' && name[1] == 0)
2712 return ERROR_SUCCESS;
2713 else if ((name[0]=='+' && name[1] == 0) ||
2714 (name[0] == '*' && name[1] == 0))
2719 root = MSI_RecordGetInteger(row,2);
2720 key = MSI_RecordGetString(row, 3);
2722 szRoot = get_root_key( package, root, &root_key );
2724 return ERROR_SUCCESS;
2726 deformat_string(package, key , &deformated);
2727 size = strlenW(deformated) + strlenW(szRoot) + 1;
2728 uikey = msi_alloc(size*sizeof(WCHAR));
2729 strcpyW(uikey,szRoot);
2730 strcatW(uikey,deformated);
2732 keypath = get_keypath( package, root_key, deformated );
2733 msi_free( deformated );
2734 if (RegCreateKeyW( root_key, keypath, &hkey ))
2736 ERR("Could not create key %s\n", debugstr_w(keypath));
2739 return ERROR_SUCCESS;
2742 value = MSI_RecordGetString(row,5);
2744 value_data = parse_value(package, value, &type, &size);
2747 value_data = (LPSTR)strdupW(szEmpty);
2748 size = sizeof(szEmpty);
2752 deformat_string(package, name, &deformated);
2756 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2758 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2763 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2764 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2766 TRACE("value %s of %s checked already exists\n",
2767 debugstr_w(deformated), debugstr_w(uikey));
2771 TRACE("Checked and setting value %s of %s\n",
2772 debugstr_w(deformated), debugstr_w(uikey));
2773 if (deformated || size)
2774 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2779 uirow = MSI_CreateRecord(3);
2780 MSI_RecordSetStringW(uirow,2,deformated);
2781 MSI_RecordSetStringW(uirow,1,uikey);
2782 if (type == REG_SZ || type == REG_EXPAND_SZ)
2783 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2784 ui_actiondata(package,szWriteRegistryValues,uirow);
2785 msiobj_release( &uirow->hdr );
2787 msi_free(value_data);
2788 msi_free(deformated);
2792 return ERROR_SUCCESS;
2795 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2799 static const WCHAR ExecSeqQuery[] =
2800 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2801 '`','R','e','g','i','s','t','r','y','`',0 };
2803 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2804 if (rc != ERROR_SUCCESS)
2805 return ERROR_SUCCESS;
2807 /* increment progress bar each time action data is sent */
2808 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2810 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2812 msiobj_release(&view->hdr);
2816 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2820 DWORD num_subkeys, num_values;
2824 if ((res = RegDeleteTreeW( hkey_root, key )))
2826 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2831 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2833 if ((res = RegDeleteValueW( hkey, value )))
2835 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2837 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2838 NULL, NULL, NULL, NULL );
2839 RegCloseKey( hkey );
2840 if (!res && !num_subkeys && !num_values)
2842 TRACE("Removing empty key %s\n", debugstr_w(key));
2843 RegDeleteKeyW( hkey_root, key );
2847 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2851 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2853 MSIPACKAGE *package = param;
2854 LPCWSTR component, name, key_str, root_key_str;
2855 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2858 BOOL delete_key = FALSE;
2863 ui_progress( package, 2, 0, 0, 0 );
2865 component = MSI_RecordGetString( row, 6 );
2866 comp = get_loaded_component( package, component );
2868 return ERROR_SUCCESS;
2872 TRACE("component is disabled\n");
2873 return ERROR_SUCCESS;
2876 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2878 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2879 comp->Action = comp->Installed;
2880 return ERROR_SUCCESS;
2882 comp->Action = INSTALLSTATE_ABSENT;
2884 name = MSI_RecordGetString( row, 4 );
2885 if (MSI_RecordIsNull( row, 5 ) && name )
2887 if (name[0] == '+' && !name[1])
2888 return ERROR_SUCCESS;
2889 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2896 root = MSI_RecordGetInteger( row, 2 );
2897 key_str = MSI_RecordGetString( row, 3 );
2899 root_key_str = get_root_key( package, root, &hkey_root );
2901 return ERROR_SUCCESS;
2903 deformat_string( package, key_str, &deformated_key );
2904 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2905 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2906 strcpyW( ui_key_str, root_key_str );
2907 strcatW( ui_key_str, deformated_key );
2909 deformat_string( package, name, &deformated_name );
2911 keypath = get_keypath( package, hkey_root, deformated_key );
2912 msi_free( deformated_key );
2913 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2914 msi_free( keypath );
2916 uirow = MSI_CreateRecord( 2 );
2917 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2918 MSI_RecordSetStringW( uirow, 2, deformated_name );
2920 ui_actiondata( package, szRemoveRegistryValues, uirow );
2921 msiobj_release( &uirow->hdr );
2923 msi_free( ui_key_str );
2924 msi_free( deformated_name );
2925 return ERROR_SUCCESS;
2928 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2930 MSIPACKAGE *package = param;
2931 LPCWSTR component, name, key_str, root_key_str;
2932 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2935 BOOL delete_key = FALSE;
2940 ui_progress( package, 2, 0, 0, 0 );
2942 component = MSI_RecordGetString( row, 5 );
2943 comp = get_loaded_component( package, component );
2945 return ERROR_SUCCESS;
2949 TRACE("component is disabled\n");
2950 return ERROR_SUCCESS;
2953 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2955 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2956 comp->Action = comp->Installed;
2957 return ERROR_SUCCESS;
2959 comp->Action = INSTALLSTATE_LOCAL;
2961 if ((name = MSI_RecordGetString( row, 4 )))
2963 if (name[0] == '-' && !name[1])
2970 root = MSI_RecordGetInteger( row, 2 );
2971 key_str = MSI_RecordGetString( row, 3 );
2973 root_key_str = get_root_key( package, root, &hkey_root );
2975 return ERROR_SUCCESS;
2977 deformat_string( package, key_str, &deformated_key );
2978 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2979 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2980 strcpyW( ui_key_str, root_key_str );
2981 strcatW( ui_key_str, deformated_key );
2983 deformat_string( package, name, &deformated_name );
2985 keypath = get_keypath( package, hkey_root, deformated_key );
2986 msi_free( deformated_key );
2987 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2988 msi_free( keypath );
2990 uirow = MSI_CreateRecord( 2 );
2991 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2992 MSI_RecordSetStringW( uirow, 2, deformated_name );
2994 ui_actiondata( package, szRemoveRegistryValues, uirow );
2995 msiobj_release( &uirow->hdr );
2997 msi_free( ui_key_str );
2998 msi_free( deformated_name );
2999 return ERROR_SUCCESS;
3002 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3006 static const WCHAR registry_query[] =
3007 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3008 '`','R','e','g','i','s','t','r','y','`',0 };
3009 static const WCHAR remove_registry_query[] =
3010 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3011 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
3013 /* increment progress bar each time action data is sent */
3014 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
3016 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3017 if (rc == ERROR_SUCCESS)
3019 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3020 msiobj_release( &view->hdr );
3021 if (rc != ERROR_SUCCESS)
3025 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3026 if (rc == ERROR_SUCCESS)
3028 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3029 msiobj_release( &view->hdr );
3030 if (rc != ERROR_SUCCESS)
3034 return ERROR_SUCCESS;
3037 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3039 package->script->CurrentlyScripting = TRUE;
3041 return ERROR_SUCCESS;
3045 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3050 static const WCHAR q1[]=
3051 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3052 '`','R','e','g','i','s','t','r','y','`',0};
3055 MSIFEATURE *feature;
3058 TRACE("InstallValidate\n");
3060 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3061 if (rc == ERROR_SUCCESS)
3063 MSI_IterateRecords( view, &progress, NULL, package );
3064 msiobj_release( &view->hdr );
3065 total += progress * REG_PROGRESS_VALUE;
3068 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3069 total += COMPONENT_PROGRESS_VALUE;
3071 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3072 total += file->FileSize;
3074 ui_progress(package,0,total,0,0);
3076 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3078 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3079 debugstr_w(feature->Feature), feature->Installed,
3080 feature->ActionRequest, feature->Action);
3083 return ERROR_SUCCESS;
3086 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3088 MSIPACKAGE* package = param;
3089 LPCWSTR cond = NULL;
3090 LPCWSTR message = NULL;
3093 static const WCHAR title[]=
3094 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3096 cond = MSI_RecordGetString(row,1);
3098 r = MSI_EvaluateConditionW(package,cond);
3099 if (r == MSICONDITION_FALSE)
3101 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3104 message = MSI_RecordGetString(row,2);
3105 deformat_string(package,message,&deformated);
3106 MessageBoxW(NULL,deformated,title,MB_OK);
3107 msi_free(deformated);
3110 return ERROR_INSTALL_FAILURE;
3113 return ERROR_SUCCESS;
3116 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3119 MSIQUERY * view = NULL;
3120 static const WCHAR ExecSeqQuery[] =
3121 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3122 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3124 TRACE("Checking launch conditions\n");
3126 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3127 if (rc != ERROR_SUCCESS)
3128 return ERROR_SUCCESS;
3130 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3131 msiobj_release(&view->hdr);
3136 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3140 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
3142 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3144 MSIRECORD * row = 0;
3146 LPWSTR deformated,buffer,deformated_name;
3148 static const WCHAR ExecSeqQuery[] =
3149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3150 '`','R','e','g','i','s','t','r','y','`',' ',
3151 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3152 ' ','=',' ' ,'\'','%','s','\'',0 };
3153 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3154 static const WCHAR fmt2[]=
3155 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3157 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3161 root = MSI_RecordGetInteger(row,2);
3162 key = MSI_RecordGetString(row, 3);
3163 name = MSI_RecordGetString(row, 4);
3164 deformat_string(package, key , &deformated);
3165 deformat_string(package, name, &deformated_name);
3167 len = strlenW(deformated) + 6;
3168 if (deformated_name)
3169 len+=strlenW(deformated_name);
3171 buffer = msi_alloc( len *sizeof(WCHAR));
3173 if (deformated_name)
3174 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3176 sprintfW(buffer,fmt,root,deformated);
3178 msi_free(deformated);
3179 msi_free(deformated_name);
3180 msiobj_release(&row->hdr);
3184 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3186 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3191 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3194 return strdupW( file->TargetPath );
3199 static HKEY openSharedDLLsKey(void)
3202 static const WCHAR path[] =
3203 {'S','o','f','t','w','a','r','e','\\',
3204 'M','i','c','r','o','s','o','f','t','\\',
3205 'W','i','n','d','o','w','s','\\',
3206 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3207 'S','h','a','r','e','d','D','L','L','s',0};
3209 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3213 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3218 DWORD sz = sizeof(count);
3221 hkey = openSharedDLLsKey();
3222 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3223 if (rc != ERROR_SUCCESS)
3229 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3233 hkey = openSharedDLLsKey();
3235 msi_reg_set_val_dword( hkey, path, count );
3237 RegDeleteValueW(hkey,path);
3243 * Return TRUE if the count should be written out and FALSE if not
3245 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3247 MSIFEATURE *feature;
3251 /* only refcount DLLs */
3252 if (comp->KeyPath == NULL ||
3253 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3254 comp->Attributes & msidbComponentAttributesODBCDataSource)
3258 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3259 write = (count > 0);
3261 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3265 /* increment counts */
3266 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3270 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3273 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3275 if ( cl->component == comp )
3280 /* decrement counts */
3281 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3285 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3288 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3290 if ( cl->component == comp )
3295 /* ref count all the files in the component */
3300 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3302 if (file->Component == comp)
3303 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3307 /* add a count for permanent */
3308 if (comp->Attributes & msidbComponentAttributesPermanent)
3311 comp->RefCount = count;
3314 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3317 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3319 WCHAR squished_pc[GUID_SIZE];
3320 WCHAR squished_cc[GUID_SIZE];
3327 squash_guid(package->ProductCode,squished_pc);
3328 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3330 msi_set_sourcedir_props(package, FALSE);
3332 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3336 ui_progress(package,2,0,0,0);
3337 if (!comp->ComponentId)
3340 squash_guid(comp->ComponentId,squished_cc);
3342 msi_free(comp->FullKeypath);
3343 comp->FullKeypath = resolve_keypath( package, comp );
3345 ACTION_RefCountComponent( package, comp );
3347 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3348 debugstr_w(comp->Component),
3349 debugstr_w(squished_cc),
3350 debugstr_w(comp->FullKeypath),
3352 comp->ActionRequest);
3354 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3355 comp->ActionRequest == INSTALLSTATE_SOURCE)
3357 if (!comp->FullKeypath)
3360 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3361 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3364 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3367 if (rc != ERROR_SUCCESS)
3370 if (comp->Attributes & msidbComponentAttributesPermanent)
3372 static const WCHAR szPermKey[] =
3373 { '0','0','0','0','0','0','0','0','0','0','0','0',
3374 '0','0','0','0','0','0','0','0','0','0','0','0',
3375 '0','0','0','0','0','0','0','0',0 };
3377 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3380 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3381 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3387 WCHAR source[MAX_PATH];
3388 WCHAR base[MAX_PATH];
3391 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3392 static const WCHAR query[] = {
3393 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3394 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3395 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3396 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3397 '`','D','i','s','k','I','d','`',0};
3399 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3402 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3403 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3404 ptr2 = strrchrW(source, '\\') + 1;
3405 msiobj_release(&row->hdr);
3407 lstrcpyW(base, package->PackagePath);
3408 ptr = strrchrW(base, '\\');
3411 sourcepath = resolve_file_source(package, file);
3412 ptr = sourcepath + lstrlenW(base);
3413 lstrcpyW(ptr2, ptr);
3414 msi_free(sourcepath);
3416 msi_reg_set_val_str(hkey, squished_pc, source);
3420 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3422 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3423 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3425 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3427 comp->Action = comp->ActionRequest;
3430 uirow = MSI_CreateRecord(3);
3431 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3432 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3433 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3434 ui_actiondata(package,szProcessComponents,uirow);
3435 msiobj_release( &uirow->hdr );
3438 return ERROR_SUCCESS;
3449 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3450 LPWSTR lpszName, LONG_PTR lParam)
3453 typelib_struct *tl_struct = (typelib_struct*) lParam;
3454 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3458 if (!IS_INTRESOURCE(lpszName))
3460 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3464 sz = strlenW(tl_struct->source)+4;
3465 sz *= sizeof(WCHAR);
3467 if ((INT_PTR)lpszName == 1)
3468 tl_struct->path = strdupW(tl_struct->source);
3471 tl_struct->path = msi_alloc(sz);
3472 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3475 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3476 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3479 msi_free(tl_struct->path);
3480 tl_struct->path = NULL;
3485 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3486 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3488 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3492 msi_free(tl_struct->path);
3493 tl_struct->path = NULL;
3495 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3496 ITypeLib_Release(tl_struct->ptLib);
3501 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3503 MSIPACKAGE* package = param;
3507 typelib_struct tl_struct;
3512 component = MSI_RecordGetString(row,3);
3513 comp = get_loaded_component(package,component);
3515 return ERROR_SUCCESS;
3519 TRACE("component is disabled\n");
3520 return ERROR_SUCCESS;
3523 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3525 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3526 comp->Action = comp->Installed;
3527 return ERROR_SUCCESS;
3529 comp->Action = INSTALLSTATE_LOCAL;
3531 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3533 TRACE("component has no key path\n");
3534 return ERROR_SUCCESS;
3536 ui_actiondata( package, szRegisterTypeLibraries, row );
3538 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3542 guid = MSI_RecordGetString(row,1);
3543 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3544 tl_struct.source = strdupW( file->TargetPath );
3545 tl_struct.path = NULL;
3547 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3548 (LONG_PTR)&tl_struct);
3556 helpid = MSI_RecordGetString(row,6);
3559 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3560 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3564 ERR("Failed to register type library %s\n",
3565 debugstr_w(tl_struct.path));
3567 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3569 ITypeLib_Release(tl_struct.ptLib);
3570 msi_free(tl_struct.path);
3573 ERR("Failed to load type library %s\n",
3574 debugstr_w(tl_struct.source));
3576 FreeLibrary(module);
3577 msi_free(tl_struct.source);
3581 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3584 ERR("Failed to load type library: %08x\n", hr);
3585 return ERROR_INSTALL_FAILURE;
3588 ITypeLib_Release(tlib);
3591 return ERROR_SUCCESS;
3594 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3597 * OK this is a bit confusing.. I am given a _Component key and I believe
3598 * that the file that is being registered as a type library is the "key file
3599 * of that component" which I interpret to mean "The file in the KeyPath of
3604 static const WCHAR Query[] =
3605 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3606 '`','T','y','p','e','L','i','b','`',0};
3608 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3609 if (rc != ERROR_SUCCESS)
3610 return ERROR_SUCCESS;
3612 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3613 msiobj_release(&view->hdr);
3617 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3619 MSIPACKAGE *package = param;
3620 LPCWSTR component, guid;
3628 component = MSI_RecordGetString( row, 3 );
3629 comp = get_loaded_component( package, component );
3631 return ERROR_SUCCESS;
3635 TRACE("component is disabled\n");
3636 return ERROR_SUCCESS;
3639 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3641 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3642 comp->Action = comp->Installed;
3643 return ERROR_SUCCESS;
3645 comp->Action = INSTALLSTATE_ABSENT;
3647 ui_actiondata( package, szUnregisterTypeLibraries, row );
3649 guid = MSI_RecordGetString( row, 1 );
3650 CLSIDFromString( (LPCWSTR)guid, &libid );
3651 version = MSI_RecordGetInteger( row, 4 );
3652 language = MSI_RecordGetInteger( row, 2 );
3655 syskind = SYS_WIN64;
3657 syskind = SYS_WIN32;
3660 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3663 WARN("Failed to unregister typelib: %08x\n", hr);
3666 return ERROR_SUCCESS;
3669 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3673 static const WCHAR query[] =
3674 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3675 '`','T','y','p','e','L','i','b','`',0};
3677 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3678 if (rc != ERROR_SUCCESS)
3679 return ERROR_SUCCESS;
3681 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3682 msiobj_release( &view->hdr );
3686 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3688 static const WCHAR szlnk[] = {'.','l','n','k',0};
3689 LPCWSTR directory, extension;
3690 LPWSTR link_folder, link_file, filename;
3692 directory = MSI_RecordGetString( row, 2 );
3693 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3695 /* may be needed because of a bug somewhere else */
3696 create_full_pathW( link_folder );
3698 filename = msi_dup_record_field( row, 3 );
3699 reduce_to_longfilename( filename );
3701 extension = strchrW( filename, '.' );
3702 if (!extension || strcmpiW( extension, szlnk ))
3704 int len = strlenW( filename );
3705 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3706 memcpy( filename + len, szlnk, sizeof(szlnk) );
3708 link_file = build_directory_name( 2, link_folder, filename );
3709 msi_free( link_folder );
3710 msi_free( filename );
3715 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3717 MSIPACKAGE *package = param;
3718 LPWSTR link_file, deformated, path;
3719 LPCWSTR component, target;
3721 IShellLinkW *sl = NULL;
3722 IPersistFile *pf = NULL;
3725 component = MSI_RecordGetString(row, 4);
3726 comp = get_loaded_component(package, component);
3728 return ERROR_SUCCESS;
3732 TRACE("component is disabled\n");
3733 return ERROR_SUCCESS;
3736 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3738 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3739 comp->Action = comp->Installed;
3740 return ERROR_SUCCESS;
3742 comp->Action = INSTALLSTATE_LOCAL;
3744 ui_actiondata(package,szCreateShortcuts,row);
3746 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3747 &IID_IShellLinkW, (LPVOID *) &sl );
3751 ERR("CLSID_ShellLink not available\n");
3755 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3758 ERR("QueryInterface(IID_IPersistFile) failed\n");
3762 target = MSI_RecordGetString(row, 5);
3763 if (strchrW(target, '['))
3765 deformat_string(package, target, &deformated);
3766 IShellLinkW_SetPath(sl,deformated);
3767 msi_free(deformated);
3771 FIXME("poorly handled shortcut format, advertised shortcut\n");
3772 IShellLinkW_SetPath(sl,comp->FullKeypath);
3775 if (!MSI_RecordIsNull(row,6))
3777 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3778 deformat_string(package, arguments, &deformated);
3779 IShellLinkW_SetArguments(sl,deformated);
3780 msi_free(deformated);
3783 if (!MSI_RecordIsNull(row,7))
3785 LPCWSTR description = MSI_RecordGetString(row, 7);
3786 IShellLinkW_SetDescription(sl, description);
3789 if (!MSI_RecordIsNull(row,8))
3790 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3792 if (!MSI_RecordIsNull(row,9))
3795 LPCWSTR icon = MSI_RecordGetString(row, 9);
3797 path = build_icon_path(package, icon);
3798 index = MSI_RecordGetInteger(row,10);
3800 /* no value means 0 */
3801 if (index == MSI_NULL_INTEGER)
3804 IShellLinkW_SetIconLocation(sl, path, index);
3808 if (!MSI_RecordIsNull(row,11))
3809 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3811 if (!MSI_RecordIsNull(row,12))
3813 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3814 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3816 IShellLinkW_SetWorkingDirectory(sl, path);
3820 link_file = get_link_file(package, row);
3822 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3823 IPersistFile_Save(pf, link_file, FALSE);
3825 msi_free(link_file);
3829 IPersistFile_Release( pf );
3831 IShellLinkW_Release( sl );
3833 return ERROR_SUCCESS;
3836 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3841 static const WCHAR Query[] =
3842 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3843 '`','S','h','o','r','t','c','u','t','`',0};
3845 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3846 if (rc != ERROR_SUCCESS)
3847 return ERROR_SUCCESS;
3849 res = CoInitialize( NULL );
3851 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3852 msiobj_release(&view->hdr);
3860 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3862 MSIPACKAGE *package = param;
3867 component = MSI_RecordGetString( row, 4 );
3868 comp = get_loaded_component( package, component );
3870 return ERROR_SUCCESS;
3874 TRACE("component is disabled\n");
3875 return ERROR_SUCCESS;
3878 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3880 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3881 comp->Action = comp->Installed;
3882 return ERROR_SUCCESS;
3884 comp->Action = INSTALLSTATE_ABSENT;
3886 ui_actiondata( package, szRemoveShortcuts, row );
3888 link_file = get_link_file( package, row );
3890 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3891 if (!DeleteFileW( link_file ))
3893 WARN("Failed to remove shortcut file %u\n", GetLastError());
3895 msi_free( link_file );
3897 return ERROR_SUCCESS;
3900 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3904 static const WCHAR query[] =
3905 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3906 '`','S','h','o','r','t','c','u','t','`',0};
3908 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3909 if (rc != ERROR_SUCCESS)
3910 return ERROR_SUCCESS;
3912 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3913 msiobj_release( &view->hdr );
3918 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3920 MSIPACKAGE* package = param;
3928 FileName = MSI_RecordGetString(row,1);
3931 ERR("Unable to get FileName\n");
3932 return ERROR_SUCCESS;
3935 FilePath = build_icon_path(package,FileName);
3937 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3939 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3940 FILE_ATTRIBUTE_NORMAL, NULL);
3942 if (the_file == INVALID_HANDLE_VALUE)
3944 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3946 return ERROR_SUCCESS;
3953 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3954 if (rc != ERROR_SUCCESS)
3956 ERR("Failed to get stream\n");
3957 CloseHandle(the_file);
3958 DeleteFileW(FilePath);
3961 WriteFile(the_file,buffer,sz,&write,NULL);
3962 } while (sz == 1024);
3965 CloseHandle(the_file);
3967 return ERROR_SUCCESS;
3970 static UINT msi_publish_icons(MSIPACKAGE *package)
3975 static const WCHAR query[]= {
3976 'S','E','L','E','C','T',' ','*',' ',
3977 'F','R','O','M',' ','`','I','c','o','n','`',0};
3979 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3980 if (r == ERROR_SUCCESS)
3982 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3983 msiobj_release(&view->hdr);
3986 return ERROR_SUCCESS;
3989 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3995 MSISOURCELISTINFO *info;
3997 r = RegCreateKeyW(hkey, szSourceList, &source);
3998 if (r != ERROR_SUCCESS)
4001 RegCloseKey(source);
4003 buffer = strrchrW(package->PackagePath, '\\') + 1;
4004 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4005 package->Context, MSICODE_PRODUCT,
4006 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4007 if (r != ERROR_SUCCESS)
4010 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4011 package->Context, MSICODE_PRODUCT,
4012 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4013 if (r != ERROR_SUCCESS)
4016 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4017 package->Context, MSICODE_PRODUCT,
4018 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4019 if (r != ERROR_SUCCESS)
4022 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4024 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4025 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4026 info->options, info->value);
4028 MsiSourceListSetInfoW(package->ProductCode, NULL,
4029 info->context, info->options,
4030 info->property, info->value);
4033 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4035 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4036 disk->context, disk->options,
4037 disk->disk_id, disk->volume_label, disk->disk_prompt);
4040 return ERROR_SUCCESS;
4043 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4045 MSIHANDLE hdb, suminfo;
4046 WCHAR guids[MAX_PATH];
4047 WCHAR packcode[SQUISH_GUID_SIZE];
4054 static const WCHAR szProductLanguage[] =
4055 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4056 static const WCHAR szARPProductIcon[] =
4057 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4058 static const WCHAR szProductVersion[] =
4059 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4060 static const WCHAR szAssignment[] =
4061 {'A','s','s','i','g','n','m','e','n','t',0};
4062 static const WCHAR szAdvertiseFlags[] =
4063 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4064 static const WCHAR szClients[] =
4065 {'C','l','i','e','n','t','s',0};
4066 static const WCHAR szColon[] = {':',0};
4068 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4069 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4072 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4073 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4076 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4078 buffer = msi_dup_property(package->db, szARPProductIcon);
4081 LPWSTR path = build_icon_path(package,buffer);
4082 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4087 buffer = msi_dup_property(package->db, szProductVersion);
4090 DWORD verdword = msi_version_str_to_dword(buffer);
4091 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4095 msi_reg_set_val_dword(hkey, szAssignment, 0);
4096 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4097 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4098 msi_reg_set_val_str(hkey, szClients, szColon);
4100 hdb = alloc_msihandle(&package->db->hdr);
4102 return ERROR_NOT_ENOUGH_MEMORY;
4104 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4105 MsiCloseHandle(hdb);
4106 if (r != ERROR_SUCCESS)
4110 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4111 NULL, guids, &size);
4112 if (r != ERROR_SUCCESS)
4115 ptr = strchrW(guids, ';');
4117 squash_guid(guids, packcode);
4118 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4121 MsiCloseHandle(suminfo);
4122 return ERROR_SUCCESS;
4125 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4130 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4132 upgrade = msi_dup_property(package->db, szUpgradeCode);
4134 return ERROR_SUCCESS;
4136 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4138 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4139 if (r != ERROR_SUCCESS)
4144 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4145 if (r != ERROR_SUCCESS)
4149 squash_guid(package->ProductCode, squashed_pc);
4150 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4159 static BOOL msi_check_publish(MSIPACKAGE *package)
4161 MSIFEATURE *feature;
4163 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4165 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4172 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4174 MSIFEATURE *feature;
4176 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4178 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4185 static UINT msi_publish_patches( MSIPACKAGE *package )
4187 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4188 WCHAR patch_squashed[GUID_SIZE];
4189 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4191 MSIPATCHINFO *patch;
4193 WCHAR *p, *all_patches = NULL;
4196 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4197 if (r != ERROR_SUCCESS)
4198 return ERROR_FUNCTION_FAILED;
4200 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4201 if (res != ERROR_SUCCESS)
4203 r = ERROR_FUNCTION_FAILED;
4207 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4208 if (r != ERROR_SUCCESS)
4211 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4213 squash_guid( patch->patchcode, patch_squashed );
4214 len += strlenW( patch_squashed ) + 1;
4217 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4221 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4225 squash_guid( patch->patchcode, p );
4226 p += strlenW( p ) + 1;
4228 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4229 (const BYTE *)patch->transforms,
4230 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4231 if (res != ERROR_SUCCESS)
4234 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4235 if (r != ERROR_SUCCESS)
4238 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4239 (const BYTE *)patch->localfile,
4240 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4241 RegCloseKey( patch_key );
4242 if (res != ERROR_SUCCESS)
4245 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4246 if (res != ERROR_SUCCESS)
4249 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4250 RegCloseKey( patch_key );
4251 if (res != ERROR_SUCCESS)
4255 all_patches[len] = 0;
4256 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4257 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4258 if (res != ERROR_SUCCESS)
4261 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4262 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4263 if (res != ERROR_SUCCESS)
4264 r = ERROR_FUNCTION_FAILED;
4267 RegCloseKey( product_patches_key );
4268 RegCloseKey( patches_key );
4269 RegCloseKey( product_key );
4270 msi_free( all_patches );
4275 * 99% of the work done here is only done for
4276 * advertised installs. However this is where the
4277 * Icon table is processed and written out
4278 * so that is what I am going to do here.
4280 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4283 HKEY hukey = NULL, hudkey = NULL;
4286 if (!list_empty(&package->patches))
4288 rc = msi_publish_patches(package);
4289 if (rc != ERROR_SUCCESS)
4293 /* FIXME: also need to publish if the product is in advertise mode */
4294 if (!msi_check_publish(package))
4295 return ERROR_SUCCESS;
4297 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4299 if (rc != ERROR_SUCCESS)
4302 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4303 NULL, &hudkey, TRUE);
4304 if (rc != ERROR_SUCCESS)
4307 rc = msi_publish_upgrade_code(package);
4308 if (rc != ERROR_SUCCESS)
4311 rc = msi_publish_product_properties(package, hukey);
4312 if (rc != ERROR_SUCCESS)
4315 rc = msi_publish_sourcelist(package, hukey);
4316 if (rc != ERROR_SUCCESS)
4319 rc = msi_publish_icons(package);
4322 uirow = MSI_CreateRecord( 1 );
4323 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4324 ui_actiondata( package, szPublishProduct, uirow );
4325 msiobj_release( &uirow->hdr );
4328 RegCloseKey(hudkey);
4333 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4335 WCHAR *filename, *ptr, *folder, *ret;
4336 const WCHAR *dirprop;
4338 filename = msi_dup_record_field( row, 2 );
4339 if (filename && (ptr = strchrW( filename, '|' )))
4344 dirprop = MSI_RecordGetString( row, 3 );
4347 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4349 folder = msi_dup_property( package->db, dirprop );
4352 folder = msi_dup_property( package->db, szWindowsFolder );
4356 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4357 msi_free( filename );
4361 ret = build_directory_name( 2, folder, ptr );
4363 msi_free( filename );
4368 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4370 MSIPACKAGE *package = param;
4371 LPCWSTR component, section, key, value, identifier;
4372 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4377 component = MSI_RecordGetString(row, 8);
4378 comp = get_loaded_component(package,component);
4380 return ERROR_SUCCESS;
4384 TRACE("component is disabled\n");
4385 return ERROR_SUCCESS;
4388 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4390 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4391 comp->Action = comp->Installed;
4392 return ERROR_SUCCESS;
4394 comp->Action = INSTALLSTATE_LOCAL;
4396 identifier = MSI_RecordGetString(row,1);
4397 section = MSI_RecordGetString(row,4);
4398 key = MSI_RecordGetString(row,5);
4399 value = MSI_RecordGetString(row,6);
4400 action = MSI_RecordGetInteger(row,7);
4402 deformat_string(package,section,&deformated_section);
4403 deformat_string(package,key,&deformated_key);
4404 deformat_string(package,value,&deformated_value);
4406 fullname = get_ini_file_name(package, row);
4410 TRACE("Adding value %s to section %s in %s\n",
4411 debugstr_w(deformated_key), debugstr_w(deformated_section),
4412 debugstr_w(fullname));
4413 WritePrivateProfileStringW(deformated_section, deformated_key,
4414 deformated_value, fullname);
4416 else if (action == 1)
4419 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4420 returned, 10, fullname);
4421 if (returned[0] == 0)
4423 TRACE("Adding value %s to section %s in %s\n",
4424 debugstr_w(deformated_key), debugstr_w(deformated_section),
4425 debugstr_w(fullname));
4427 WritePrivateProfileStringW(deformated_section, deformated_key,
4428 deformated_value, fullname);
4431 else if (action == 3)
4432 FIXME("Append to existing section not yet implemented\n");
4434 uirow = MSI_CreateRecord(4);
4435 MSI_RecordSetStringW(uirow,1,identifier);
4436 MSI_RecordSetStringW(uirow,2,deformated_section);
4437 MSI_RecordSetStringW(uirow,3,deformated_key);
4438 MSI_RecordSetStringW(uirow,4,deformated_value);
4439 ui_actiondata(package,szWriteIniValues,uirow);
4440 msiobj_release( &uirow->hdr );
4443 msi_free(deformated_key);
4444 msi_free(deformated_value);
4445 msi_free(deformated_section);
4446 return ERROR_SUCCESS;
4449 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4453 static const WCHAR ExecSeqQuery[] =
4454 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4455 '`','I','n','i','F','i','l','e','`',0};
4457 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4458 if (rc != ERROR_SUCCESS)
4460 TRACE("no IniFile table\n");
4461 return ERROR_SUCCESS;
4464 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4465 msiobj_release(&view->hdr);
4469 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4471 MSIPACKAGE *package = param;
4472 LPCWSTR component, section, key, value, identifier;
4473 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4478 component = MSI_RecordGetString( row, 8 );
4479 comp = get_loaded_component( package, component );
4481 return ERROR_SUCCESS;
4485 TRACE("component is disabled\n");
4486 return ERROR_SUCCESS;
4489 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4491 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4492 comp->Action = comp->Installed;
4493 return ERROR_SUCCESS;
4495 comp->Action = INSTALLSTATE_ABSENT;
4497 identifier = MSI_RecordGetString( row, 1 );
4498 section = MSI_RecordGetString( row, 4 );
4499 key = MSI_RecordGetString( row, 5 );
4500 value = MSI_RecordGetString( row, 6 );
4501 action = MSI_RecordGetInteger( row, 7 );
4503 deformat_string( package, section, &deformated_section );
4504 deformat_string( package, key, &deformated_key );
4505 deformat_string( package, value, &deformated_value );
4507 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4509 filename = get_ini_file_name( package, row );
4511 TRACE("Removing key %s from section %s in %s\n",
4512 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4514 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4516 WARN("Unable to remove key %u\n", GetLastError());
4518 msi_free( filename );
4521 FIXME("Unsupported action %d\n", action);
4524 uirow = MSI_CreateRecord( 4 );
4525 MSI_RecordSetStringW( uirow, 1, identifier );
4526 MSI_RecordSetStringW( uirow, 2, deformated_section );
4527 MSI_RecordSetStringW( uirow, 3, deformated_key );
4528 MSI_RecordSetStringW( uirow, 4, deformated_value );
4529 ui_actiondata( package, szRemoveIniValues, uirow );
4530 msiobj_release( &uirow->hdr );
4532 msi_free( deformated_key );
4533 msi_free( deformated_value );
4534 msi_free( deformated_section );
4535 return ERROR_SUCCESS;
4538 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4540 MSIPACKAGE *package = param;
4541 LPCWSTR component, section, key, value, identifier;
4542 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4547 component = MSI_RecordGetString( row, 8 );
4548 comp = get_loaded_component( package, component );
4550 return ERROR_SUCCESS;
4554 TRACE("component is disabled\n");
4555 return ERROR_SUCCESS;
4558 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4560 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4561 comp->Action = comp->Installed;
4562 return ERROR_SUCCESS;
4564 comp->Action = INSTALLSTATE_LOCAL;
4566 identifier = MSI_RecordGetString( row, 1 );
4567 section = MSI_RecordGetString( row, 4 );
4568 key = MSI_RecordGetString( row, 5 );
4569 value = MSI_RecordGetString( row, 6 );
4570 action = MSI_RecordGetInteger( row, 7 );
4572 deformat_string( package, section, &deformated_section );
4573 deformat_string( package, key, &deformated_key );
4574 deformat_string( package, value, &deformated_value );
4576 if (action == msidbIniFileActionRemoveLine)
4578 filename = get_ini_file_name( package, row );
4580 TRACE("Removing key %s from section %s in %s\n",
4581 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4583 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4585 WARN("Unable to remove key %u\n", GetLastError());
4587 msi_free( filename );
4590 FIXME("Unsupported action %d\n", action);
4592 uirow = MSI_CreateRecord( 4 );
4593 MSI_RecordSetStringW( uirow, 1, identifier );
4594 MSI_RecordSetStringW( uirow, 2, deformated_section );
4595 MSI_RecordSetStringW( uirow, 3, deformated_key );
4596 MSI_RecordSetStringW( uirow, 4, deformated_value );
4597 ui_actiondata( package, szRemoveIniValues, uirow );
4598 msiobj_release( &uirow->hdr );
4600 msi_free( deformated_key );
4601 msi_free( deformated_value );
4602 msi_free( deformated_section );
4603 return ERROR_SUCCESS;
4606 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4610 static const WCHAR query[] =
4611 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4612 '`','I','n','i','F','i','l','e','`',0};
4613 static const WCHAR remove_query[] =
4614 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4615 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4617 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4618 if (rc == ERROR_SUCCESS)
4620 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4621 msiobj_release( &view->hdr );
4622 if (rc != ERROR_SUCCESS)
4626 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4627 if (rc == ERROR_SUCCESS)
4629 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4630 msiobj_release( &view->hdr );
4631 if (rc != ERROR_SUCCESS)
4635 return ERROR_SUCCESS;
4638 static void register_dll( const WCHAR *dll, BOOL unregister )
4642 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4645 HRESULT (WINAPI *func_ptr)( void );
4646 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4648 func_ptr = (void *)GetProcAddress( hmod, func );
4651 HRESULT hr = func_ptr();
4653 WARN("failed to register dll 0x%08x\n", hr);
4656 WARN("entry point %s not found\n", func);
4657 FreeLibrary( hmod );
4660 WARN("failed to load library %u\n", GetLastError());
4663 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4665 MSIPACKAGE *package = param;
4670 filename = MSI_RecordGetString(row,1);
4671 file = get_loaded_file( package, filename );
4675 ERR("Unable to find file id %s\n",debugstr_w(filename));
4676 return ERROR_SUCCESS;
4679 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4681 register_dll( file->TargetPath, FALSE );
4683 uirow = MSI_CreateRecord( 2 );
4684 MSI_RecordSetStringW( uirow, 1, filename );
4685 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4686 ui_actiondata( package, szSelfRegModules, uirow );
4687 msiobj_release( &uirow->hdr );
4689 return ERROR_SUCCESS;
4692 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4696 static const WCHAR ExecSeqQuery[] =
4697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4698 '`','S','e','l','f','R','e','g','`',0};
4700 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4701 if (rc != ERROR_SUCCESS)
4703 TRACE("no SelfReg table\n");
4704 return ERROR_SUCCESS;
4707 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4708 msiobj_release(&view->hdr);
4710 return ERROR_SUCCESS;
4713 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4715 MSIPACKAGE *package = param;
4720 filename = MSI_RecordGetString( row, 1 );
4721 file = get_loaded_file( package, filename );
4725 ERR("Unable to find file id %s\n", debugstr_w(filename));
4726 return ERROR_SUCCESS;
4729 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4731 register_dll( file->TargetPath, TRUE );
4733 uirow = MSI_CreateRecord( 2 );
4734 MSI_RecordSetStringW( uirow, 1, filename );
4735 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4736 ui_actiondata( package, szSelfUnregModules, uirow );
4737 msiobj_release( &uirow->hdr );
4739 return ERROR_SUCCESS;
4742 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4746 static const WCHAR query[] =
4747 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4748 '`','S','e','l','f','R','e','g','`',0};
4750 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4751 if (rc != ERROR_SUCCESS)
4753 TRACE("no SelfReg table\n");
4754 return ERROR_SUCCESS;
4757 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4758 msiobj_release( &view->hdr );
4760 return ERROR_SUCCESS;
4763 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4765 MSIFEATURE *feature;
4767 HKEY hkey = NULL, userdata = NULL;
4769 if (!msi_check_publish(package))
4770 return ERROR_SUCCESS;
4772 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4774 if (rc != ERROR_SUCCESS)
4777 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4779 if (rc != ERROR_SUCCESS)
4782 /* here the guids are base 85 encoded */
4783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4789 BOOL absent = FALSE;
4792 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4793 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4794 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4797 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4801 if (feature->Feature_Parent)
4802 size += strlenW( feature->Feature_Parent )+2;
4804 data = msi_alloc(size * sizeof(WCHAR));
4807 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4809 MSICOMPONENT* component = cl->component;
4813 if (component->ComponentId)
4815 TRACE("From %s\n",debugstr_w(component->ComponentId));
4816 CLSIDFromString(component->ComponentId, &clsid);
4817 encode_base85_guid(&clsid,buf);
4818 TRACE("to %s\n",debugstr_w(buf));
4823 if (feature->Feature_Parent)
4825 static const WCHAR sep[] = {'\2',0};
4827 strcatW(data,feature->Feature_Parent);
4830 msi_reg_set_val_str( userdata, feature->Feature, data );
4834 if (feature->Feature_Parent)
4835 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4838 size += sizeof(WCHAR);
4839 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4840 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4844 size += 2*sizeof(WCHAR);
4845 data = msi_alloc(size);
4848 if (feature->Feature_Parent)
4849 strcpyW( &data[1], feature->Feature_Parent );
4850 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4856 uirow = MSI_CreateRecord( 1 );
4857 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4858 ui_actiondata( package, szPublishFeatures, uirow);
4859 msiobj_release( &uirow->hdr );
4860 /* FIXME: call ui_progress? */
4865 RegCloseKey(userdata);
4869 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4875 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4877 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4879 if (r == ERROR_SUCCESS)
4881 RegDeleteValueW(hkey, feature->Feature);
4885 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4887 if (r == ERROR_SUCCESS)
4889 RegDeleteValueW(hkey, feature->Feature);
4893 uirow = MSI_CreateRecord( 1 );
4894 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4895 ui_actiondata( package, szUnpublishFeatures, uirow );
4896 msiobj_release( &uirow->hdr );
4898 return ERROR_SUCCESS;
4901 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4903 MSIFEATURE *feature;
4905 if (!msi_check_unpublish(package))
4906 return ERROR_SUCCESS;
4908 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4910 msi_unpublish_feature(package, feature);
4913 return ERROR_SUCCESS;
4916 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4920 WCHAR date[9], *val, *buffer;
4921 const WCHAR *prop, *key;
4923 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4924 static const WCHAR szWindowsInstaller[] =
4925 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4926 static const WCHAR modpath_fmt[] =
4927 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4928 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4929 static const WCHAR szModifyPath[] =
4930 {'M','o','d','i','f','y','P','a','t','h',0};
4931 static const WCHAR szUninstallString[] =
4932 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4933 static const WCHAR szEstimatedSize[] =
4934 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4935 static const WCHAR szProductLanguage[] =
4936 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4937 static const WCHAR szProductVersion[] =
4938 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4939 static const WCHAR szDisplayVersion[] =
4940 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4941 static const WCHAR szInstallSource[] =
4942 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4943 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4944 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4945 static const WCHAR szAuthorizedCDFPrefix[] =
4946 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4947 static const WCHAR szARPCONTACT[] =
4948 {'A','R','P','C','O','N','T','A','C','T',0};
4949 static const WCHAR szContact[] =
4950 {'C','o','n','t','a','c','t',0};
4951 static const WCHAR szARPCOMMENTS[] =
4952 {'A','R','P','C','O','M','M','E','N','T','S',0};
4953 static const WCHAR szComments[] =
4954 {'C','o','m','m','e','n','t','s',0};
4955 static const WCHAR szProductName[] =
4956 {'P','r','o','d','u','c','t','N','a','m','e',0};
4957 static const WCHAR szDisplayName[] =
4958 {'D','i','s','p','l','a','y','N','a','m','e',0};
4959 static const WCHAR szARPHELPLINK[] =
4960 {'A','R','P','H','E','L','P','L','I','N','K',0};
4961 static const WCHAR szHelpLink[] =
4962 {'H','e','l','p','L','i','n','k',0};
4963 static const WCHAR szARPHELPTELEPHONE[] =
4964 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4965 static const WCHAR szHelpTelephone[] =
4966 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4967 static const WCHAR szARPINSTALLLOCATION[] =
4968 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4969 static const WCHAR szInstallLocation[] =
4970 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4971 static const WCHAR szManufacturer[] =
4972 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4973 static const WCHAR szPublisher[] =
4974 {'P','u','b','l','i','s','h','e','r',0};
4975 static const WCHAR szARPREADME[] =
4976 {'A','R','P','R','E','A','D','M','E',0};
4977 static const WCHAR szReadme[] =
4978 {'R','e','a','d','M','e',0};
4979 static const WCHAR szARPSIZE[] =
4980 {'A','R','P','S','I','Z','E',0};
4981 static const WCHAR szSize[] =
4982 {'S','i','z','e',0};
4983 static const WCHAR szARPURLINFOABOUT[] =
4984 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4985 static const WCHAR szURLInfoAbout[] =
4986 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4987 static const WCHAR szARPURLUPDATEINFO[] =
4988 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4989 static const WCHAR szURLUpdateInfo[] =
4990 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4992 static const WCHAR *propval[] = {
4993 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4994 szARPCONTACT, szContact,
4995 szARPCOMMENTS, szComments,
4996 szProductName, szDisplayName,
4997 szARPHELPLINK, szHelpLink,
4998 szARPHELPTELEPHONE, szHelpTelephone,
4999 szARPINSTALLLOCATION, szInstallLocation,
5000 cszSourceDir, szInstallSource,
5001 szManufacturer, szPublisher,
5002 szARPREADME, szReadme,
5004 szARPURLINFOABOUT, szURLInfoAbout,
5005 szARPURLUPDATEINFO, szURLUpdateInfo,
5008 const WCHAR **p = propval;
5014 val = msi_dup_property(package->db, prop);
5015 msi_reg_set_val_str(hkey, key, val);
5019 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5021 size = deformat_string(package, modpath_fmt, &buffer);
5022 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5023 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5026 /* FIXME: Write real Estimated Size when we have it */
5027 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5029 GetLocalTime(&systime);
5030 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5031 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5033 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5034 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5036 buffer = msi_dup_property(package->db, szProductVersion);
5037 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5040 DWORD verdword = msi_version_str_to_dword(buffer);
5042 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5043 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5044 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5048 return ERROR_SUCCESS;
5051 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5053 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5055 LPWSTR upgrade_code;
5060 /* FIXME: also need to publish if the product is in advertise mode */
5061 if (!msi_check_publish(package))
5062 return ERROR_SUCCESS;
5064 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
5065 if (rc != ERROR_SUCCESS)
5068 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5069 NULL, &props, TRUE);
5070 if (rc != ERROR_SUCCESS)
5073 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5074 msi_free( package->db->localfile );
5075 package->db->localfile = NULL;
5077 rc = msi_publish_install_properties(package, hkey);
5078 if (rc != ERROR_SUCCESS)
5081 rc = msi_publish_install_properties(package, props);
5082 if (rc != ERROR_SUCCESS)
5085 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5088 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5089 squash_guid(package->ProductCode, squashed_pc);
5090 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5091 RegCloseKey(upgrade);
5092 msi_free(upgrade_code);
5096 uirow = MSI_CreateRecord( 1 );
5097 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5098 ui_actiondata( package, szRegisterProduct, uirow );
5099 msiobj_release( &uirow->hdr );
5102 return ERROR_SUCCESS;
5105 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5107 return execute_script(package,INSTALL_SCRIPT);
5110 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5112 WCHAR *upgrade, **features;
5113 BOOL full_uninstall = TRUE;
5114 MSIFEATURE *feature;
5115 MSIPATCHINFO *patch;
5117 static const WCHAR szUpgradeCode[] =
5118 {'U','p','g','r','a','d','e','C','o','d','e',0};
5120 features = msi_split_string(remove, ',');
5123 ERR("REMOVE feature list is empty!\n");
5124 return ERROR_FUNCTION_FAILED;
5127 if (!strcmpW( features[0], szAll ))
5128 full_uninstall = TRUE;
5131 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5133 if (feature->Action != INSTALLSTATE_ABSENT)
5134 full_uninstall = FALSE;
5139 if (!full_uninstall)
5140 return ERROR_SUCCESS;
5142 MSIREG_DeleteProductKey(package->ProductCode);
5143 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5144 MSIREG_DeleteUninstallKey(package);
5146 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
5148 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5149 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5153 MSIREG_DeleteUserProductKey(package->ProductCode);
5154 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5157 upgrade = msi_dup_property(package->db, szUpgradeCode);
5160 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5164 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5166 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5169 return ERROR_SUCCESS;
5172 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5177 /* turn off scheduling */
5178 package->script->CurrentlyScripting= FALSE;
5180 /* first do the same as an InstallExecute */
5181 rc = ACTION_InstallExecute(package);
5182 if (rc != ERROR_SUCCESS)
5185 /* then handle Commit Actions */
5186 rc = execute_script(package,COMMIT_SCRIPT);
5187 if (rc != ERROR_SUCCESS)
5190 remove = msi_dup_property(package->db, szRemove);
5192 rc = msi_unpublish_product(package, remove);
5198 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5200 static const WCHAR RunOnce[] = {
5201 'S','o','f','t','w','a','r','e','\\',
5202 'M','i','c','r','o','s','o','f','t','\\',
5203 'W','i','n','d','o','w','s','\\',
5204 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5205 'R','u','n','O','n','c','e',0};
5206 static const WCHAR InstallRunOnce[] = {
5207 'S','o','f','t','w','a','r','e','\\',
5208 'M','i','c','r','o','s','o','f','t','\\',
5209 'W','i','n','d','o','w','s','\\',
5210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5211 'I','n','s','t','a','l','l','e','r','\\',
5212 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5214 static const WCHAR msiexec_fmt[] = {
5216 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5217 '\"','%','s','\"',0};
5218 static const WCHAR install_fmt[] = {
5219 '/','I',' ','\"','%','s','\"',' ',
5220 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5221 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5222 WCHAR buffer[256], sysdir[MAX_PATH];
5224 WCHAR squished_pc[100];
5226 squash_guid(package->ProductCode,squished_pc);
5228 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5229 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5230 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5233 msi_reg_set_val_str( hkey, squished_pc, buffer );
5236 TRACE("Reboot command %s\n",debugstr_w(buffer));
5238 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5239 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5241 msi_reg_set_val_str( hkey, squished_pc, buffer );
5244 return ERROR_INSTALL_SUSPEND;
5247 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5253 * We are currently doing what should be done here in the top level Install
5254 * however for Administrative and uninstalls this step will be needed
5256 if (!package->PackagePath)
5257 return ERROR_SUCCESS;
5259 msi_set_sourcedir_props(package, TRUE);
5261 attrib = GetFileAttributesW(package->db->path);
5262 if (attrib == INVALID_FILE_ATTRIBUTES)
5268 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5269 package->Context, MSICODE_PRODUCT,
5270 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5271 if (rc == ERROR_MORE_DATA)
5273 prompt = msi_alloc(size * sizeof(WCHAR));
5274 MsiSourceListGetInfoW(package->ProductCode, NULL,
5275 package->Context, MSICODE_PRODUCT,
5276 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5279 prompt = strdupW(package->db->path);
5281 msg = generate_error_string(package,1302,1,prompt);
5282 while(attrib == INVALID_FILE_ATTRIBUTES)
5284 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5287 rc = ERROR_INSTALL_USEREXIT;
5290 attrib = GetFileAttributesW(package->db->path);
5296 return ERROR_SUCCESS;
5301 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5304 LPWSTR buffer, productid = NULL;
5305 UINT i, rc = ERROR_SUCCESS;
5308 static const WCHAR szPropKeys[][80] =
5310 {'P','r','o','d','u','c','t','I','D',0},
5311 {'U','S','E','R','N','A','M','E',0},
5312 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5316 static const WCHAR szRegKeys[][80] =
5318 {'P','r','o','d','u','c','t','I','D',0},
5319 {'R','e','g','O','w','n','e','r',0},
5320 {'R','e','g','C','o','m','p','a','n','y',0},
5324 if (msi_check_unpublish(package))
5326 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5330 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5334 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5336 if (rc != ERROR_SUCCESS)
5339 for( i = 0; szPropKeys[i][0]; i++ )
5341 buffer = msi_dup_property( package->db, szPropKeys[i] );
5342 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5347 uirow = MSI_CreateRecord( 1 );
5348 MSI_RecordSetStringW( uirow, 1, productid );
5349 ui_actiondata( package, szRegisterUser, uirow );
5350 msiobj_release( &uirow->hdr );
5352 msi_free(productid);
5358 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5362 package->script->InWhatSequence |= SEQUENCE_EXEC;
5363 rc = ACTION_ProcessExecSequence(package,FALSE);
5368 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5370 MSIPACKAGE *package = param;
5371 LPCWSTR compgroupid, component, feature, qualifier, text;
5372 LPWSTR advertise = NULL, output = NULL;
5380 feature = MSI_RecordGetString(rec, 5);
5381 feat = get_loaded_feature(package, feature);
5383 return ERROR_SUCCESS;
5385 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5386 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5387 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5389 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5390 feat->Action = feat->Installed;
5391 return ERROR_SUCCESS;
5394 component = MSI_RecordGetString(rec, 3);
5395 comp = get_loaded_component(package, component);
5397 return ERROR_SUCCESS;
5399 compgroupid = MSI_RecordGetString(rec,1);
5400 qualifier = MSI_RecordGetString(rec,2);
5402 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5403 if (rc != ERROR_SUCCESS)
5406 text = MSI_RecordGetString(rec,4);
5407 advertise = create_component_advertise_string(package, comp, feature);
5409 sz = strlenW(advertise);
5412 sz += lstrlenW(text);
5415 sz *= sizeof(WCHAR);
5417 output = msi_alloc_zero(sz);
5418 strcpyW(output,advertise);
5419 msi_free(advertise);
5422 strcatW(output,text);
5424 msi_reg_set_val_multi_str( hkey, qualifier, output );
5431 uirow = MSI_CreateRecord( 2 );
5432 MSI_RecordSetStringW( uirow, 1, compgroupid );
5433 MSI_RecordSetStringW( uirow, 2, qualifier);
5434 ui_actiondata( package, szPublishComponents, uirow);
5435 msiobj_release( &uirow->hdr );
5436 /* FIXME: call ui_progress? */
5442 * At present I am ignorning the advertised components part of this and only
5443 * focusing on the qualified component sets
5445 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5449 static const WCHAR ExecSeqQuery[] =
5450 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5451 '`','P','u','b','l','i','s','h',
5452 'C','o','m','p','o','n','e','n','t','`',0};
5454 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5455 if (rc != ERROR_SUCCESS)
5456 return ERROR_SUCCESS;
5458 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5459 msiobj_release(&view->hdr);
5464 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5466 static const WCHAR szInstallerComponents[] = {
5467 'S','o','f','t','w','a','r','e','\\',
5468 'M','i','c','r','o','s','o','f','t','\\',
5469 'I','n','s','t','a','l','l','e','r','\\',
5470 'C','o','m','p','o','n','e','n','t','s','\\',0};
5472 MSIPACKAGE *package = param;
5473 LPCWSTR compgroupid, component, feature, qualifier;
5477 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5480 feature = MSI_RecordGetString( rec, 5 );
5481 feat = get_loaded_feature( package, feature );
5483 return ERROR_SUCCESS;
5485 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5487 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5488 feat->Action = feat->Installed;
5489 return ERROR_SUCCESS;
5492 component = MSI_RecordGetString( rec, 3 );
5493 comp = get_loaded_component( package, component );
5495 return ERROR_SUCCESS;
5497 compgroupid = MSI_RecordGetString( rec, 1 );
5498 qualifier = MSI_RecordGetString( rec, 2 );
5500 squash_guid( compgroupid, squashed );
5501 strcpyW( keypath, szInstallerComponents );
5502 strcatW( keypath, squashed );
5504 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5505 if (res != ERROR_SUCCESS)
5507 WARN("Unable to delete component key %d\n", res);
5510 uirow = MSI_CreateRecord( 2 );
5511 MSI_RecordSetStringW( uirow, 1, compgroupid );
5512 MSI_RecordSetStringW( uirow, 2, qualifier );
5513 ui_actiondata( package, szUnpublishComponents, uirow );
5514 msiobj_release( &uirow->hdr );
5516 return ERROR_SUCCESS;
5519 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5523 static const WCHAR query[] =
5524 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5525 '`','P','u','b','l','i','s','h',
5526 'C','o','m','p','o','n','e','n','t','`',0};
5528 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5529 if (rc != ERROR_SUCCESS)
5530 return ERROR_SUCCESS;
5532 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5533 msiobj_release( &view->hdr );
5538 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5540 MSIPACKAGE *package = param;
5543 SC_HANDLE hscm, service = NULL;
5545 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5546 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5547 DWORD serv_type, start_type, err_control;
5548 SERVICE_DESCRIPTIONW sd = {NULL};
5550 static const WCHAR query[] =
5551 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5552 '`','C','o','m','p','o','n','e','n','t','`',' ',
5553 'W','H','E','R','E',' ',
5554 '`','C','o','m','p','o','n','e','n','t','`',' ',
5555 '=','\'','%','s','\'',0};
5557 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5560 ERR("Failed to open the SC Manager!\n");
5564 comp = MSI_RecordGetString( rec, 12 );
5565 if (!get_loaded_component( package, comp ))
5568 start_type = MSI_RecordGetInteger(rec, 5);
5569 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5572 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5573 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5574 serv_type = MSI_RecordGetInteger(rec, 4);
5575 err_control = MSI_RecordGetInteger(rec, 6);
5576 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5577 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5578 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5579 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5580 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5581 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5583 /* fetch the service path */
5584 row = MSI_QueryGetRecord(package->db, query, comp);
5587 ERR("Control query failed!\n");
5590 key = MSI_RecordGetString(row, 6);
5592 file = get_loaded_file(package, key);
5593 msiobj_release(&row->hdr);
5596 ERR("Failed to load the service file\n");
5600 if (!args || !args[0]) image_path = file->TargetPath;
5603 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5604 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5605 return ERROR_OUTOFMEMORY;
5607 strcpyW(image_path, file->TargetPath);
5608 strcatW(image_path, szSpace);
5609 strcatW(image_path, args);
5611 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5612 start_type, err_control, image_path, load_order,
5613 NULL, depends, serv_name, pass);
5617 if (GetLastError() != ERROR_SERVICE_EXISTS)
5618 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5620 else if (sd.lpDescription)
5622 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5623 WARN("failed to set service description %u\n", GetLastError());
5626 if (image_path != file->TargetPath) msi_free(image_path);
5628 CloseServiceHandle(service);
5629 CloseServiceHandle(hscm);
5632 msi_free(sd.lpDescription);
5633 msi_free(load_order);
5634 msi_free(serv_name);
5639 return ERROR_SUCCESS;
5642 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5646 static const WCHAR ExecSeqQuery[] =
5647 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5648 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5650 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5651 if (rc != ERROR_SUCCESS)
5652 return ERROR_SUCCESS;
5654 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5655 msiobj_release(&view->hdr);
5660 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5661 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5663 LPCWSTR *vector, *temp_vector;
5667 static const WCHAR separator[] = {'[','~',']',0};
5670 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5675 vector = msi_alloc(sizeof(LPWSTR));
5683 vector[*numargs - 1] = p;
5685 if ((q = strstrW(p, separator)))
5689 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5695 vector = temp_vector;
5704 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5706 MSIPACKAGE *package = param;
5709 SC_HANDLE scm = NULL, service = NULL;
5710 LPCWSTR component, *vector = NULL;
5711 LPWSTR name, args, display_name = NULL;
5712 DWORD event, numargs, len;
5713 UINT r = ERROR_FUNCTION_FAILED;
5715 component = MSI_RecordGetString(rec, 6);
5716 comp = get_loaded_component(package, component);
5718 return ERROR_SUCCESS;
5722 TRACE("component is disabled\n");
5723 return ERROR_SUCCESS;
5726 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5728 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5729 comp->Action = comp->Installed;
5730 return ERROR_SUCCESS;
5732 comp->Action = INSTALLSTATE_LOCAL;
5734 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5735 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5736 event = MSI_RecordGetInteger(rec, 3);
5738 if (!(event & msidbServiceControlEventStart))
5744 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5747 ERR("Failed to open the service control manager\n");
5752 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5753 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5755 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5756 GetServiceDisplayNameW( scm, name, display_name, &len );
5759 service = OpenServiceW(scm, name, SERVICE_START);
5762 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5766 vector = msi_service_args_to_vector(args, &numargs);
5768 if (!StartServiceW(service, numargs, vector) &&
5769 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5771 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5778 uirow = MSI_CreateRecord( 2 );
5779 MSI_RecordSetStringW( uirow, 1, display_name );
5780 MSI_RecordSetStringW( uirow, 2, name );
5781 ui_actiondata( package, szStartServices, uirow );
5782 msiobj_release( &uirow->hdr );
5784 CloseServiceHandle(service);
5785 CloseServiceHandle(scm);
5790 msi_free(display_name);
5794 static UINT ACTION_StartServices( MSIPACKAGE *package )
5799 static const WCHAR query[] = {
5800 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5801 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5803 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5804 if (rc != ERROR_SUCCESS)
5805 return ERROR_SUCCESS;
5807 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5808 msiobj_release(&view->hdr);
5813 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5815 DWORD i, needed, count;
5816 ENUM_SERVICE_STATUSW *dependencies;
5820 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5821 0, &needed, &count))
5824 if (GetLastError() != ERROR_MORE_DATA)
5827 dependencies = msi_alloc(needed);
5831 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5832 needed, &needed, &count))
5835 for (i = 0; i < count; i++)
5837 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5838 SERVICE_STOP | SERVICE_QUERY_STATUS);
5842 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5849 msi_free(dependencies);
5853 static UINT stop_service( LPCWSTR name )
5855 SC_HANDLE scm = NULL, service = NULL;
5856 SERVICE_STATUS status;
5857 SERVICE_STATUS_PROCESS ssp;
5860 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5863 WARN("Failed to open the SCM: %d\n", GetLastError());
5867 service = OpenServiceW(scm, name,
5869 SERVICE_QUERY_STATUS |
5870 SERVICE_ENUMERATE_DEPENDENTS);
5873 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5877 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5878 sizeof(SERVICE_STATUS_PROCESS), &needed))
5880 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5884 if (ssp.dwCurrentState == SERVICE_STOPPED)
5887 stop_service_dependents(scm, service);
5889 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5890 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5893 CloseServiceHandle(service);
5894 CloseServiceHandle(scm);
5896 return ERROR_SUCCESS;
5899 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5901 MSIPACKAGE *package = param;
5905 LPWSTR name = NULL, display_name = NULL;
5909 event = MSI_RecordGetInteger( rec, 3 );
5910 if (!(event & msidbServiceControlEventStop))
5911 return ERROR_SUCCESS;
5913 component = MSI_RecordGetString( rec, 6 );
5914 comp = get_loaded_component( package, component );
5916 return ERROR_SUCCESS;
5920 TRACE("component is disabled\n");
5921 return ERROR_SUCCESS;
5924 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5926 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5927 comp->Action = comp->Installed;
5928 return ERROR_SUCCESS;
5930 comp->Action = INSTALLSTATE_ABSENT;
5932 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5935 ERR("Failed to open the service control manager\n");
5940 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5941 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5943 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5944 GetServiceDisplayNameW( scm, name, display_name, &len );
5946 CloseServiceHandle( scm );
5948 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5949 stop_service( name );
5952 uirow = MSI_CreateRecord( 2 );
5953 MSI_RecordSetStringW( uirow, 1, display_name );
5954 MSI_RecordSetStringW( uirow, 2, name );
5955 ui_actiondata( package, szStopServices, uirow );
5956 msiobj_release( &uirow->hdr );
5959 msi_free( display_name );
5960 return ERROR_SUCCESS;
5963 static UINT ACTION_StopServices( MSIPACKAGE *package )
5968 static const WCHAR query[] = {
5969 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5970 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5972 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5973 if (rc != ERROR_SUCCESS)
5974 return ERROR_SUCCESS;
5976 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5977 msiobj_release(&view->hdr);
5982 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5984 MSIPACKAGE *package = param;
5988 LPWSTR name = NULL, display_name = NULL;
5990 SC_HANDLE scm = NULL, service = NULL;
5992 event = MSI_RecordGetInteger( rec, 3 );
5993 if (!(event & msidbServiceControlEventDelete))
5994 return ERROR_SUCCESS;
5996 component = MSI_RecordGetString(rec, 6);
5997 comp = get_loaded_component(package, component);
5999 return ERROR_SUCCESS;
6003 TRACE("component is disabled\n");
6004 return ERROR_SUCCESS;
6007 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6009 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6010 comp->Action = comp->Installed;
6011 return ERROR_SUCCESS;
6013 comp->Action = INSTALLSTATE_ABSENT;
6015 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6016 stop_service( name );
6018 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6021 WARN("Failed to open the SCM: %d\n", GetLastError());
6026 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6027 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6029 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6030 GetServiceDisplayNameW( scm, name, display_name, &len );
6033 service = OpenServiceW( scm, name, DELETE );
6036 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6040 if (!DeleteService( service ))
6041 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6044 uirow = MSI_CreateRecord( 2 );
6045 MSI_RecordSetStringW( uirow, 1, display_name );
6046 MSI_RecordSetStringW( uirow, 2, name );
6047 ui_actiondata( package, szDeleteServices, uirow );
6048 msiobj_release( &uirow->hdr );
6050 CloseServiceHandle( service );
6051 CloseServiceHandle( scm );
6053 msi_free( display_name );
6055 return ERROR_SUCCESS;
6058 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6063 static const WCHAR query[] = {
6064 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6065 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6067 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6068 if (rc != ERROR_SUCCESS)
6069 return ERROR_SUCCESS;
6071 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6072 msiobj_release( &view->hdr );
6077 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6079 MSIPACKAGE *package = param;
6080 LPWSTR driver, driver_path, ptr;
6081 WCHAR outpath[MAX_PATH];
6082 MSIFILE *driver_file = NULL, *setup_file = NULL;
6085 LPCWSTR desc, file_key, component;
6087 UINT r = ERROR_SUCCESS;
6089 static const WCHAR driver_fmt[] = {
6090 'D','r','i','v','e','r','=','%','s',0};
6091 static const WCHAR setup_fmt[] = {
6092 'S','e','t','u','p','=','%','s',0};
6093 static const WCHAR usage_fmt[] = {
6094 'F','i','l','e','U','s','a','g','e','=','1',0};
6096 component = MSI_RecordGetString( rec, 2 );
6097 comp = get_loaded_component( package, component );
6099 return ERROR_SUCCESS;
6103 TRACE("component is disabled\n");
6104 return ERROR_SUCCESS;
6107 desc = MSI_RecordGetString(rec, 3);
6109 file_key = MSI_RecordGetString( rec, 4 );
6110 if (file_key) driver_file = get_loaded_file( package, file_key );
6112 file_key = MSI_RecordGetString( rec, 5 );
6113 if (file_key) setup_file = get_loaded_file( package, file_key );
6117 ERR("ODBC Driver entry not found!\n");
6118 return ERROR_FUNCTION_FAILED;
6121 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6123 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6124 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6126 driver = msi_alloc(len * sizeof(WCHAR));
6128 return ERROR_OUTOFMEMORY;
6131 lstrcpyW(ptr, desc);
6132 ptr += lstrlenW(ptr) + 1;
6134 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6139 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6143 lstrcpyW(ptr, usage_fmt);
6144 ptr += lstrlenW(ptr) + 1;
6147 driver_path = strdupW(driver_file->TargetPath);
6148 ptr = strrchrW(driver_path, '\\');
6149 if (ptr) *ptr = '\0';
6151 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6152 NULL, ODBC_INSTALL_COMPLETE, &usage))
6154 ERR("Failed to install SQL driver!\n");
6155 r = ERROR_FUNCTION_FAILED;
6158 uirow = MSI_CreateRecord( 5 );
6159 MSI_RecordSetStringW( uirow, 1, desc );
6160 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6161 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6162 ui_actiondata( package, szInstallODBC, uirow );
6163 msiobj_release( &uirow->hdr );
6166 msi_free(driver_path);
6171 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6173 MSIPACKAGE *package = param;
6174 LPWSTR translator, translator_path, ptr;
6175 WCHAR outpath[MAX_PATH];
6176 MSIFILE *translator_file = NULL, *setup_file = NULL;
6179 LPCWSTR desc, file_key, component;
6181 UINT r = ERROR_SUCCESS;
6183 static const WCHAR translator_fmt[] = {
6184 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6185 static const WCHAR setup_fmt[] = {
6186 'S','e','t','u','p','=','%','s',0};
6188 component = MSI_RecordGetString( rec, 2 );
6189 comp = get_loaded_component( package, component );
6191 return ERROR_SUCCESS;
6195 TRACE("component is disabled\n");
6196 return ERROR_SUCCESS;
6199 desc = MSI_RecordGetString(rec, 3);
6201 file_key = MSI_RecordGetString( rec, 4 );
6202 if (file_key) translator_file = get_loaded_file( package, file_key );
6204 file_key = MSI_RecordGetString( rec, 5 );
6205 if (file_key) setup_file = get_loaded_file( package, file_key );
6207 if (!translator_file)
6209 ERR("ODBC Translator entry not found!\n");
6210 return ERROR_FUNCTION_FAILED;
6213 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6215 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6217 translator = msi_alloc(len * sizeof(WCHAR));
6219 return ERROR_OUTOFMEMORY;
6222 lstrcpyW(ptr, desc);
6223 ptr += lstrlenW(ptr) + 1;
6225 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6230 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6235 translator_path = strdupW(translator_file->TargetPath);
6236 ptr = strrchrW(translator_path, '\\');
6237 if (ptr) *ptr = '\0';
6239 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6240 NULL, ODBC_INSTALL_COMPLETE, &usage))
6242 ERR("Failed to install SQL translator!\n");
6243 r = ERROR_FUNCTION_FAILED;
6246 uirow = MSI_CreateRecord( 5 );
6247 MSI_RecordSetStringW( uirow, 1, desc );
6248 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6249 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6250 ui_actiondata( package, szInstallODBC, uirow );
6251 msiobj_release( &uirow->hdr );
6253 msi_free(translator);
6254 msi_free(translator_path);
6259 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6261 MSIPACKAGE *package = param;
6264 LPCWSTR desc, driver, component;
6265 WORD request = ODBC_ADD_SYS_DSN;
6268 UINT r = ERROR_SUCCESS;
6271 static const WCHAR attrs_fmt[] = {
6272 'D','S','N','=','%','s',0 };
6274 component = MSI_RecordGetString( rec, 2 );
6275 comp = get_loaded_component( package, component );
6277 return ERROR_SUCCESS;
6281 TRACE("component is disabled\n");
6282 return ERROR_SUCCESS;
6285 desc = MSI_RecordGetString(rec, 3);
6286 driver = MSI_RecordGetString(rec, 4);
6287 registration = MSI_RecordGetInteger(rec, 5);
6289 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6290 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6292 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6293 attrs = msi_alloc(len * sizeof(WCHAR));
6295 return ERROR_OUTOFMEMORY;
6297 len = sprintfW(attrs, attrs_fmt, desc);
6300 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6302 ERR("Failed to install SQL data source!\n");
6303 r = ERROR_FUNCTION_FAILED;
6306 uirow = MSI_CreateRecord( 5 );
6307 MSI_RecordSetStringW( uirow, 1, desc );
6308 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6309 MSI_RecordSetInteger( uirow, 3, request );
6310 ui_actiondata( package, szInstallODBC, uirow );
6311 msiobj_release( &uirow->hdr );
6318 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6323 static const WCHAR driver_query[] = {
6324 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6325 'O','D','B','C','D','r','i','v','e','r',0 };
6327 static const WCHAR translator_query[] = {
6328 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6329 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6331 static const WCHAR source_query[] = {
6332 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6333 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6335 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6336 if (rc != ERROR_SUCCESS)
6337 return ERROR_SUCCESS;
6339 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6340 msiobj_release(&view->hdr);
6342 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6343 if (rc != ERROR_SUCCESS)
6344 return ERROR_SUCCESS;
6346 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6347 msiobj_release(&view->hdr);
6349 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6350 if (rc != ERROR_SUCCESS)
6351 return ERROR_SUCCESS;
6353 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6354 msiobj_release(&view->hdr);
6359 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6361 MSIPACKAGE *package = param;
6365 LPCWSTR desc, component;
6367 component = MSI_RecordGetString( rec, 2 );
6368 comp = get_loaded_component( package, component );
6370 return ERROR_SUCCESS;
6374 TRACE("component is disabled\n");
6375 return ERROR_SUCCESS;
6378 desc = MSI_RecordGetString( rec, 3 );
6379 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6381 WARN("Failed to remove ODBC driver\n");
6385 FIXME("Usage count reached 0\n");
6388 uirow = MSI_CreateRecord( 2 );
6389 MSI_RecordSetStringW( uirow, 1, desc );
6390 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6391 ui_actiondata( package, szRemoveODBC, uirow );
6392 msiobj_release( &uirow->hdr );
6394 return ERROR_SUCCESS;
6397 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6399 MSIPACKAGE *package = param;
6403 LPCWSTR desc, component;
6405 component = MSI_RecordGetString( rec, 2 );
6406 comp = get_loaded_component( package, component );
6408 return ERROR_SUCCESS;
6412 TRACE("component is disabled\n");
6413 return ERROR_SUCCESS;
6416 desc = MSI_RecordGetString( rec, 3 );
6417 if (!SQLRemoveTranslatorW( desc, &usage ))
6419 WARN("Failed to remove ODBC translator\n");
6423 FIXME("Usage count reached 0\n");
6426 uirow = MSI_CreateRecord( 2 );
6427 MSI_RecordSetStringW( uirow, 1, desc );
6428 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6429 ui_actiondata( package, szRemoveODBC, uirow );
6430 msiobj_release( &uirow->hdr );
6432 return ERROR_SUCCESS;
6435 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6437 MSIPACKAGE *package = param;
6441 LPCWSTR desc, driver, component;
6442 WORD request = ODBC_REMOVE_SYS_DSN;
6446 static const WCHAR attrs_fmt[] = {
6447 'D','S','N','=','%','s',0 };
6449 component = MSI_RecordGetString( rec, 2 );
6450 comp = get_loaded_component( package, component );
6452 return ERROR_SUCCESS;
6456 TRACE("component is disabled\n");
6457 return ERROR_SUCCESS;
6460 desc = MSI_RecordGetString( rec, 3 );
6461 driver = MSI_RecordGetString( rec, 4 );
6462 registration = MSI_RecordGetInteger( rec, 5 );
6464 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6465 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6467 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6468 attrs = msi_alloc( len * sizeof(WCHAR) );
6470 return ERROR_OUTOFMEMORY;
6472 FIXME("Use ODBCSourceAttribute table\n");
6474 len = sprintfW( attrs, attrs_fmt, desc );
6477 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6479 WARN("Failed to remove ODBC data source\n");
6483 uirow = MSI_CreateRecord( 3 );
6484 MSI_RecordSetStringW( uirow, 1, desc );
6485 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6486 MSI_RecordSetInteger( uirow, 3, request );
6487 ui_actiondata( package, szRemoveODBC, uirow );
6488 msiobj_release( &uirow->hdr );
6490 return ERROR_SUCCESS;
6493 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6498 static const WCHAR driver_query[] = {
6499 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6500 'O','D','B','C','D','r','i','v','e','r',0 };
6502 static const WCHAR translator_query[] = {
6503 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6504 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6506 static const WCHAR source_query[] = {
6507 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6508 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6510 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6511 if (rc != ERROR_SUCCESS)
6512 return ERROR_SUCCESS;
6514 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6515 msiobj_release( &view->hdr );
6517 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6518 if (rc != ERROR_SUCCESS)
6519 return ERROR_SUCCESS;
6521 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6522 msiobj_release( &view->hdr );
6524 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6525 if (rc != ERROR_SUCCESS)
6526 return ERROR_SUCCESS;
6528 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6529 msiobj_release( &view->hdr );
6534 #define ENV_ACT_SETALWAYS 0x1
6535 #define ENV_ACT_SETABSENT 0x2
6536 #define ENV_ACT_REMOVE 0x4
6537 #define ENV_ACT_REMOVEMATCH 0x8
6539 #define ENV_MOD_MACHINE 0x20000000
6540 #define ENV_MOD_APPEND 0x40000000
6541 #define ENV_MOD_PREFIX 0x80000000
6542 #define ENV_MOD_MASK 0xC0000000
6544 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6546 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6548 LPCWSTR cptr = *name;
6550 static const WCHAR prefix[] = {'[','~',']',0};
6551 static const int prefix_len = 3;
6557 *flags |= ENV_ACT_SETALWAYS;
6558 else if (*cptr == '+')
6559 *flags |= ENV_ACT_SETABSENT;
6560 else if (*cptr == '-')
6561 *flags |= ENV_ACT_REMOVE;
6562 else if (*cptr == '!')
6563 *flags |= ENV_ACT_REMOVEMATCH;
6564 else if (*cptr == '*')
6565 *flags |= ENV_MOD_MACHINE;
6575 ERR("Missing environment variable\n");
6576 return ERROR_FUNCTION_FAILED;
6581 LPCWSTR ptr = *value;
6582 if (!strncmpW(ptr, prefix, prefix_len))
6584 if (ptr[prefix_len] == szSemiColon[0])
6586 *flags |= ENV_MOD_APPEND;
6587 *value += lstrlenW(prefix);
6594 else if (lstrlenW(*value) >= prefix_len)
6596 ptr += lstrlenW(ptr) - prefix_len;
6597 if (!strcmpW( ptr, prefix ))
6599 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6601 *flags |= ENV_MOD_PREFIX;
6602 /* the "[~]" will be removed by deformat_string */;
6612 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6613 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6614 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6615 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6617 ERR("Invalid flags: %08x\n", *flags);
6618 return ERROR_FUNCTION_FAILED;
6622 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6624 return ERROR_SUCCESS;
6627 static UINT open_env_key( DWORD flags, HKEY *key )
6629 static const WCHAR user_env[] =
6630 {'E','n','v','i','r','o','n','m','e','n','t',0};
6631 static const WCHAR machine_env[] =
6632 {'S','y','s','t','e','m','\\',
6633 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6634 'C','o','n','t','r','o','l','\\',
6635 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6636 'E','n','v','i','r','o','n','m','e','n','t',0};
6641 if (flags & ENV_MOD_MACHINE)
6644 root = HKEY_LOCAL_MACHINE;
6649 root = HKEY_CURRENT_USER;
6652 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6653 if (res != ERROR_SUCCESS)
6655 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6656 return ERROR_FUNCTION_FAILED;
6659 return ERROR_SUCCESS;
6662 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6664 MSIPACKAGE *package = param;
6665 LPCWSTR name, value, component;
6666 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6667 DWORD flags, type, size;
6674 component = MSI_RecordGetString(rec, 4);
6675 comp = get_loaded_component(package, component);
6677 return ERROR_SUCCESS;
6681 TRACE("component is disabled\n");
6682 return ERROR_SUCCESS;
6685 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6687 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6688 comp->Action = comp->Installed;
6689 return ERROR_SUCCESS;
6691 comp->Action = INSTALLSTATE_LOCAL;
6693 name = MSI_RecordGetString(rec, 2);
6694 value = MSI_RecordGetString(rec, 3);
6696 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6698 res = env_parse_flags(&name, &value, &flags);
6699 if (res != ERROR_SUCCESS || !value)
6702 if (value && !deformat_string(package, value, &deformatted))
6704 res = ERROR_OUTOFMEMORY;
6708 value = deformatted;
6710 res = open_env_key( flags, &env );
6711 if (res != ERROR_SUCCESS)
6714 if (flags & ENV_MOD_MACHINE)
6715 action |= 0x20000000;
6719 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6720 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6721 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6724 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6728 /* Nothing to do. */
6731 res = ERROR_SUCCESS;
6735 /* If we are appending but the string was empty, strip ; */
6736 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6738 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6739 newval = strdupW(value);
6742 res = ERROR_OUTOFMEMORY;
6750 /* Contrary to MSDN, +-variable to [~];path works */
6751 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6753 res = ERROR_SUCCESS;
6757 data = msi_alloc(size);
6761 return ERROR_OUTOFMEMORY;
6764 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6765 if (res != ERROR_SUCCESS)
6768 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6771 res = RegDeleteValueW(env, name);
6772 if (res != ERROR_SUCCESS)
6773 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6777 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6778 if (flags & ENV_MOD_MASK)
6782 if (flags & ENV_MOD_APPEND) multiplier++;
6783 if (flags & ENV_MOD_PREFIX) multiplier++;
6784 mod_size = lstrlenW(value) * multiplier;
6785 size += mod_size * sizeof(WCHAR);
6788 newval = msi_alloc(size);
6792 res = ERROR_OUTOFMEMORY;
6796 if (flags & ENV_MOD_PREFIX)
6798 lstrcpyW(newval, value);
6799 ptr = newval + lstrlenW(value);
6800 action |= 0x80000000;
6803 lstrcpyW(ptr, data);
6805 if (flags & ENV_MOD_APPEND)
6807 lstrcatW(newval, value);
6808 action |= 0x40000000;
6811 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6812 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6815 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6819 uirow = MSI_CreateRecord( 3 );
6820 MSI_RecordSetStringW( uirow, 1, name );
6821 MSI_RecordSetStringW( uirow, 2, newval );
6822 MSI_RecordSetInteger( uirow, 3, action );
6823 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6824 msiobj_release( &uirow->hdr );
6826 if (env) RegCloseKey(env);
6827 msi_free(deformatted);
6833 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6837 static const WCHAR ExecSeqQuery[] =
6838 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6839 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6840 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6841 if (rc != ERROR_SUCCESS)
6842 return ERROR_SUCCESS;
6844 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6845 msiobj_release(&view->hdr);
6850 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6852 MSIPACKAGE *package = param;
6853 LPCWSTR name, value, component;
6854 LPWSTR deformatted = NULL;
6863 component = MSI_RecordGetString( rec, 4 );
6864 comp = get_loaded_component( package, component );
6866 return ERROR_SUCCESS;
6870 TRACE("component is disabled\n");
6871 return ERROR_SUCCESS;
6874 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6876 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6877 comp->Action = comp->Installed;
6878 return ERROR_SUCCESS;
6880 comp->Action = INSTALLSTATE_ABSENT;
6882 name = MSI_RecordGetString( rec, 2 );
6883 value = MSI_RecordGetString( rec, 3 );
6885 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6887 r = env_parse_flags( &name, &value, &flags );
6888 if (r != ERROR_SUCCESS)
6891 if (!(flags & ENV_ACT_REMOVE))
6893 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6894 return ERROR_SUCCESS;
6897 if (value && !deformat_string( package, value, &deformatted ))
6898 return ERROR_OUTOFMEMORY;
6900 value = deformatted;
6902 r = open_env_key( flags, &env );
6903 if (r != ERROR_SUCCESS)
6909 if (flags & ENV_MOD_MACHINE)
6910 action |= 0x20000000;
6912 TRACE("Removing %s\n", debugstr_w(name));
6914 res = RegDeleteValueW( env, name );
6915 if (res != ERROR_SUCCESS)
6917 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6922 uirow = MSI_CreateRecord( 3 );
6923 MSI_RecordSetStringW( uirow, 1, name );
6924 MSI_RecordSetStringW( uirow, 2, value );
6925 MSI_RecordSetInteger( uirow, 3, action );
6926 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6927 msiobj_release( &uirow->hdr );
6929 if (env) RegCloseKey( env );
6930 msi_free( deformatted );
6934 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6938 static const WCHAR query[] =
6939 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6940 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6942 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6943 if (rc != ERROR_SUCCESS)
6944 return ERROR_SUCCESS;
6946 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6947 msiobj_release( &view->hdr );
6952 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6954 LPWSTR key, template, id;
6955 UINT r = ERROR_SUCCESS;
6957 id = msi_dup_property( package->db, szProductID );
6961 return ERROR_SUCCESS;
6963 template = msi_dup_property( package->db, szPIDTemplate );
6964 key = msi_dup_property( package->db, szPIDKEY );
6966 if (key && template)
6968 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6969 r = msi_set_property( package->db, szProductID, key );
6971 msi_free( template );
6976 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6979 package->need_reboot = 1;
6980 return ERROR_SUCCESS;
6983 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6985 static const WCHAR szAvailableFreeReg[] =
6986 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6988 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6990 TRACE("%p %d kilobytes\n", package, space);
6992 uirow = MSI_CreateRecord( 1 );
6993 MSI_RecordSetInteger( uirow, 1, space );
6994 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6995 msiobj_release( &uirow->hdr );
6997 return ERROR_SUCCESS;
7000 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7002 FIXME("%p\n", package);
7003 return ERROR_SUCCESS;
7006 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7008 FIXME("%p\n", package);
7009 return ERROR_SUCCESS;
7012 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7017 static const WCHAR driver_query[] = {
7018 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7019 'O','D','B','C','D','r','i','v','e','r',0 };
7021 static const WCHAR translator_query[] = {
7022 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7023 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7025 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7026 if (r == ERROR_SUCCESS)
7029 r = MSI_IterateRecords( view, &count, NULL, package );
7030 msiobj_release( &view->hdr );
7031 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7034 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7035 if (r == ERROR_SUCCESS)
7038 r = MSI_IterateRecords( view, &count, NULL, package );
7039 msiobj_release( &view->hdr );
7040 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7043 return ERROR_SUCCESS;
7046 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7048 MSIPACKAGE *package = param;
7049 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7052 if ((value = msi_dup_property( package->db, property )))
7054 FIXME("remove %s\n", debugstr_w(value));
7057 return ERROR_SUCCESS;
7060 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7065 static const WCHAR query[] =
7066 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7067 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7069 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7070 if (r == ERROR_SUCCESS)
7072 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7073 msiobj_release( &view->hdr );
7075 return ERROR_SUCCESS;
7078 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7080 MSIPACKAGE *package = param;
7081 int attributes = MSI_RecordGetInteger( rec, 5 );
7083 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7085 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7086 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7087 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7088 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7092 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7094 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7095 if (r != ERROR_SUCCESS)
7096 return ERROR_SUCCESS;
7100 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7101 if (r != ERROR_SUCCESS)
7102 return ERROR_SUCCESS;
7104 RegCloseKey( hkey );
7106 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7107 debugstr_w(upgrade_code), debugstr_w(version_min),
7108 debugstr_w(version_max), debugstr_w(language));
7110 return ERROR_SUCCESS;
7113 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7118 static const WCHAR query[] =
7119 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7121 if (msi_get_property_int( package->db, szInstalled, 0 ))
7123 TRACE("product is installed, skipping action\n");
7124 return ERROR_SUCCESS;
7126 if (msi_get_property_int( package->db, szPreselected, 0 ))
7128 TRACE("Preselected property is set, not migrating feature states\n");
7129 return ERROR_SUCCESS;
7132 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7133 if (r == ERROR_SUCCESS)
7135 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7136 msiobj_release( &view->hdr );
7138 return ERROR_SUCCESS;
7141 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7142 LPCSTR action, LPCWSTR table )
7144 static const WCHAR query[] = {
7145 'S','E','L','E','C','T',' ','*',' ',
7146 'F','R','O','M',' ','`','%','s','`',0 };
7147 MSIQUERY *view = NULL;
7151 r = MSI_OpenQuery( package->db, &view, query, table );
7152 if (r == ERROR_SUCCESS)
7154 r = MSI_IterateRecords(view, &count, NULL, package);
7155 msiobj_release(&view->hdr);
7159 FIXME("%s -> %u ignored %s table values\n",
7160 action, count, debugstr_w(table));
7162 return ERROR_SUCCESS;
7165 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7167 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7168 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7171 static UINT ACTION_BindImage( MSIPACKAGE *package )
7173 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7174 return msi_unimplemented_action_stub( package, "BindImage", table );
7177 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7179 static const WCHAR table[] = {
7180 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7181 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7184 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7186 static const WCHAR table[] = {
7187 'M','s','i','A','s','s','e','m','b','l','y',0 };
7188 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7191 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7193 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7194 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7197 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7199 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7200 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7203 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7205 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7206 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7209 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7211 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7212 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7215 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7219 const WCHAR *action;
7220 UINT (*handler)(MSIPACKAGE *);
7224 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7225 { szAppSearch, ACTION_AppSearch },
7226 { szBindImage, ACTION_BindImage },
7227 { szCCPSearch, ACTION_CCPSearch },
7228 { szCostFinalize, ACTION_CostFinalize },
7229 { szCostInitialize, ACTION_CostInitialize },
7230 { szCreateFolders, ACTION_CreateFolders },
7231 { szCreateShortcuts, ACTION_CreateShortcuts },
7232 { szDeleteServices, ACTION_DeleteServices },
7233 { szDisableRollback, ACTION_DisableRollback },
7234 { szDuplicateFiles, ACTION_DuplicateFiles },
7235 { szExecuteAction, ACTION_ExecuteAction },
7236 { szFileCost, ACTION_FileCost },
7237 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7238 { szForceReboot, ACTION_ForceReboot },
7239 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7240 { szInstallExecute, ACTION_InstallExecute },
7241 { szInstallExecuteAgain, ACTION_InstallExecute },
7242 { szInstallFiles, ACTION_InstallFiles},
7243 { szInstallFinalize, ACTION_InstallFinalize },
7244 { szInstallInitialize, ACTION_InstallInitialize },
7245 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7246 { szInstallValidate, ACTION_InstallValidate },
7247 { szIsolateComponents, ACTION_IsolateComponents },
7248 { szLaunchConditions, ACTION_LaunchConditions },
7249 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7250 { szMoveFiles, ACTION_MoveFiles },
7251 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7252 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7253 { szInstallODBC, ACTION_InstallODBC },
7254 { szInstallServices, ACTION_InstallServices },
7255 { szPatchFiles, ACTION_PatchFiles },
7256 { szProcessComponents, ACTION_ProcessComponents },
7257 { szPublishComponents, ACTION_PublishComponents },
7258 { szPublishFeatures, ACTION_PublishFeatures },
7259 { szPublishProduct, ACTION_PublishProduct },
7260 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7261 { szRegisterComPlus, ACTION_RegisterComPlus},
7262 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7263 { szRegisterFonts, ACTION_RegisterFonts },
7264 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7265 { szRegisterProduct, ACTION_RegisterProduct },
7266 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7267 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7268 { szRegisterUser, ACTION_RegisterUser },
7269 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7270 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7271 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7272 { szRemoveFiles, ACTION_RemoveFiles },
7273 { szRemoveFolders, ACTION_RemoveFolders },
7274 { szRemoveIniValues, ACTION_RemoveIniValues },
7275 { szRemoveODBC, ACTION_RemoveODBC },
7276 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7277 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7278 { szResolveSource, ACTION_ResolveSource },
7279 { szRMCCPSearch, ACTION_RMCCPSearch },
7280 { szScheduleReboot, ACTION_ScheduleReboot },
7281 { szSelfRegModules, ACTION_SelfRegModules },
7282 { szSelfUnregModules, ACTION_SelfUnregModules },
7283 { szSetODBCFolders, ACTION_SetODBCFolders },
7284 { szStartServices, ACTION_StartServices },
7285 { szStopServices, ACTION_StopServices },
7286 { szUnpublishComponents, ACTION_UnpublishComponents },
7287 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7288 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7289 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7290 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7291 { szUnregisterFonts, ACTION_UnregisterFonts },
7292 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7293 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7294 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7295 { szValidateProductID, ACTION_ValidateProductID },
7296 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7297 { szWriteIniValues, ACTION_WriteIniValues },
7298 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7302 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7308 while (StandardActions[i].action != NULL)
7310 if (!strcmpW( StandardActions[i].action, action ))
7312 ui_actionstart( package, action );
7313 if (StandardActions[i].handler)
7315 ui_actioninfo( package, action, TRUE, 0 );
7316 *rc = StandardActions[i].handler( package );
7317 ui_actioninfo( package, action, FALSE, *rc );
7321 FIXME("unhandled standard action %s\n", debugstr_w(action));
7322 *rc = ERROR_SUCCESS;
7332 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7334 UINT rc = ERROR_SUCCESS;
7337 TRACE("Performing action (%s)\n", debugstr_w(action));
7339 handled = ACTION_HandleStandardAction(package, action, &rc);
7342 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7346 WARN("unhandled msi action %s\n", debugstr_w(action));
7347 rc = ERROR_FUNCTION_NOT_CALLED;
7353 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7355 UINT rc = ERROR_SUCCESS;
7356 BOOL handled = FALSE;
7358 TRACE("Performing action (%s)\n", debugstr_w(action));
7360 handled = ACTION_HandleStandardAction(package, action, &rc);
7363 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7365 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7370 WARN("unhandled msi action %s\n", debugstr_w(action));
7371 rc = ERROR_FUNCTION_NOT_CALLED;
7377 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7379 UINT rc = ERROR_SUCCESS;
7382 static const WCHAR ExecSeqQuery[] =
7383 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7384 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7385 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7386 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7387 static const WCHAR UISeqQuery[] =
7388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7389 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7390 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7391 ' ', '=',' ','%','i',0};
7393 if (needs_ui_sequence(package))
7394 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7396 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7400 LPCWSTR action, cond;
7402 TRACE("Running the actions\n");
7404 /* check conditions */
7405 cond = MSI_RecordGetString(row, 2);
7407 /* this is a hack to skip errors in the condition code */
7408 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7410 msiobj_release(&row->hdr);
7411 return ERROR_SUCCESS;
7414 action = MSI_RecordGetString(row, 1);
7417 ERR("failed to fetch action\n");
7418 msiobj_release(&row->hdr);
7419 return ERROR_FUNCTION_FAILED;
7422 if (needs_ui_sequence(package))
7423 rc = ACTION_PerformUIAction(package, action, -1);
7425 rc = ACTION_PerformAction(package, action, -1);
7427 msiobj_release(&row->hdr);
7433 /****************************************************
7434 * TOP level entry points
7435 *****************************************************/
7437 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7438 LPCWSTR szCommandLine )
7443 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7444 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7446 msi_set_property( package->db, szAction, szInstall );
7448 package->script->InWhatSequence = SEQUENCE_INSTALL;
7455 dir = strdupW(szPackagePath);
7456 p = strrchrW(dir, '\\');
7460 file = szPackagePath + (p - dir);
7465 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7466 GetCurrentDirectoryW(MAX_PATH, dir);
7467 lstrcatW(dir, szBackSlash);
7468 file = szPackagePath;
7471 msi_free( package->PackagePath );
7472 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7473 if (!package->PackagePath)
7476 return ERROR_OUTOFMEMORY;
7479 lstrcpyW(package->PackagePath, dir);
7480 lstrcatW(package->PackagePath, file);
7483 msi_set_sourcedir_props(package, FALSE);
7486 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7487 if (rc != ERROR_SUCCESS)
7490 msi_apply_transforms( package );
7491 msi_apply_patches( package );
7493 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7495 TRACE("setting reinstall property\n");
7496 msi_set_property( package->db, szReinstall, szAll );
7499 /* properties may have been added by a transform */
7500 msi_clone_properties( package );
7502 msi_parse_command_line( package, szCommandLine, FALSE );
7503 msi_adjust_privilege_properties( package );
7504 msi_set_context( package );
7506 if (needs_ui_sequence( package))
7508 package->script->InWhatSequence |= SEQUENCE_UI;
7509 rc = ACTION_ProcessUISequence(package);
7510 ui_exists = ui_sequence_exists(package);
7511 if (rc == ERROR_SUCCESS || !ui_exists)
7513 package->script->InWhatSequence |= SEQUENCE_EXEC;
7514 rc = ACTION_ProcessExecSequence(package, ui_exists);
7518 rc = ACTION_ProcessExecSequence(package, FALSE);
7520 package->script->CurrentlyScripting = FALSE;
7522 /* process the ending type action */
7523 if (rc == ERROR_SUCCESS)
7524 ACTION_PerformActionSequence(package, -1);
7525 else if (rc == ERROR_INSTALL_USEREXIT)
7526 ACTION_PerformActionSequence(package, -2);
7527 else if (rc == ERROR_INSTALL_SUSPEND)
7528 ACTION_PerformActionSequence(package, -4);
7530 ACTION_PerformActionSequence(package, -3);
7532 /* finish up running custom actions */
7533 ACTION_FinishCustomActions(package);
7535 if (rc == ERROR_SUCCESS && package->need_reboot)
7536 return ERROR_SUCCESS_REBOOT_REQUIRED;