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);
302 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
308 LPWSTR prop = NULL, val = NULL;
311 return ERROR_SUCCESS;
323 TRACE("Looking at %s\n",debugstr_w(ptr));
325 ptr2 = strchrW(ptr,'=');
328 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
335 prop = msi_alloc((len+1)*sizeof(WCHAR));
336 memcpy(prop,ptr,len*sizeof(WCHAR));
346 while (*ptr && (quote || (!quote && *ptr!=' ')))
359 val = msi_alloc((len+1)*sizeof(WCHAR));
360 memcpy(val,ptr2,len*sizeof(WCHAR));
363 if (lstrlenW(prop) > 0)
365 UINT r = msi_set_property( package->db, prop, val );
367 TRACE("Found commandline property (%s) = (%s)\n",
368 debugstr_w(prop), debugstr_w(val));
370 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
371 msi_reset_folders( package, TRUE );
377 return ERROR_SUCCESS;
381 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
384 LPWSTR p, *ret = NULL;
390 /* count the number of substrings */
391 for ( pc = str, count = 0; pc; count++ )
393 pc = strchrW( pc, sep );
398 /* allocate space for an array of substring pointers and the substrings */
399 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
400 (lstrlenW(str)+1) * sizeof(WCHAR) );
404 /* copy the string and set the pointers */
405 p = (LPWSTR) &ret[count+1];
407 for( count = 0; (ret[count] = p); count++ )
409 p = strchrW( p, sep );
417 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
419 static const WCHAR szSystemLanguageID[] =
420 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
422 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
423 UINT ret = ERROR_FUNCTION_FAILED;
425 prod_code = msi_dup_property( package->db, szProductCode );
426 patch_product = msi_get_suminfo_product( patch );
428 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
430 if ( strstrW( patch_product, prod_code ) )
435 si = MSI_GetSummaryInformationW( patch, 0 );
438 ERR("no summary information!\n");
442 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
445 ERR("no template property!\n");
446 msiobj_release( &si->hdr );
453 msiobj_release( &si->hdr );
457 langid = msi_dup_property( package->db, szSystemLanguageID );
460 msiobj_release( &si->hdr );
464 p = strchrW( template, ';' );
465 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
467 TRACE("applicable transform\n");
471 /* FIXME: check platform */
473 msiobj_release( &si->hdr );
477 msi_free( patch_product );
478 msi_free( prod_code );
479 msi_free( template );
485 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
486 MSIDATABASE *patch_db, LPCWSTR name )
488 UINT ret = ERROR_FUNCTION_FAILED;
489 IStorage *stg = NULL;
492 TRACE("%p %s\n", package, debugstr_w(name) );
496 ERR("expected a colon in %s\n", debugstr_w(name));
497 return ERROR_FUNCTION_FAILED;
500 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
503 ret = msi_check_transform_applicable( package, stg );
504 if (ret == ERROR_SUCCESS)
505 msi_table_apply_transform( package->db, stg );
507 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
508 IStorage_Release( stg );
511 ERR("failed to open substorage %s\n", debugstr_w(name));
513 return ERROR_SUCCESS;
516 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
518 LPWSTR guid_list, *guids, product_code;
519 UINT i, ret = ERROR_FUNCTION_FAILED;
521 product_code = msi_dup_property( package->db, szProductCode );
524 /* FIXME: the property ProductCode should be written into the DB somewhere */
525 ERR("no product code to check\n");
526 return ERROR_SUCCESS;
529 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
530 guids = msi_split_string( guid_list, ';' );
531 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
533 if (!strcmpW( guids[i], product_code ))
537 msi_free( guid_list );
538 msi_free( product_code );
543 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
546 MSIRECORD *rec = NULL;
551 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
552 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
553 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
554 '`','S','o','u','r','c','e','`',' ','I','S',' ',
555 'N','O','T',' ','N','U','L','L',0};
557 r = MSI_DatabaseOpenViewW(package->db, query, &view);
558 if (r != ERROR_SUCCESS)
561 r = MSI_ViewExecute(view, 0);
562 if (r != ERROR_SUCCESS)
565 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
567 prop = MSI_RecordGetString(rec, 1);
568 patch = msi_dup_property(package->db, szPatch);
569 msi_set_property(package->db, prop, patch);
574 if (rec) msiobj_release(&rec->hdr);
575 msiobj_release(&view->hdr);
580 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
583 UINT r = ERROR_SUCCESS;
586 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
588 return ERROR_OUTOFMEMORY;
590 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
594 return ERROR_OUTOFMEMORY;
600 msi_free( pi->patchcode );
602 return ERROR_PATCH_PACKAGE_INVALID;
605 p = strchrW( p + 1, '}' );
608 msi_free( pi->patchcode );
610 return ERROR_PATCH_PACKAGE_INVALID;
615 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
619 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
621 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
624 msi_free( pi->patchcode );
626 return ERROR_OUTOFMEMORY;
633 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
635 UINT i, r = ERROR_SUCCESS;
638 /* apply substorage transforms */
639 substorage = msi_split_string( patch->transforms, ';' );
640 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
641 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
643 msi_free( substorage );
644 if (r != ERROR_SUCCESS)
647 msi_set_media_source_prop( package );
650 * There might be a CAB file in the patch package,
651 * so append it to the list of storages to search for streams.
653 append_storage_to_db( package->db, patch_db->storage );
655 patch->state = MSIPATCHSTATE_APPLIED;
656 list_add_tail( &package->patches, &patch->entry );
657 return ERROR_SUCCESS;
660 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
662 static const WCHAR dotmsp[] = {'.','m','s','p',0};
663 MSIDATABASE *patch_db = NULL;
664 WCHAR localfile[MAX_PATH];
666 MSIPATCHINFO *patch = NULL;
667 UINT r = ERROR_SUCCESS;
669 TRACE("%p %s\n", package, debugstr_w( file ) );
671 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
672 if ( r != ERROR_SUCCESS )
674 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
678 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
681 msiobj_release( &patch_db->hdr );
682 return ERROR_FUNCTION_FAILED;
685 r = msi_check_patch_applicable( package, si );
686 if (r != ERROR_SUCCESS)
688 TRACE("patch not applicable\n");
693 r = msi_parse_patch_summary( si, &patch );
694 if ( r != ERROR_SUCCESS )
697 r = msi_get_local_package_name( localfile, dotmsp );
698 if ( r != ERROR_SUCCESS )
701 TRACE("copying to local package %s\n", debugstr_w(localfile));
703 if (!CopyFileW( file, localfile, FALSE ))
705 ERR("Unable to copy package (%s -> %s) (error %u)\n",
706 debugstr_w(file), debugstr_w(localfile), GetLastError());
710 patch->localfile = strdupW( localfile );
712 r = msi_apply_patch_db( package, patch_db, patch );
713 if ( r != ERROR_SUCCESS )
714 WARN("patch failed to apply %u\n", r);
717 msiobj_release( &si->hdr );
718 msiobj_release( &patch_db->hdr );
719 if (patch && r != ERROR_SUCCESS)
721 if (patch->localfile)
722 DeleteFileW( patch->localfile );
724 msi_free( patch->patchcode );
725 msi_free( patch->transforms );
726 msi_free( patch->localfile );
732 /* get the PATCH property, and apply all the patches it specifies */
733 static UINT msi_apply_patches( MSIPACKAGE *package )
735 LPWSTR patch_list, *patches;
736 UINT i, r = ERROR_SUCCESS;
738 patch_list = msi_dup_property( package->db, szPatch );
740 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
742 patches = msi_split_string( patch_list, ';' );
743 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
744 r = msi_apply_patch_package( package, patches[i] );
747 msi_free( patch_list );
752 static UINT msi_apply_transforms( MSIPACKAGE *package )
754 static const WCHAR szTransforms[] = {
755 'T','R','A','N','S','F','O','R','M','S',0 };
756 LPWSTR xform_list, *xforms;
757 UINT i, r = ERROR_SUCCESS;
759 xform_list = msi_dup_property( package->db, szTransforms );
760 xforms = msi_split_string( xform_list, ';' );
762 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
764 if (xforms[i][0] == ':')
765 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
770 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
773 WCHAR *p = strrchrW( package->PackagePath, '\\' );
774 DWORD len = p - package->PackagePath + 1;
776 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
779 msi_free( xform_list );
780 return ERROR_OUTOFMEMORY;
782 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
783 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
785 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
786 if (transform != xforms[i]) msi_free( transform );
791 msi_free( xform_list );
796 static BOOL ui_sequence_exists( MSIPACKAGE *package )
801 static const WCHAR ExecSeqQuery [] =
802 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
803 '`','I','n','s','t','a','l','l',
804 'U','I','S','e','q','u','e','n','c','e','`',
805 ' ','W','H','E','R','E',' ',
806 '`','S','e','q','u','e','n','c','e','`',' ',
807 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
808 '`','S','e','q','u','e','n','c','e','`',0};
810 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
811 if (rc == ERROR_SUCCESS)
813 msiobj_release(&view->hdr);
820 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
822 LPWSTR source, check;
824 if (msi_get_property_int( package->db, szInstalled, 0 ))
828 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
829 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
837 db = msi_dup_property( package->db, szOriginalDatabase );
839 return ERROR_OUTOFMEMORY;
841 p = strrchrW( db, '\\' );
844 p = strrchrW( db, '/' );
848 return ERROR_SUCCESS;
853 source = msi_alloc( len * sizeof(WCHAR) );
854 lstrcpynW( source, db, len );
858 check = msi_dup_property( package->db, cszSourceDir );
859 if (!check || replace)
861 UINT r = msi_set_property( package->db, cszSourceDir, source );
862 if (r == ERROR_SUCCESS)
863 msi_reset_folders( package, TRUE );
867 check = msi_dup_property( package->db, cszSOURCEDIR );
868 if (!check || replace)
869 msi_set_property( package->db, cszSOURCEDIR, source );
874 return ERROR_SUCCESS;
877 static BOOL needs_ui_sequence(MSIPACKAGE *package)
879 INT level = msi_get_property_int(package->db, szUILevel, 0);
880 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
883 UINT msi_set_context(MSIPACKAGE *package)
887 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
889 num = msi_get_property_int(package->db, szAllUsers, 0);
890 if (num == 1 || num == 2)
891 package->Context = MSIINSTALLCONTEXT_MACHINE;
893 return ERROR_SUCCESS;
896 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
899 LPCWSTR cond, action;
900 MSIPACKAGE *package = param;
902 action = MSI_RecordGetString(row,1);
905 ERR("Error is retrieving action name\n");
906 return ERROR_FUNCTION_FAILED;
909 /* check conditions */
910 cond = MSI_RecordGetString(row,2);
912 /* this is a hack to skip errors in the condition code */
913 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
915 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
916 return ERROR_SUCCESS;
919 if (needs_ui_sequence(package))
920 rc = ACTION_PerformUIAction(package, action, -1);
922 rc = ACTION_PerformAction(package, action, -1);
924 msi_dialog_check_messages( NULL );
926 if (package->CurrentInstallState != ERROR_SUCCESS)
927 rc = package->CurrentInstallState;
929 if (rc == ERROR_FUNCTION_NOT_CALLED)
932 if (rc != ERROR_SUCCESS)
933 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
938 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
942 static const WCHAR query[] =
943 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
945 ' ','W','H','E','R','E',' ',
946 '`','S','e','q','u','e','n','c','e','`',' ',
947 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
948 '`','S','e','q','u','e','n','c','e','`',0};
950 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
952 r = MSI_OpenQuery( package->db, &view, query, szTable );
953 if (r == ERROR_SUCCESS)
955 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
956 msiobj_release(&view->hdr);
962 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
966 static const WCHAR ExecSeqQuery[] =
967 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
968 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
969 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
970 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
971 'O','R','D','E','R',' ', 'B','Y',' ',
972 '`','S','e','q','u','e','n','c','e','`',0 };
973 static const WCHAR IVQuery[] =
974 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
975 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
976 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
977 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
978 ' ','\'', 'I','n','s','t','a','l','l',
979 'V','a','l','i','d','a','t','e','\'', 0};
982 if (package->script->ExecuteSequenceRun)
984 TRACE("Execute Sequence already Run\n");
985 return ERROR_SUCCESS;
988 package->script->ExecuteSequenceRun = TRUE;
990 /* get the sequence number */
993 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
995 return ERROR_FUNCTION_FAILED;
996 seq = MSI_RecordGetInteger(row,1);
997 msiobj_release(&row->hdr);
1000 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1001 if (rc == ERROR_SUCCESS)
1003 TRACE("Running the actions\n");
1005 msi_set_property(package->db, cszSourceDir, NULL);
1007 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1008 msiobj_release(&view->hdr);
1014 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1018 static const WCHAR ExecSeqQuery [] =
1019 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1020 '`','I','n','s','t','a','l','l',
1021 'U','I','S','e','q','u','e','n','c','e','`',
1022 ' ','W','H','E','R','E',' ',
1023 '`','S','e','q','u','e','n','c','e','`',' ',
1024 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1025 '`','S','e','q','u','e','n','c','e','`',0};
1027 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1028 if (rc == ERROR_SUCCESS)
1030 TRACE("Running the actions\n");
1032 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1033 msiobj_release(&view->hdr);
1039 /********************************************************
1040 * ACTION helper functions and functions that perform the actions
1041 *******************************************************/
1042 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1043 UINT* rc, UINT script, BOOL force )
1048 arc = ACTION_CustomAction(package, action, script, force);
1050 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1059 * Actual Action Handlers
1062 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1064 MSIPACKAGE *package = param;
1065 LPCWSTR dir, component;
1071 component = MSI_RecordGetString(row, 2);
1073 return ERROR_SUCCESS;
1075 comp = get_loaded_component(package, component);
1077 return ERROR_SUCCESS;
1081 TRACE("component is disabled\n");
1082 return ERROR_SUCCESS;
1085 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1087 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1088 comp->Action = comp->Installed;
1089 return ERROR_SUCCESS;
1091 comp->Action = INSTALLSTATE_LOCAL;
1093 dir = MSI_RecordGetString(row,1);
1096 ERR("Unable to get folder id\n");
1097 return ERROR_SUCCESS;
1100 uirow = MSI_CreateRecord(1);
1101 MSI_RecordSetStringW(uirow, 1, dir);
1102 ui_actiondata(package, szCreateFolders, uirow);
1103 msiobj_release(&uirow->hdr);
1105 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1108 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1109 return ERROR_SUCCESS;
1112 TRACE("Folder is %s\n",debugstr_w(full_path));
1114 if (folder->State == 0)
1115 create_full_pathW(full_path);
1119 msi_free(full_path);
1120 return ERROR_SUCCESS;
1123 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1125 static const WCHAR query[] =
1126 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1127 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1131 /* create all the empty folders specified in the CreateFolder table */
1132 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1133 if (rc != ERROR_SUCCESS)
1134 return ERROR_SUCCESS;
1136 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1137 msiobj_release(&view->hdr);
1142 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1144 MSIPACKAGE *package = param;
1145 LPCWSTR dir, component;
1151 component = MSI_RecordGetString(row, 2);
1153 return ERROR_SUCCESS;
1155 comp = get_loaded_component(package, component);
1157 return ERROR_SUCCESS;
1161 TRACE("component is disabled\n");
1162 return ERROR_SUCCESS;
1165 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1167 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1168 comp->Action = comp->Installed;
1169 return ERROR_SUCCESS;
1171 comp->Action = INSTALLSTATE_ABSENT;
1173 dir = MSI_RecordGetString( row, 1 );
1176 ERR("Unable to get folder id\n");
1177 return ERROR_SUCCESS;
1180 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1183 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1184 return ERROR_SUCCESS;
1187 TRACE("folder is %s\n", debugstr_w(full_path));
1189 uirow = MSI_CreateRecord( 1 );
1190 MSI_RecordSetStringW( uirow, 1, dir );
1191 ui_actiondata( package, szRemoveFolders, uirow );
1192 msiobj_release( &uirow->hdr );
1194 RemoveDirectoryW( full_path );
1197 msi_free( full_path );
1198 return ERROR_SUCCESS;
1201 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1203 static const WCHAR query[] =
1204 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1205 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1210 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1211 if (rc != ERROR_SUCCESS)
1212 return ERROR_SUCCESS;
1214 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1215 msiobj_release( &view->hdr );
1220 static UINT load_component( MSIRECORD *row, LPVOID param )
1222 MSIPACKAGE *package = param;
1225 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1227 return ERROR_FUNCTION_FAILED;
1229 list_add_tail( &package->components, &comp->entry );
1231 /* fill in the data */
1232 comp->Component = msi_dup_record_field( row, 1 );
1234 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1236 comp->ComponentId = msi_dup_record_field( row, 2 );
1237 comp->Directory = msi_dup_record_field( row, 3 );
1238 comp->Attributes = MSI_RecordGetInteger(row,4);
1239 comp->Condition = msi_dup_record_field( row, 5 );
1240 comp->KeyPath = msi_dup_record_field( row, 6 );
1242 comp->Installed = INSTALLSTATE_UNKNOWN;
1243 comp->Action = INSTALLSTATE_UNKNOWN;
1244 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1246 comp->assembly = load_assembly( package, comp );
1247 return ERROR_SUCCESS;
1250 static UINT load_all_components( MSIPACKAGE *package )
1252 static const WCHAR query[] = {
1253 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1254 '`','C','o','m','p','o','n','e','n','t','`',0 };
1258 if (!list_empty(&package->components))
1259 return ERROR_SUCCESS;
1261 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1262 if (r != ERROR_SUCCESS)
1265 r = MSI_IterateRecords(view, NULL, load_component, package);
1266 msiobj_release(&view->hdr);
1271 MSIPACKAGE *package;
1272 MSIFEATURE *feature;
1275 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1279 cl = msi_alloc( sizeof (*cl) );
1281 return ERROR_NOT_ENOUGH_MEMORY;
1282 cl->component = comp;
1283 list_add_tail( &feature->Components, &cl->entry );
1285 return ERROR_SUCCESS;
1288 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1292 fl = msi_alloc( sizeof(*fl) );
1294 return ERROR_NOT_ENOUGH_MEMORY;
1295 fl->feature = child;
1296 list_add_tail( &parent->Children, &fl->entry );
1298 return ERROR_SUCCESS;
1301 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1303 _ilfs* ilfs = param;
1307 component = MSI_RecordGetString(row,1);
1309 /* check to see if the component is already loaded */
1310 comp = get_loaded_component( ilfs->package, component );
1313 ERR("unknown component %s\n", debugstr_w(component));
1314 return ERROR_FUNCTION_FAILED;
1317 add_feature_component( ilfs->feature, comp );
1318 comp->Enabled = TRUE;
1320 return ERROR_SUCCESS;
1323 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1325 MSIFEATURE *feature;
1330 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1332 if ( !strcmpW( feature->Feature, name ) )
1339 static UINT load_feature(MSIRECORD * row, LPVOID param)
1341 MSIPACKAGE* package = param;
1342 MSIFEATURE* feature;
1343 static const WCHAR Query1[] =
1344 {'S','E','L','E','C','T',' ',
1345 '`','C','o','m','p','o','n','e','n','t','_','`',
1346 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1347 'C','o','m','p','o','n','e','n','t','s','`',' ',
1348 'W','H','E','R','E',' ',
1349 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1354 /* fill in the data */
1356 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1358 return ERROR_NOT_ENOUGH_MEMORY;
1360 list_init( &feature->Children );
1361 list_init( &feature->Components );
1363 feature->Feature = msi_dup_record_field( row, 1 );
1365 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1367 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1368 feature->Title = msi_dup_record_field( row, 3 );
1369 feature->Description = msi_dup_record_field( row, 4 );
1371 if (!MSI_RecordIsNull(row,5))
1372 feature->Display = MSI_RecordGetInteger(row,5);
1374 feature->Level= MSI_RecordGetInteger(row,6);
1375 feature->Directory = msi_dup_record_field( row, 7 );
1376 feature->Attributes = MSI_RecordGetInteger(row,8);
1378 feature->Installed = INSTALLSTATE_UNKNOWN;
1379 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1381 list_add_tail( &package->features, &feature->entry );
1383 /* load feature components */
1385 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1386 if (rc != ERROR_SUCCESS)
1387 return ERROR_SUCCESS;
1389 ilfs.package = package;
1390 ilfs.feature = feature;
1392 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1393 msiobj_release(&view->hdr);
1395 return ERROR_SUCCESS;
1398 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1400 MSIPACKAGE* package = param;
1401 MSIFEATURE *parent, *child;
1403 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1405 return ERROR_FUNCTION_FAILED;
1407 if (!child->Feature_Parent)
1408 return ERROR_SUCCESS;
1410 parent = find_feature_by_name( package, child->Feature_Parent );
1412 return ERROR_FUNCTION_FAILED;
1414 add_feature_child( parent, child );
1415 return ERROR_SUCCESS;
1418 static UINT load_all_features( MSIPACKAGE *package )
1420 static const WCHAR query[] = {
1421 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1422 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1423 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1427 if (!list_empty(&package->features))
1428 return ERROR_SUCCESS;
1430 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1431 if (r != ERROR_SUCCESS)
1434 r = MSI_IterateRecords( view, NULL, load_feature, package );
1435 if (r != ERROR_SUCCESS)
1438 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1439 msiobj_release( &view->hdr );
1444 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1455 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1457 static const WCHAR query[] = {
1458 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1459 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1460 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1461 MSIQUERY *view = NULL;
1462 MSIRECORD *row = NULL;
1465 TRACE("%s\n", debugstr_w(file->File));
1467 r = MSI_OpenQuery(package->db, &view, query, file->File);
1468 if (r != ERROR_SUCCESS)
1471 r = MSI_ViewExecute(view, NULL);
1472 if (r != ERROR_SUCCESS)
1475 r = MSI_ViewFetch(view, &row);
1476 if (r != ERROR_SUCCESS)
1479 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1480 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1481 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1482 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1483 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1486 if (view) msiobj_release(&view->hdr);
1487 if (row) msiobj_release(&row->hdr);
1491 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1494 static const WCHAR query[] = {
1495 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1496 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1497 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1499 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1502 WARN("query failed\n");
1503 return ERROR_FUNCTION_FAILED;
1506 file->disk_id = MSI_RecordGetInteger( row, 1 );
1507 msiobj_release( &row->hdr );
1508 return ERROR_SUCCESS;
1511 static UINT load_file(MSIRECORD *row, LPVOID param)
1513 MSIPACKAGE* package = param;
1517 /* fill in the data */
1519 file = msi_alloc_zero( sizeof (MSIFILE) );
1521 return ERROR_NOT_ENOUGH_MEMORY;
1523 file->File = msi_dup_record_field( row, 1 );
1525 component = MSI_RecordGetString( row, 2 );
1526 file->Component = get_loaded_component( package, component );
1528 if (!file->Component)
1530 WARN("Component not found: %s\n", debugstr_w(component));
1531 msi_free(file->File);
1533 return ERROR_SUCCESS;
1536 file->FileName = msi_dup_record_field( row, 3 );
1537 reduce_to_longfilename( file->FileName );
1539 file->ShortName = msi_dup_record_field( row, 3 );
1540 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1542 file->FileSize = MSI_RecordGetInteger( row, 4 );
1543 file->Version = msi_dup_record_field( row, 5 );
1544 file->Language = msi_dup_record_field( row, 6 );
1545 file->Attributes = MSI_RecordGetInteger( row, 7 );
1546 file->Sequence = MSI_RecordGetInteger( row, 8 );
1548 file->state = msifs_invalid;
1550 /* if the compressed bits are not set in the file attributes,
1551 * then read the information from the package word count property
1553 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1555 file->IsCompressed = FALSE;
1557 else if (file->Attributes &
1558 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1560 file->IsCompressed = TRUE;
1562 else if (file->Attributes & msidbFileAttributesNoncompressed)
1564 file->IsCompressed = FALSE;
1568 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1571 load_file_hash(package, file);
1572 load_file_disk_id(package, file);
1574 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1576 list_add_tail( &package->files, &file->entry );
1578 return ERROR_SUCCESS;
1581 static UINT load_all_files(MSIPACKAGE *package)
1585 static const WCHAR Query[] =
1586 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1587 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1588 '`','S','e','q','u','e','n','c','e','`', 0};
1590 if (!list_empty(&package->files))
1591 return ERROR_SUCCESS;
1593 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1594 if (rc != ERROR_SUCCESS)
1595 return ERROR_SUCCESS;
1597 rc = MSI_IterateRecords(view, NULL, load_file, package);
1598 msiobj_release(&view->hdr);
1600 return ERROR_SUCCESS;
1603 static UINT load_folder( MSIRECORD *row, LPVOID param )
1605 MSIPACKAGE *package = param;
1606 static WCHAR szEmpty[] = { 0 };
1607 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1610 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1612 return ERROR_NOT_ENOUGH_MEMORY;
1614 folder->Directory = msi_dup_record_field( row, 1 );
1616 TRACE("%s\n", debugstr_w(folder->Directory));
1618 p = msi_dup_record_field(row, 3);
1620 /* split src and target dir */
1622 src_short = folder_split_path( p, ':' );
1624 /* split the long and short paths */
1625 tgt_long = folder_split_path( tgt_short, '|' );
1626 src_long = folder_split_path( src_short, '|' );
1628 /* check for no-op dirs */
1629 if (tgt_short && !strcmpW( szDot, tgt_short ))
1630 tgt_short = szEmpty;
1631 if (src_short && !strcmpW( szDot, src_short ))
1632 src_short = szEmpty;
1635 tgt_long = tgt_short;
1638 src_short = tgt_short;
1639 src_long = tgt_long;
1643 src_long = src_short;
1645 /* FIXME: use the target short path too */
1646 folder->TargetDefault = strdupW(tgt_long);
1647 folder->SourceShortPath = strdupW(src_short);
1648 folder->SourceLongPath = strdupW(src_long);
1651 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1652 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1653 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1655 folder->Parent = msi_dup_record_field( row, 2 );
1657 folder->Property = msi_dup_property( package->db, folder->Directory );
1659 list_add_tail( &package->folders, &folder->entry );
1661 TRACE("returning %p\n", folder);
1663 return ERROR_SUCCESS;
1666 static UINT load_all_folders( MSIPACKAGE *package )
1668 static const WCHAR query[] = {
1669 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1670 '`','D','i','r','e','c','t','o','r','y','`',0 };
1674 if (!list_empty(&package->folders))
1675 return ERROR_SUCCESS;
1677 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1678 if (r != ERROR_SUCCESS)
1681 r = MSI_IterateRecords(view, NULL, load_folder, package);
1682 msiobj_release(&view->hdr);
1687 * I am not doing any of the costing functionality yet.
1688 * Mostly looking at doing the Component and Feature loading
1690 * The native MSI does A LOT of modification to tables here. Mostly adding
1691 * a lot of temporary columns to the Feature and Component tables.
1693 * note: Native msi also tracks the short filename. But I am only going to
1694 * track the long ones. Also looking at this directory table
1695 * it appears that the directory table does not get the parents
1696 * resolved base on property only based on their entries in the
1699 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1701 static const WCHAR szCosting[] =
1702 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1704 msi_set_property( package->db, szCosting, szZero );
1705 msi_set_property( package->db, cszRootDrive, c_colon );
1707 load_all_folders( package );
1708 load_all_components( package );
1709 load_all_features( package );
1710 load_all_files( package );
1712 return ERROR_SUCCESS;
1715 static UINT execute_script(MSIPACKAGE *package, UINT script )
1718 UINT rc = ERROR_SUCCESS;
1720 TRACE("Executing Script %i\n",script);
1722 if (!package->script)
1724 ERR("no script!\n");
1725 return ERROR_FUNCTION_FAILED;
1728 for (i = 0; i < package->script->ActionCount[script]; i++)
1731 action = package->script->Actions[script][i];
1732 ui_actionstart(package, action);
1733 TRACE("Executing Action (%s)\n",debugstr_w(action));
1734 rc = ACTION_PerformAction(package, action, script);
1735 if (rc != ERROR_SUCCESS)
1738 msi_free_action_script(package, script);
1742 static UINT ACTION_FileCost(MSIPACKAGE *package)
1744 return ERROR_SUCCESS;
1747 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1753 state = MsiQueryProductStateW(package->ProductCode);
1755 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1757 if (!comp->Enabled || !comp->ComponentId)
1760 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1761 comp->Installed = INSTALLSTATE_ABSENT;
1764 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1765 package->Context, comp->ComponentId,
1767 if (r != ERROR_SUCCESS)
1768 comp->Installed = INSTALLSTATE_ABSENT;
1773 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1775 MSIFEATURE *feature;
1778 state = MsiQueryProductStateW(package->ProductCode);
1780 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1782 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1783 feature->Installed = INSTALLSTATE_ABSENT;
1786 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1792 static BOOL process_state_property(MSIPACKAGE* package, int level,
1793 LPCWSTR property, INSTALLSTATE state)
1796 MSIFEATURE *feature;
1798 override = msi_dup_property( package->db, property );
1802 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1804 if (strcmpW( property, szRemove ) &&
1805 (feature->Level <= 0 || feature->Level > level))
1808 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1810 if (!strcmpiW( override, szAll ))
1811 msi_feature_set_state(package, feature, state);
1814 LPWSTR ptr = override;
1815 LPWSTR ptr2 = strchrW(override,',');
1819 int len = ptr2 - ptr;
1821 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1822 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1824 msi_feature_set_state(package, feature, state);
1830 ptr2 = strchrW(ptr,',');
1842 static BOOL process_overrides( MSIPACKAGE *package, int level )
1844 static const WCHAR szAddLocal[] =
1845 {'A','D','D','L','O','C','A','L',0};
1846 static const WCHAR szAddSource[] =
1847 {'A','D','D','S','O','U','R','C','E',0};
1848 static const WCHAR szAdvertise[] =
1849 {'A','D','V','E','R','T','I','S','E',0};
1852 /* all these activation/deactivation things happen in order and things
1853 * later on the list override things earlier on the list.
1855 * 0 INSTALLLEVEL processing
1868 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1869 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1870 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1871 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1872 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1875 msi_set_property( package->db, szPreselected, szOne );
1880 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1883 static const WCHAR szlevel[] =
1884 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1885 MSICOMPONENT* component;
1886 MSIFEATURE *feature;
1888 TRACE("Checking Install Level\n");
1890 level = msi_get_property_int(package->db, szlevel, 1);
1892 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1894 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1896 BOOL feature_state = ((feature->Level > 0) &&
1897 (feature->Level <= level));
1899 if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1901 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1902 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1903 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1904 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1906 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1910 /* disable child features of unselected parent features */
1911 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1915 if (feature->Level > 0 && feature->Level <= level)
1918 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1919 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1924 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1926 BOOL selected = feature->Level > 0 && feature->Level <= level;
1928 if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1930 msi_feature_set_state(package, feature, feature->Installed);
1936 * now we want to enable or disable components based on feature
1938 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1942 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1943 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1944 feature->ActionRequest, feature->Action);
1946 if (!feature->Level)
1949 /* features with components that have compressed files are made local */
1950 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1952 if (!cl->component->Enabled) continue;
1954 if (cl->component->ForceLocalState &&
1955 feature->ActionRequest == INSTALLSTATE_SOURCE)
1957 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1962 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1964 component = cl->component;
1966 if (!component->Enabled) continue;
1968 switch (feature->ActionRequest)
1970 case INSTALLSTATE_ABSENT:
1971 component->anyAbsent = 1;
1973 case INSTALLSTATE_ADVERTISED:
1974 component->hasAdvertiseFeature = 1;
1976 case INSTALLSTATE_SOURCE:
1977 component->hasSourceFeature = 1;
1979 case INSTALLSTATE_LOCAL:
1980 component->hasLocalFeature = 1;
1982 case INSTALLSTATE_DEFAULT:
1983 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1984 component->hasAdvertiseFeature = 1;
1985 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1986 component->hasSourceFeature = 1;
1988 component->hasLocalFeature = 1;
1996 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1998 if (!component->Enabled) continue;
2000 /* check if it's local or source */
2001 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2002 (component->hasLocalFeature || component->hasSourceFeature))
2004 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2005 !component->ForceLocalState)
2006 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2008 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2012 /* if any feature is local, the component must be local too */
2013 if (component->hasLocalFeature)
2015 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2019 if (component->hasSourceFeature)
2021 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2025 if (component->hasAdvertiseFeature)
2027 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2031 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2032 if (component->anyAbsent)
2033 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2036 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2038 if (!component->Enabled) continue;
2040 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2042 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2043 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2046 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2047 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2050 return ERROR_SUCCESS;
2053 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2055 MSIPACKAGE *package = param;
2060 name = MSI_RecordGetString(row,1);
2062 f = get_loaded_folder(package, name);
2063 if (!f) return ERROR_SUCCESS;
2065 /* reset the ResolvedTarget */
2066 msi_free(f->ResolvedTarget);
2067 f->ResolvedTarget = NULL;
2069 /* This helper function now does ALL the work */
2070 TRACE("Dir %s ...\n",debugstr_w(name));
2071 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2072 TRACE("resolves to %s\n",debugstr_w(path));
2075 return ERROR_SUCCESS;
2078 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2080 MSIPACKAGE *package = param;
2082 MSIFEATURE *feature;
2084 name = MSI_RecordGetString( row, 1 );
2086 feature = get_loaded_feature( package, name );
2088 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2092 Condition = MSI_RecordGetString(row,3);
2094 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2096 int level = MSI_RecordGetInteger(row,2);
2097 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2098 feature->Level = level;
2101 return ERROR_SUCCESS;
2104 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2106 static const WCHAR name[] = {'\\',0};
2107 VS_FIXEDFILEINFO *ptr, *ret;
2109 DWORD versize, handle;
2112 TRACE("%s\n", debugstr_w(filename));
2114 versize = GetFileVersionInfoSizeW( filename, &handle );
2118 version = msi_alloc( versize );
2122 GetFileVersionInfoW( filename, 0, versize, version );
2124 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2126 msi_free( version );
2130 ret = msi_alloc( sz );
2131 memcpy( ret, ptr, sz );
2133 msi_free( version );
2137 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2141 msi_parse_version_string( version, &ms, &ls );
2143 if (fi->dwFileVersionMS > ms) return 1;
2144 else if (fi->dwFileVersionMS < ms) return -1;
2145 else if (fi->dwFileVersionLS > ls) return 1;
2146 else if (fi->dwFileVersionLS < ls) return -1;
2150 static DWORD get_disk_file_size( LPCWSTR filename )
2155 TRACE("%s\n", debugstr_w(filename));
2157 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2158 if (file == INVALID_HANDLE_VALUE)
2159 return INVALID_FILE_SIZE;
2161 size = GetFileSize( file, NULL );
2162 CloseHandle( file );
2166 static BOOL hash_matches( MSIFILE *file )
2169 MSIFILEHASHINFO hash;
2171 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2172 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2173 if (r != ERROR_SUCCESS)
2176 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2179 static WCHAR *get_temp_dir( void )
2182 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2184 GetTempPathW( MAX_PATH, tmp );
2187 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2188 if (CreateDirectoryW( dir, NULL )) break;
2190 return strdupW( dir );
2193 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2195 MSIASSEMBLY *assembly = file->Component->assembly;
2197 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2199 msi_free( file->TargetPath );
2200 if (assembly && !assembly->application)
2202 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2203 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2204 track_tempfile( package, file->TargetPath );
2208 WCHAR *dir = resolve_folder( package, file->Component->Directory, FALSE, FALSE, TRUE, NULL );
2209 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2213 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2216 static UINT set_file_install_states( MSIPACKAGE *package )
2218 VS_FIXEDFILEINFO *file_version;
2221 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2223 MSICOMPONENT *comp = file->Component;
2226 if (!comp->Enabled) continue;
2228 if (file->IsCompressed)
2229 comp->ForceLocalState = TRUE;
2231 set_target_path( package, file );
2233 if ((comp->assembly && !comp->assembly->installed) ||
2234 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2236 file->state = msifs_missing;
2237 comp->Cost += file->FileSize;
2240 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2242 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2243 HIWORD(file_version->dwFileVersionMS),
2244 LOWORD(file_version->dwFileVersionMS),
2245 HIWORD(file_version->dwFileVersionLS),
2246 LOWORD(file_version->dwFileVersionLS));
2248 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2250 file->state = msifs_overwrite;
2251 comp->Cost += file->FileSize;
2255 TRACE("Destination file version equal or greater, not overwriting\n");
2256 file->state = msifs_present;
2258 msi_free( file_version );
2261 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2263 file->state = msifs_overwrite;
2264 comp->Cost += file->FileSize - file_size;
2267 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2269 TRACE("File hashes match, not overwriting\n");
2270 file->state = msifs_present;
2273 file->state = msifs_overwrite;
2274 comp->Cost += file->FileSize - file_size;
2277 return ERROR_SUCCESS;
2281 * A lot is done in this function aside from just the costing.
2282 * The costing needs to be implemented at some point but for now I am going
2283 * to focus on the directory building
2286 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2288 static const WCHAR ExecSeqQuery[] =
2289 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2290 '`','D','i','r','e','c','t','o','r','y','`',0};
2291 static const WCHAR ConditionQuery[] =
2292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2293 '`','C','o','n','d','i','t','i','o','n','`',0};
2294 static const WCHAR szCosting[] =
2295 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2296 static const WCHAR szlevel[] =
2297 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2298 static const WCHAR szOutOfDiskSpace[] =
2299 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2301 UINT rc = ERROR_SUCCESS;
2305 TRACE("Building Directory properties\n");
2307 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2308 if (rc == ERROR_SUCCESS)
2310 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2312 msiobj_release(&view->hdr);
2315 TRACE("Evaluating component conditions\n");
2316 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2318 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2320 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2321 comp->Enabled = FALSE;
2324 comp->Enabled = TRUE;
2327 /* read components states from the registry */
2328 ACTION_GetComponentInstallStates(package);
2329 ACTION_GetFeatureInstallStates(package);
2331 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2333 TRACE("Evaluating feature conditions\n");
2335 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2336 if (rc == ERROR_SUCCESS)
2338 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2339 msiobj_release( &view->hdr );
2343 TRACE("Calculating file install states\n");
2344 set_file_install_states( package );
2346 msi_set_property( package->db, szCosting, szOne );
2347 /* set default run level if not set */
2348 level = msi_dup_property( package->db, szlevel );
2350 msi_set_property( package->db, szlevel, szOne );
2353 /* FIXME: check volume disk space */
2354 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2356 return MSI_SetFeatureStates(package);
2359 /* OK this value is "interpreted" and then formatted based on the
2360 first few characters */
2361 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2366 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2372 LPWSTR deformated = NULL;
2375 deformat_string(package, &value[2], &deformated);
2377 /* binary value type */
2381 *size = (strlenW(ptr)/2)+1;
2383 *size = strlenW(ptr)/2;
2385 data = msi_alloc(*size);
2391 /* if uneven pad with a zero in front */
2397 data[count] = (BYTE)strtol(byte,NULL,0);
2399 TRACE("Uneven byte count\n");
2407 data[count] = (BYTE)strtol(byte,NULL,0);
2410 msi_free(deformated);
2412 TRACE("Data %i bytes(%i)\n",*size,count);
2419 deformat_string(package, &value[1], &deformated);
2422 *size = sizeof(DWORD);
2423 data = msi_alloc(*size);
2429 if ( (*p < '0') || (*p > '9') )
2435 if (deformated[0] == '-')
2438 TRACE("DWORD %i\n",*(LPDWORD)data);
2440 msi_free(deformated);
2445 static const WCHAR szMulti[] = {'[','~',']',0};
2454 *type=REG_EXPAND_SZ;
2462 if (strstrW(value, szMulti))
2463 *type = REG_MULTI_SZ;
2465 /* remove initial delimiter */
2466 if (!strncmpW(value, szMulti, 3))
2469 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2471 /* add double NULL terminator */
2472 if (*type == REG_MULTI_SZ)
2474 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2475 data = msi_realloc_zero(data, *size);
2481 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2488 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2490 *root_key = HKEY_LOCAL_MACHINE;
2495 *root_key = HKEY_CURRENT_USER;
2500 *root_key = HKEY_CLASSES_ROOT;
2504 *root_key = HKEY_CURRENT_USER;
2508 *root_key = HKEY_LOCAL_MACHINE;
2512 *root_key = HKEY_USERS;
2516 ERR("Unknown root %i\n", root);
2523 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2525 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2526 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2528 if (is_64bit && package->platform == PLATFORM_INTEL &&
2529 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2534 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2535 path_32node = msi_alloc( size );
2539 memcpy( path_32node, path, len * sizeof(WCHAR) );
2540 path_32node[len] = 0;
2541 strcatW( path_32node, szWow6432Node );
2542 strcatW( path_32node, szBackSlash );
2543 strcatW( path_32node, path + len );
2547 return strdupW( path );
2550 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2552 MSIPACKAGE *package = param;
2553 LPSTR value_data = NULL;
2554 HKEY root_key, hkey;
2556 LPWSTR deformated, uikey, keypath;
2557 LPCWSTR szRoot, component, name, key, value;
2561 BOOL check_first = FALSE;
2564 ui_progress(package,2,0,0,0);
2566 component = MSI_RecordGetString(row, 6);
2567 comp = get_loaded_component(package,component);
2569 return ERROR_SUCCESS;
2573 TRACE("component is disabled\n");
2574 return ERROR_SUCCESS;
2577 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2579 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2580 comp->Action = comp->Installed;
2581 return ERROR_SUCCESS;
2583 comp->Action = INSTALLSTATE_LOCAL;
2585 name = MSI_RecordGetString(row, 4);
2586 if( MSI_RecordIsNull(row,5) && name )
2588 /* null values can have special meanings */
2589 if (name[0]=='-' && name[1] == 0)
2590 return ERROR_SUCCESS;
2591 else if ((name[0]=='+' && name[1] == 0) ||
2592 (name[0] == '*' && name[1] == 0))
2597 root = MSI_RecordGetInteger(row,2);
2598 key = MSI_RecordGetString(row, 3);
2600 szRoot = get_root_key( package, root, &root_key );
2602 return ERROR_SUCCESS;
2604 deformat_string(package, key , &deformated);
2605 size = strlenW(deformated) + strlenW(szRoot) + 1;
2606 uikey = msi_alloc(size*sizeof(WCHAR));
2607 strcpyW(uikey,szRoot);
2608 strcatW(uikey,deformated);
2610 keypath = get_keypath( package, root_key, deformated );
2611 msi_free( deformated );
2612 if (RegCreateKeyW( root_key, keypath, &hkey ))
2614 ERR("Could not create key %s\n", debugstr_w(keypath));
2616 return ERROR_SUCCESS;
2619 value = MSI_RecordGetString(row,5);
2621 value_data = parse_value(package, value, &type, &size);
2624 value_data = (LPSTR)strdupW(szEmpty);
2625 size = sizeof(szEmpty);
2629 deformat_string(package, name, &deformated);
2633 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2635 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2640 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2641 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2643 TRACE("value %s of %s checked already exists\n",
2644 debugstr_w(deformated), debugstr_w(uikey));
2648 TRACE("Checked and setting value %s of %s\n",
2649 debugstr_w(deformated), debugstr_w(uikey));
2650 if (deformated || size)
2651 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2656 uirow = MSI_CreateRecord(3);
2657 MSI_RecordSetStringW(uirow,2,deformated);
2658 MSI_RecordSetStringW(uirow,1,uikey);
2659 if (type == REG_SZ || type == REG_EXPAND_SZ)
2660 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2661 ui_actiondata(package,szWriteRegistryValues,uirow);
2662 msiobj_release( &uirow->hdr );
2664 msi_free(value_data);
2665 msi_free(deformated);
2668 return ERROR_SUCCESS;
2671 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2675 static const WCHAR ExecSeqQuery[] =
2676 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2677 '`','R','e','g','i','s','t','r','y','`',0 };
2679 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2680 if (rc != ERROR_SUCCESS)
2681 return ERROR_SUCCESS;
2683 /* increment progress bar each time action data is sent */
2684 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2686 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2688 msiobj_release(&view->hdr);
2692 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2696 DWORD num_subkeys, num_values;
2700 if ((res = RegDeleteTreeW( hkey_root, key )))
2702 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2707 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2709 if ((res = RegDeleteValueW( hkey, value )))
2711 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2713 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2714 NULL, NULL, NULL, NULL );
2715 RegCloseKey( hkey );
2716 if (!res && !num_subkeys && !num_values)
2718 TRACE("Removing empty key %s\n", debugstr_w(key));
2719 RegDeleteKeyW( hkey_root, key );
2723 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2727 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2729 MSIPACKAGE *package = param;
2730 LPCWSTR component, name, key_str, root_key_str;
2731 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2734 BOOL delete_key = FALSE;
2739 ui_progress( package, 2, 0, 0, 0 );
2741 component = MSI_RecordGetString( row, 6 );
2742 comp = get_loaded_component( package, component );
2744 return ERROR_SUCCESS;
2748 TRACE("component is disabled\n");
2749 return ERROR_SUCCESS;
2752 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2754 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2755 comp->Action = comp->Installed;
2756 return ERROR_SUCCESS;
2758 comp->Action = INSTALLSTATE_ABSENT;
2760 name = MSI_RecordGetString( row, 4 );
2761 if (MSI_RecordIsNull( row, 5 ) && name )
2763 if (name[0] == '+' && !name[1])
2764 return ERROR_SUCCESS;
2765 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2772 root = MSI_RecordGetInteger( row, 2 );
2773 key_str = MSI_RecordGetString( row, 3 );
2775 root_key_str = get_root_key( package, root, &hkey_root );
2777 return ERROR_SUCCESS;
2779 deformat_string( package, key_str, &deformated_key );
2780 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2781 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2782 strcpyW( ui_key_str, root_key_str );
2783 strcatW( ui_key_str, deformated_key );
2785 deformat_string( package, name, &deformated_name );
2787 keypath = get_keypath( package, hkey_root, deformated_key );
2788 msi_free( deformated_key );
2789 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2790 msi_free( keypath );
2792 uirow = MSI_CreateRecord( 2 );
2793 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2794 MSI_RecordSetStringW( uirow, 2, deformated_name );
2796 ui_actiondata( package, szRemoveRegistryValues, uirow );
2797 msiobj_release( &uirow->hdr );
2799 msi_free( ui_key_str );
2800 msi_free( deformated_name );
2801 return ERROR_SUCCESS;
2804 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2806 MSIPACKAGE *package = param;
2807 LPCWSTR component, name, key_str, root_key_str;
2808 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2811 BOOL delete_key = FALSE;
2816 ui_progress( package, 2, 0, 0, 0 );
2818 component = MSI_RecordGetString( row, 5 );
2819 comp = get_loaded_component( package, component );
2821 return ERROR_SUCCESS;
2825 TRACE("component is disabled\n");
2826 return ERROR_SUCCESS;
2829 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2831 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2832 comp->Action = comp->Installed;
2833 return ERROR_SUCCESS;
2835 comp->Action = INSTALLSTATE_LOCAL;
2837 if ((name = MSI_RecordGetString( row, 4 )))
2839 if (name[0] == '-' && !name[1])
2846 root = MSI_RecordGetInteger( row, 2 );
2847 key_str = MSI_RecordGetString( row, 3 );
2849 root_key_str = get_root_key( package, root, &hkey_root );
2851 return ERROR_SUCCESS;
2853 deformat_string( package, key_str, &deformated_key );
2854 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2855 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2856 strcpyW( ui_key_str, root_key_str );
2857 strcatW( ui_key_str, deformated_key );
2859 deformat_string( package, name, &deformated_name );
2861 keypath = get_keypath( package, hkey_root, deformated_key );
2862 msi_free( deformated_key );
2863 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2864 msi_free( keypath );
2866 uirow = MSI_CreateRecord( 2 );
2867 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2868 MSI_RecordSetStringW( uirow, 2, deformated_name );
2870 ui_actiondata( package, szRemoveRegistryValues, uirow );
2871 msiobj_release( &uirow->hdr );
2873 msi_free( ui_key_str );
2874 msi_free( deformated_name );
2875 return ERROR_SUCCESS;
2878 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2882 static const WCHAR registry_query[] =
2883 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2884 '`','R','e','g','i','s','t','r','y','`',0 };
2885 static const WCHAR remove_registry_query[] =
2886 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2887 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2889 /* increment progress bar each time action data is sent */
2890 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2892 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2893 if (rc == ERROR_SUCCESS)
2895 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2896 msiobj_release( &view->hdr );
2897 if (rc != ERROR_SUCCESS)
2901 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2902 if (rc == ERROR_SUCCESS)
2904 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2905 msiobj_release( &view->hdr );
2906 if (rc != ERROR_SUCCESS)
2910 return ERROR_SUCCESS;
2913 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2915 package->script->CurrentlyScripting = TRUE;
2917 return ERROR_SUCCESS;
2921 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2926 static const WCHAR q1[]=
2927 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2928 '`','R','e','g','i','s','t','r','y','`',0};
2931 MSIFEATURE *feature;
2934 TRACE("InstallValidate\n");
2936 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2937 if (rc == ERROR_SUCCESS)
2939 MSI_IterateRecords( view, &progress, NULL, package );
2940 msiobj_release( &view->hdr );
2941 total += progress * REG_PROGRESS_VALUE;
2944 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2945 total += COMPONENT_PROGRESS_VALUE;
2947 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2948 total += file->FileSize;
2950 ui_progress(package,0,total,0,0);
2952 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2954 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2955 debugstr_w(feature->Feature), feature->Installed,
2956 feature->ActionRequest, feature->Action);
2959 return ERROR_SUCCESS;
2962 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2964 MSIPACKAGE* package = param;
2965 LPCWSTR cond = NULL;
2966 LPCWSTR message = NULL;
2969 static const WCHAR title[]=
2970 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2972 cond = MSI_RecordGetString(row,1);
2974 r = MSI_EvaluateConditionW(package,cond);
2975 if (r == MSICONDITION_FALSE)
2977 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2980 message = MSI_RecordGetString(row,2);
2981 deformat_string(package,message,&deformated);
2982 MessageBoxW(NULL,deformated,title,MB_OK);
2983 msi_free(deformated);
2986 return ERROR_INSTALL_FAILURE;
2989 return ERROR_SUCCESS;
2992 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2995 MSIQUERY * view = NULL;
2996 static const WCHAR ExecSeqQuery[] =
2997 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2998 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3000 TRACE("Checking launch conditions\n");
3002 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3003 if (rc != ERROR_SUCCESS)
3004 return ERROR_SUCCESS;
3006 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3007 msiobj_release(&view->hdr);
3012 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3016 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
3018 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3020 MSIRECORD * row = 0;
3022 LPWSTR deformated,buffer,deformated_name;
3024 static const WCHAR ExecSeqQuery[] =
3025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3026 '`','R','e','g','i','s','t','r','y','`',' ',
3027 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3028 ' ','=',' ' ,'\'','%','s','\'',0 };
3029 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3030 static const WCHAR fmt2[]=
3031 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3033 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3037 root = MSI_RecordGetInteger(row,2);
3038 key = MSI_RecordGetString(row, 3);
3039 name = MSI_RecordGetString(row, 4);
3040 deformat_string(package, key , &deformated);
3041 deformat_string(package, name, &deformated_name);
3043 len = strlenW(deformated) + 6;
3044 if (deformated_name)
3045 len+=strlenW(deformated_name);
3047 buffer = msi_alloc( len *sizeof(WCHAR));
3049 if (deformated_name)
3050 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3052 sprintfW(buffer,fmt,root,deformated);
3054 msi_free(deformated);
3055 msi_free(deformated_name);
3056 msiobj_release(&row->hdr);
3060 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3062 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3067 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3070 return strdupW( file->TargetPath );
3075 static HKEY openSharedDLLsKey(void)
3078 static const WCHAR path[] =
3079 {'S','o','f','t','w','a','r','e','\\',
3080 'M','i','c','r','o','s','o','f','t','\\',
3081 'W','i','n','d','o','w','s','\\',
3082 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3083 'S','h','a','r','e','d','D','L','L','s',0};
3085 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3089 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3094 DWORD sz = sizeof(count);
3097 hkey = openSharedDLLsKey();
3098 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3099 if (rc != ERROR_SUCCESS)
3105 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3109 hkey = openSharedDLLsKey();
3111 msi_reg_set_val_dword( hkey, path, count );
3113 RegDeleteValueW(hkey,path);
3119 * Return TRUE if the count should be written out and FALSE if not
3121 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3123 MSIFEATURE *feature;
3127 /* only refcount DLLs */
3128 if (comp->KeyPath == NULL ||
3129 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3130 comp->Attributes & msidbComponentAttributesODBCDataSource)
3134 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3135 write = (count > 0);
3137 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3141 /* increment counts */
3142 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3146 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3149 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3151 if ( cl->component == comp )
3156 /* decrement counts */
3157 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3161 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3164 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3166 if ( cl->component == comp )
3171 /* ref count all the files in the component */
3176 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3178 if (file->Component == comp)
3179 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3183 /* add a count for permanent */
3184 if (comp->Attributes & msidbComponentAttributesPermanent)
3187 comp->RefCount = count;
3190 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3193 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3195 WCHAR squished_pc[GUID_SIZE];
3196 WCHAR squished_cc[GUID_SIZE];
3203 squash_guid(package->ProductCode,squished_pc);
3204 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3206 msi_set_sourcedir_props(package, FALSE);
3208 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3212 ui_progress(package,2,0,0,0);
3213 if (!comp->ComponentId)
3216 squash_guid(comp->ComponentId,squished_cc);
3218 msi_free(comp->FullKeypath);
3219 comp->FullKeypath = resolve_keypath( package, comp );
3221 ACTION_RefCountComponent( package, comp );
3223 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3224 debugstr_w(comp->Component),
3225 debugstr_w(squished_cc),
3226 debugstr_w(comp->FullKeypath),
3228 comp->ActionRequest);
3230 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3231 comp->ActionRequest == INSTALLSTATE_SOURCE)
3233 if (!comp->FullKeypath)
3236 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3237 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3240 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3243 if (rc != ERROR_SUCCESS)
3246 if (comp->Attributes & msidbComponentAttributesPermanent)
3248 static const WCHAR szPermKey[] =
3249 { '0','0','0','0','0','0','0','0','0','0','0','0',
3250 '0','0','0','0','0','0','0','0','0','0','0','0',
3251 '0','0','0','0','0','0','0','0',0 };
3253 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3256 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3257 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3263 WCHAR source[MAX_PATH];
3264 WCHAR base[MAX_PATH];
3267 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3268 static const WCHAR query[] = {
3269 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3270 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3271 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3272 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3273 '`','D','i','s','k','I','d','`',0};
3275 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3278 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3279 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3280 ptr2 = strrchrW(source, '\\') + 1;
3281 msiobj_release(&row->hdr);
3283 lstrcpyW(base, package->PackagePath);
3284 ptr = strrchrW(base, '\\');
3287 sourcepath = resolve_file_source(package, file);
3288 ptr = sourcepath + lstrlenW(base);
3289 lstrcpyW(ptr2, ptr);
3290 msi_free(sourcepath);
3292 msi_reg_set_val_str(hkey, squished_pc, source);
3296 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3298 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3299 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3301 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3303 comp->Action = comp->ActionRequest;
3306 uirow = MSI_CreateRecord(3);
3307 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3308 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3309 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3310 ui_actiondata(package,szProcessComponents,uirow);
3311 msiobj_release( &uirow->hdr );
3314 return ERROR_SUCCESS;
3325 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3326 LPWSTR lpszName, LONG_PTR lParam)
3329 typelib_struct *tl_struct = (typelib_struct*) lParam;
3330 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3334 if (!IS_INTRESOURCE(lpszName))
3336 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3340 sz = strlenW(tl_struct->source)+4;
3341 sz *= sizeof(WCHAR);
3343 if ((INT_PTR)lpszName == 1)
3344 tl_struct->path = strdupW(tl_struct->source);
3347 tl_struct->path = msi_alloc(sz);
3348 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3351 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3352 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3355 msi_free(tl_struct->path);
3356 tl_struct->path = NULL;
3361 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3362 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3364 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3368 msi_free(tl_struct->path);
3369 tl_struct->path = NULL;
3371 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3372 ITypeLib_Release(tl_struct->ptLib);
3377 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3379 MSIPACKAGE* package = param;
3383 typelib_struct tl_struct;
3388 component = MSI_RecordGetString(row,3);
3389 comp = get_loaded_component(package,component);
3391 return ERROR_SUCCESS;
3395 TRACE("component is disabled\n");
3396 return ERROR_SUCCESS;
3399 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3401 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3402 comp->Action = comp->Installed;
3403 return ERROR_SUCCESS;
3405 comp->Action = INSTALLSTATE_LOCAL;
3407 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3409 TRACE("component has no key path\n");
3410 return ERROR_SUCCESS;
3412 ui_actiondata( package, szRegisterTypeLibraries, row );
3414 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3418 guid = MSI_RecordGetString(row,1);
3419 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3420 tl_struct.source = strdupW( file->TargetPath );
3421 tl_struct.path = NULL;
3423 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3424 (LONG_PTR)&tl_struct);
3432 helpid = MSI_RecordGetString(row,6);
3435 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3436 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3440 ERR("Failed to register type library %s\n",
3441 debugstr_w(tl_struct.path));
3443 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3445 ITypeLib_Release(tl_struct.ptLib);
3446 msi_free(tl_struct.path);
3449 ERR("Failed to load type library %s\n",
3450 debugstr_w(tl_struct.source));
3452 FreeLibrary(module);
3453 msi_free(tl_struct.source);
3457 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3460 ERR("Failed to load type library: %08x\n", hr);
3461 return ERROR_INSTALL_FAILURE;
3464 ITypeLib_Release(tlib);
3467 return ERROR_SUCCESS;
3470 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3473 * OK this is a bit confusing.. I am given a _Component key and I believe
3474 * that the file that is being registered as a type library is the "key file
3475 * of that component" which I interpret to mean "The file in the KeyPath of
3480 static const WCHAR Query[] =
3481 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3482 '`','T','y','p','e','L','i','b','`',0};
3484 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3485 if (rc != ERROR_SUCCESS)
3486 return ERROR_SUCCESS;
3488 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3489 msiobj_release(&view->hdr);
3493 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3495 MSIPACKAGE *package = param;
3496 LPCWSTR component, guid;
3504 component = MSI_RecordGetString( row, 3 );
3505 comp = get_loaded_component( package, component );
3507 return ERROR_SUCCESS;
3511 TRACE("component is disabled\n");
3512 return ERROR_SUCCESS;
3515 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3517 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3518 comp->Action = comp->Installed;
3519 return ERROR_SUCCESS;
3521 comp->Action = INSTALLSTATE_ABSENT;
3523 ui_actiondata( package, szUnregisterTypeLibraries, row );
3525 guid = MSI_RecordGetString( row, 1 );
3526 CLSIDFromString( (LPCWSTR)guid, &libid );
3527 version = MSI_RecordGetInteger( row, 4 );
3528 language = MSI_RecordGetInteger( row, 2 );
3531 syskind = SYS_WIN64;
3533 syskind = SYS_WIN32;
3536 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3539 WARN("Failed to unregister typelib: %08x\n", hr);
3542 return ERROR_SUCCESS;
3545 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3549 static const WCHAR query[] =
3550 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3551 '`','T','y','p','e','L','i','b','`',0};
3553 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3554 if (rc != ERROR_SUCCESS)
3555 return ERROR_SUCCESS;
3557 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3558 msiobj_release( &view->hdr );
3562 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3564 static const WCHAR szlnk[] = {'.','l','n','k',0};
3565 LPCWSTR directory, extension;
3566 LPWSTR link_folder, link_file, filename;
3568 directory = MSI_RecordGetString( row, 2 );
3569 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3571 /* may be needed because of a bug somewhere else */
3572 create_full_pathW( link_folder );
3574 filename = msi_dup_record_field( row, 3 );
3575 reduce_to_longfilename( filename );
3577 extension = strchrW( filename, '.' );
3578 if (!extension || strcmpiW( extension, szlnk ))
3580 int len = strlenW( filename );
3581 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3582 memcpy( filename + len, szlnk, sizeof(szlnk) );
3584 link_file = build_directory_name( 2, link_folder, filename );
3585 msi_free( link_folder );
3586 msi_free( filename );
3591 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3593 MSIPACKAGE *package = param;
3594 LPWSTR link_file, deformated, path;
3595 LPCWSTR component, target;
3597 IShellLinkW *sl = NULL;
3598 IPersistFile *pf = NULL;
3601 component = MSI_RecordGetString(row, 4);
3602 comp = get_loaded_component(package, component);
3604 return ERROR_SUCCESS;
3608 TRACE("component is disabled\n");
3609 return ERROR_SUCCESS;
3612 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3614 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3615 comp->Action = comp->Installed;
3616 return ERROR_SUCCESS;
3618 comp->Action = INSTALLSTATE_LOCAL;
3620 ui_actiondata(package,szCreateShortcuts,row);
3622 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3623 &IID_IShellLinkW, (LPVOID *) &sl );
3627 ERR("CLSID_ShellLink not available\n");
3631 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3634 ERR("QueryInterface(IID_IPersistFile) failed\n");
3638 target = MSI_RecordGetString(row, 5);
3639 if (strchrW(target, '['))
3641 deformat_string(package, target, &deformated);
3642 IShellLinkW_SetPath(sl,deformated);
3643 msi_free(deformated);
3647 FIXME("poorly handled shortcut format, advertised shortcut\n");
3648 IShellLinkW_SetPath(sl,comp->FullKeypath);
3651 if (!MSI_RecordIsNull(row,6))
3653 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3654 deformat_string(package, arguments, &deformated);
3655 IShellLinkW_SetArguments(sl,deformated);
3656 msi_free(deformated);
3659 if (!MSI_RecordIsNull(row,7))
3661 LPCWSTR description = MSI_RecordGetString(row, 7);
3662 IShellLinkW_SetDescription(sl, description);
3665 if (!MSI_RecordIsNull(row,8))
3666 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3668 if (!MSI_RecordIsNull(row,9))
3671 LPCWSTR icon = MSI_RecordGetString(row, 9);
3673 path = build_icon_path(package, icon);
3674 index = MSI_RecordGetInteger(row,10);
3676 /* no value means 0 */
3677 if (index == MSI_NULL_INTEGER)
3680 IShellLinkW_SetIconLocation(sl, path, index);
3684 if (!MSI_RecordIsNull(row,11))
3685 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3687 if (!MSI_RecordIsNull(row,12))
3689 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3690 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3692 IShellLinkW_SetWorkingDirectory(sl, path);
3696 link_file = get_link_file(package, row);
3698 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3699 IPersistFile_Save(pf, link_file, FALSE);
3701 msi_free(link_file);
3705 IPersistFile_Release( pf );
3707 IShellLinkW_Release( sl );
3709 return ERROR_SUCCESS;
3712 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3717 static const WCHAR Query[] =
3718 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3719 '`','S','h','o','r','t','c','u','t','`',0};
3721 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3722 if (rc != ERROR_SUCCESS)
3723 return ERROR_SUCCESS;
3725 res = CoInitialize( NULL );
3727 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3728 msiobj_release(&view->hdr);
3736 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3738 MSIPACKAGE *package = param;
3743 component = MSI_RecordGetString( row, 4 );
3744 comp = get_loaded_component( package, component );
3746 return ERROR_SUCCESS;
3750 TRACE("component is disabled\n");
3751 return ERROR_SUCCESS;
3754 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3756 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3757 comp->Action = comp->Installed;
3758 return ERROR_SUCCESS;
3760 comp->Action = INSTALLSTATE_ABSENT;
3762 ui_actiondata( package, szRemoveShortcuts, row );
3764 link_file = get_link_file( package, row );
3766 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3767 if (!DeleteFileW( link_file ))
3769 WARN("Failed to remove shortcut file %u\n", GetLastError());
3771 msi_free( link_file );
3773 return ERROR_SUCCESS;
3776 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3780 static const WCHAR query[] =
3781 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3782 '`','S','h','o','r','t','c','u','t','`',0};
3784 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3785 if (rc != ERROR_SUCCESS)
3786 return ERROR_SUCCESS;
3788 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3789 msiobj_release( &view->hdr );
3794 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3796 MSIPACKAGE* package = param;
3804 FileName = MSI_RecordGetString(row,1);
3807 ERR("Unable to get FileName\n");
3808 return ERROR_SUCCESS;
3811 FilePath = build_icon_path(package,FileName);
3813 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3815 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3816 FILE_ATTRIBUTE_NORMAL, NULL);
3818 if (the_file == INVALID_HANDLE_VALUE)
3820 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3822 return ERROR_SUCCESS;
3829 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3830 if (rc != ERROR_SUCCESS)
3832 ERR("Failed to get stream\n");
3833 CloseHandle(the_file);
3834 DeleteFileW(FilePath);
3837 WriteFile(the_file,buffer,sz,&write,NULL);
3838 } while (sz == 1024);
3841 CloseHandle(the_file);
3843 return ERROR_SUCCESS;
3846 static UINT msi_publish_icons(MSIPACKAGE *package)
3851 static const WCHAR query[]= {
3852 'S','E','L','E','C','T',' ','*',' ',
3853 'F','R','O','M',' ','`','I','c','o','n','`',0};
3855 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3856 if (r == ERROR_SUCCESS)
3858 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3859 msiobj_release(&view->hdr);
3862 return ERROR_SUCCESS;
3865 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3871 MSISOURCELISTINFO *info;
3873 r = RegCreateKeyW(hkey, szSourceList, &source);
3874 if (r != ERROR_SUCCESS)
3877 RegCloseKey(source);
3879 buffer = strrchrW(package->PackagePath, '\\') + 1;
3880 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3881 package->Context, MSICODE_PRODUCT,
3882 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3883 if (r != ERROR_SUCCESS)
3886 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3887 package->Context, MSICODE_PRODUCT,
3888 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3889 if (r != ERROR_SUCCESS)
3892 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3893 package->Context, MSICODE_PRODUCT,
3894 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3895 if (r != ERROR_SUCCESS)
3898 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3900 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3901 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3902 info->options, info->value);
3904 MsiSourceListSetInfoW(package->ProductCode, NULL,
3905 info->context, info->options,
3906 info->property, info->value);
3909 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3911 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3912 disk->context, disk->options,
3913 disk->disk_id, disk->volume_label, disk->disk_prompt);
3916 return ERROR_SUCCESS;
3919 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3921 MSIHANDLE hdb, suminfo;
3922 WCHAR guids[MAX_PATH];
3923 WCHAR packcode[SQUISH_GUID_SIZE];
3930 static const WCHAR szProductLanguage[] =
3931 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3932 static const WCHAR szARPProductIcon[] =
3933 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3934 static const WCHAR szProductVersion[] =
3935 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3936 static const WCHAR szAssignment[] =
3937 {'A','s','s','i','g','n','m','e','n','t',0};
3938 static const WCHAR szAdvertiseFlags[] =
3939 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3940 static const WCHAR szClients[] =
3941 {'C','l','i','e','n','t','s',0};
3942 static const WCHAR szColon[] = {':',0};
3944 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3945 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3948 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3949 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3952 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3954 buffer = msi_dup_property(package->db, szARPProductIcon);
3957 LPWSTR path = build_icon_path(package,buffer);
3958 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3963 buffer = msi_dup_property(package->db, szProductVersion);
3966 DWORD verdword = msi_version_str_to_dword(buffer);
3967 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3971 msi_reg_set_val_dword(hkey, szAssignment, 0);
3972 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3973 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3974 msi_reg_set_val_str(hkey, szClients, szColon);
3976 hdb = alloc_msihandle(&package->db->hdr);
3978 return ERROR_NOT_ENOUGH_MEMORY;
3980 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3981 MsiCloseHandle(hdb);
3982 if (r != ERROR_SUCCESS)
3986 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3987 NULL, guids, &size);
3988 if (r != ERROR_SUCCESS)
3991 ptr = strchrW(guids, ';');
3993 squash_guid(guids, packcode);
3994 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3997 MsiCloseHandle(suminfo);
3998 return ERROR_SUCCESS;
4001 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4006 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4008 upgrade = msi_dup_property(package->db, szUpgradeCode);
4010 return ERROR_SUCCESS;
4012 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4014 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4015 if (r != ERROR_SUCCESS)
4020 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4021 if (r != ERROR_SUCCESS)
4025 squash_guid(package->ProductCode, squashed_pc);
4026 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4035 static BOOL msi_check_publish(MSIPACKAGE *package)
4037 MSIFEATURE *feature;
4039 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4041 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4048 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4050 MSIFEATURE *feature;
4052 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4054 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4061 static UINT msi_publish_patches( MSIPACKAGE *package )
4063 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4064 WCHAR patch_squashed[GUID_SIZE];
4065 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4067 MSIPATCHINFO *patch;
4069 WCHAR *p, *all_patches = NULL;
4072 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4073 if (r != ERROR_SUCCESS)
4074 return ERROR_FUNCTION_FAILED;
4076 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4077 if (res != ERROR_SUCCESS)
4079 r = ERROR_FUNCTION_FAILED;
4083 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4084 if (r != ERROR_SUCCESS)
4087 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4089 squash_guid( patch->patchcode, patch_squashed );
4090 len += strlenW( patch_squashed ) + 1;
4093 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4097 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4101 squash_guid( patch->patchcode, p );
4102 p += strlenW( p ) + 1;
4104 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4105 (const BYTE *)patch->transforms,
4106 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4107 if (res != ERROR_SUCCESS)
4110 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4111 if (r != ERROR_SUCCESS)
4114 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4115 (const BYTE *)patch->localfile,
4116 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4117 RegCloseKey( patch_key );
4118 if (res != ERROR_SUCCESS)
4121 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4122 if (res != ERROR_SUCCESS)
4125 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4126 RegCloseKey( patch_key );
4127 if (res != ERROR_SUCCESS)
4131 all_patches[len] = 0;
4132 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4133 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4134 if (res != ERROR_SUCCESS)
4137 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4138 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4139 if (res != ERROR_SUCCESS)
4140 r = ERROR_FUNCTION_FAILED;
4143 RegCloseKey( product_patches_key );
4144 RegCloseKey( patches_key );
4145 RegCloseKey( product_key );
4146 msi_free( all_patches );
4151 * 99% of the work done here is only done for
4152 * advertised installs. However this is where the
4153 * Icon table is processed and written out
4154 * so that is what I am going to do here.
4156 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4159 HKEY hukey = NULL, hudkey = NULL;
4162 if (!list_empty(&package->patches))
4164 rc = msi_publish_patches(package);
4165 if (rc != ERROR_SUCCESS)
4169 /* FIXME: also need to publish if the product is in advertise mode */
4170 if (!msi_check_publish(package))
4171 return ERROR_SUCCESS;
4173 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4175 if (rc != ERROR_SUCCESS)
4178 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4179 NULL, &hudkey, TRUE);
4180 if (rc != ERROR_SUCCESS)
4183 rc = msi_publish_upgrade_code(package);
4184 if (rc != ERROR_SUCCESS)
4187 rc = msi_publish_product_properties(package, hukey);
4188 if (rc != ERROR_SUCCESS)
4191 rc = msi_publish_sourcelist(package, hukey);
4192 if (rc != ERROR_SUCCESS)
4195 rc = msi_publish_icons(package);
4198 uirow = MSI_CreateRecord( 1 );
4199 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4200 ui_actiondata( package, szPublishProduct, uirow );
4201 msiobj_release( &uirow->hdr );
4204 RegCloseKey(hudkey);
4209 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4211 WCHAR *filename, *ptr, *folder, *ret;
4212 const WCHAR *dirprop;
4214 filename = msi_dup_record_field( row, 2 );
4215 if (filename && (ptr = strchrW( filename, '|' )))
4220 dirprop = MSI_RecordGetString( row, 3 );
4223 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4225 folder = msi_dup_property( package->db, dirprop );
4228 folder = msi_dup_property( package->db, szWindowsFolder );
4232 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4233 msi_free( filename );
4237 ret = build_directory_name( 2, folder, ptr );
4239 msi_free( filename );
4244 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4246 MSIPACKAGE *package = param;
4247 LPCWSTR component, section, key, value, identifier;
4248 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4253 component = MSI_RecordGetString(row, 8);
4254 comp = get_loaded_component(package,component);
4256 return ERROR_SUCCESS;
4260 TRACE("component is disabled\n");
4261 return ERROR_SUCCESS;
4264 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4266 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4267 comp->Action = comp->Installed;
4268 return ERROR_SUCCESS;
4270 comp->Action = INSTALLSTATE_LOCAL;
4272 identifier = MSI_RecordGetString(row,1);
4273 section = MSI_RecordGetString(row,4);
4274 key = MSI_RecordGetString(row,5);
4275 value = MSI_RecordGetString(row,6);
4276 action = MSI_RecordGetInteger(row,7);
4278 deformat_string(package,section,&deformated_section);
4279 deformat_string(package,key,&deformated_key);
4280 deformat_string(package,value,&deformated_value);
4282 fullname = get_ini_file_name(package, row);
4286 TRACE("Adding value %s to section %s in %s\n",
4287 debugstr_w(deformated_key), debugstr_w(deformated_section),
4288 debugstr_w(fullname));
4289 WritePrivateProfileStringW(deformated_section, deformated_key,
4290 deformated_value, fullname);
4292 else if (action == 1)
4295 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4296 returned, 10, fullname);
4297 if (returned[0] == 0)
4299 TRACE("Adding value %s to section %s in %s\n",
4300 debugstr_w(deformated_key), debugstr_w(deformated_section),
4301 debugstr_w(fullname));
4303 WritePrivateProfileStringW(deformated_section, deformated_key,
4304 deformated_value, fullname);
4307 else if (action == 3)
4308 FIXME("Append to existing section not yet implemented\n");
4310 uirow = MSI_CreateRecord(4);
4311 MSI_RecordSetStringW(uirow,1,identifier);
4312 MSI_RecordSetStringW(uirow,2,deformated_section);
4313 MSI_RecordSetStringW(uirow,3,deformated_key);
4314 MSI_RecordSetStringW(uirow,4,deformated_value);
4315 ui_actiondata(package,szWriteIniValues,uirow);
4316 msiobj_release( &uirow->hdr );
4319 msi_free(deformated_key);
4320 msi_free(deformated_value);
4321 msi_free(deformated_section);
4322 return ERROR_SUCCESS;
4325 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4329 static const WCHAR ExecSeqQuery[] =
4330 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4331 '`','I','n','i','F','i','l','e','`',0};
4333 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4334 if (rc != ERROR_SUCCESS)
4336 TRACE("no IniFile table\n");
4337 return ERROR_SUCCESS;
4340 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4341 msiobj_release(&view->hdr);
4345 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4347 MSIPACKAGE *package = param;
4348 LPCWSTR component, section, key, value, identifier;
4349 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4354 component = MSI_RecordGetString( row, 8 );
4355 comp = get_loaded_component( package, component );
4357 return ERROR_SUCCESS;
4361 TRACE("component is disabled\n");
4362 return ERROR_SUCCESS;
4365 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4367 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4368 comp->Action = comp->Installed;
4369 return ERROR_SUCCESS;
4371 comp->Action = INSTALLSTATE_ABSENT;
4373 identifier = MSI_RecordGetString( row, 1 );
4374 section = MSI_RecordGetString( row, 4 );
4375 key = MSI_RecordGetString( row, 5 );
4376 value = MSI_RecordGetString( row, 6 );
4377 action = MSI_RecordGetInteger( row, 7 );
4379 deformat_string( package, section, &deformated_section );
4380 deformat_string( package, key, &deformated_key );
4381 deformat_string( package, value, &deformated_value );
4383 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4385 filename = get_ini_file_name( package, row );
4387 TRACE("Removing key %s from section %s in %s\n",
4388 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4390 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4392 WARN("Unable to remove key %u\n", GetLastError());
4394 msi_free( filename );
4397 FIXME("Unsupported action %d\n", action);
4400 uirow = MSI_CreateRecord( 4 );
4401 MSI_RecordSetStringW( uirow, 1, identifier );
4402 MSI_RecordSetStringW( uirow, 2, deformated_section );
4403 MSI_RecordSetStringW( uirow, 3, deformated_key );
4404 MSI_RecordSetStringW( uirow, 4, deformated_value );
4405 ui_actiondata( package, szRemoveIniValues, uirow );
4406 msiobj_release( &uirow->hdr );
4408 msi_free( deformated_key );
4409 msi_free( deformated_value );
4410 msi_free( deformated_section );
4411 return ERROR_SUCCESS;
4414 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4416 MSIPACKAGE *package = param;
4417 LPCWSTR component, section, key, value, identifier;
4418 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4423 component = MSI_RecordGetString( row, 8 );
4424 comp = get_loaded_component( package, component );
4426 return ERROR_SUCCESS;
4430 TRACE("component is disabled\n");
4431 return ERROR_SUCCESS;
4434 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4436 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4437 comp->Action = comp->Installed;
4438 return ERROR_SUCCESS;
4440 comp->Action = INSTALLSTATE_LOCAL;
4442 identifier = MSI_RecordGetString( row, 1 );
4443 section = MSI_RecordGetString( row, 4 );
4444 key = MSI_RecordGetString( row, 5 );
4445 value = MSI_RecordGetString( row, 6 );
4446 action = MSI_RecordGetInteger( row, 7 );
4448 deformat_string( package, section, &deformated_section );
4449 deformat_string( package, key, &deformated_key );
4450 deformat_string( package, value, &deformated_value );
4452 if (action == msidbIniFileActionRemoveLine)
4454 filename = get_ini_file_name( package, row );
4456 TRACE("Removing key %s from section %s in %s\n",
4457 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4459 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4461 WARN("Unable to remove key %u\n", GetLastError());
4463 msi_free( filename );
4466 FIXME("Unsupported action %d\n", action);
4468 uirow = MSI_CreateRecord( 4 );
4469 MSI_RecordSetStringW( uirow, 1, identifier );
4470 MSI_RecordSetStringW( uirow, 2, deformated_section );
4471 MSI_RecordSetStringW( uirow, 3, deformated_key );
4472 MSI_RecordSetStringW( uirow, 4, deformated_value );
4473 ui_actiondata( package, szRemoveIniValues, uirow );
4474 msiobj_release( &uirow->hdr );
4476 msi_free( deformated_key );
4477 msi_free( deformated_value );
4478 msi_free( deformated_section );
4479 return ERROR_SUCCESS;
4482 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4486 static const WCHAR query[] =
4487 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4488 '`','I','n','i','F','i','l','e','`',0};
4489 static const WCHAR remove_query[] =
4490 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4491 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4493 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4494 if (rc == ERROR_SUCCESS)
4496 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4497 msiobj_release( &view->hdr );
4498 if (rc != ERROR_SUCCESS)
4502 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4503 if (rc == ERROR_SUCCESS)
4505 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4506 msiobj_release( &view->hdr );
4507 if (rc != ERROR_SUCCESS)
4511 return ERROR_SUCCESS;
4514 static void register_dll( const WCHAR *dll, BOOL unregister )
4518 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4521 HRESULT (WINAPI *func_ptr)( void );
4522 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4524 func_ptr = (void *)GetProcAddress( hmod, func );
4527 HRESULT hr = func_ptr();
4529 WARN("failed to register dll 0x%08x\n", hr);
4532 WARN("entry point %s not found\n", func);
4533 FreeLibrary( hmod );
4536 WARN("failed to load library %u\n", GetLastError());
4539 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4541 MSIPACKAGE *package = param;
4546 filename = MSI_RecordGetString(row,1);
4547 file = get_loaded_file( package, filename );
4551 ERR("Unable to find file id %s\n",debugstr_w(filename));
4552 return ERROR_SUCCESS;
4555 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4557 register_dll( file->TargetPath, FALSE );
4559 uirow = MSI_CreateRecord( 2 );
4560 MSI_RecordSetStringW( uirow, 1, filename );
4561 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4562 ui_actiondata( package, szSelfRegModules, uirow );
4563 msiobj_release( &uirow->hdr );
4565 return ERROR_SUCCESS;
4568 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4572 static const WCHAR ExecSeqQuery[] =
4573 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4574 '`','S','e','l','f','R','e','g','`',0};
4576 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4577 if (rc != ERROR_SUCCESS)
4579 TRACE("no SelfReg table\n");
4580 return ERROR_SUCCESS;
4583 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4584 msiobj_release(&view->hdr);
4586 return ERROR_SUCCESS;
4589 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4591 MSIPACKAGE *package = param;
4596 filename = MSI_RecordGetString( row, 1 );
4597 file = get_loaded_file( package, filename );
4601 ERR("Unable to find file id %s\n", debugstr_w(filename));
4602 return ERROR_SUCCESS;
4605 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4607 register_dll( file->TargetPath, TRUE );
4609 uirow = MSI_CreateRecord( 2 );
4610 MSI_RecordSetStringW( uirow, 1, filename );
4611 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4612 ui_actiondata( package, szSelfUnregModules, uirow );
4613 msiobj_release( &uirow->hdr );
4615 return ERROR_SUCCESS;
4618 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4622 static const WCHAR query[] =
4623 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4624 '`','S','e','l','f','R','e','g','`',0};
4626 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4627 if (rc != ERROR_SUCCESS)
4629 TRACE("no SelfReg table\n");
4630 return ERROR_SUCCESS;
4633 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4634 msiobj_release( &view->hdr );
4636 return ERROR_SUCCESS;
4639 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4641 MSIFEATURE *feature;
4643 HKEY hkey = NULL, userdata = NULL;
4645 if (!msi_check_publish(package))
4646 return ERROR_SUCCESS;
4648 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4650 if (rc != ERROR_SUCCESS)
4653 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4655 if (rc != ERROR_SUCCESS)
4658 /* here the guids are base 85 encoded */
4659 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4665 BOOL absent = FALSE;
4668 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4669 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4670 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4673 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4677 if (feature->Feature_Parent)
4678 size += strlenW( feature->Feature_Parent )+2;
4680 data = msi_alloc(size * sizeof(WCHAR));
4683 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4685 MSICOMPONENT* component = cl->component;
4689 if (component->ComponentId)
4691 TRACE("From %s\n",debugstr_w(component->ComponentId));
4692 CLSIDFromString(component->ComponentId, &clsid);
4693 encode_base85_guid(&clsid,buf);
4694 TRACE("to %s\n",debugstr_w(buf));
4699 if (feature->Feature_Parent)
4701 static const WCHAR sep[] = {'\2',0};
4703 strcatW(data,feature->Feature_Parent);
4706 msi_reg_set_val_str( userdata, feature->Feature, data );
4710 if (feature->Feature_Parent)
4711 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4714 size += sizeof(WCHAR);
4715 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4716 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4720 size += 2*sizeof(WCHAR);
4721 data = msi_alloc(size);
4724 if (feature->Feature_Parent)
4725 strcpyW( &data[1], feature->Feature_Parent );
4726 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4732 uirow = MSI_CreateRecord( 1 );
4733 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4734 ui_actiondata( package, szPublishFeatures, uirow);
4735 msiobj_release( &uirow->hdr );
4736 /* FIXME: call ui_progress? */
4741 RegCloseKey(userdata);
4745 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4751 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4753 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4755 if (r == ERROR_SUCCESS)
4757 RegDeleteValueW(hkey, feature->Feature);
4761 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4763 if (r == ERROR_SUCCESS)
4765 RegDeleteValueW(hkey, feature->Feature);
4769 uirow = MSI_CreateRecord( 1 );
4770 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4771 ui_actiondata( package, szUnpublishFeatures, uirow );
4772 msiobj_release( &uirow->hdr );
4774 return ERROR_SUCCESS;
4777 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4779 MSIFEATURE *feature;
4781 if (!msi_check_unpublish(package))
4782 return ERROR_SUCCESS;
4784 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4786 msi_unpublish_feature(package, feature);
4789 return ERROR_SUCCESS;
4792 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4796 WCHAR date[9], *val, *buffer;
4797 const WCHAR *prop, *key;
4799 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4800 static const WCHAR szWindowsInstaller[] =
4801 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4802 static const WCHAR modpath_fmt[] =
4803 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4804 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4805 static const WCHAR szModifyPath[] =
4806 {'M','o','d','i','f','y','P','a','t','h',0};
4807 static const WCHAR szUninstallString[] =
4808 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4809 static const WCHAR szEstimatedSize[] =
4810 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4811 static const WCHAR szProductLanguage[] =
4812 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4813 static const WCHAR szProductVersion[] =
4814 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4815 static const WCHAR szDisplayVersion[] =
4816 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4817 static const WCHAR szInstallSource[] =
4818 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4819 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4820 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4821 static const WCHAR szAuthorizedCDFPrefix[] =
4822 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4823 static const WCHAR szARPCONTACT[] =
4824 {'A','R','P','C','O','N','T','A','C','T',0};
4825 static const WCHAR szContact[] =
4826 {'C','o','n','t','a','c','t',0};
4827 static const WCHAR szARPCOMMENTS[] =
4828 {'A','R','P','C','O','M','M','E','N','T','S',0};
4829 static const WCHAR szComments[] =
4830 {'C','o','m','m','e','n','t','s',0};
4831 static const WCHAR szProductName[] =
4832 {'P','r','o','d','u','c','t','N','a','m','e',0};
4833 static const WCHAR szDisplayName[] =
4834 {'D','i','s','p','l','a','y','N','a','m','e',0};
4835 static const WCHAR szARPHELPLINK[] =
4836 {'A','R','P','H','E','L','P','L','I','N','K',0};
4837 static const WCHAR szHelpLink[] =
4838 {'H','e','l','p','L','i','n','k',0};
4839 static const WCHAR szARPHELPTELEPHONE[] =
4840 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4841 static const WCHAR szHelpTelephone[] =
4842 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4843 static const WCHAR szARPINSTALLLOCATION[] =
4844 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4845 static const WCHAR szInstallLocation[] =
4846 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4847 static const WCHAR szManufacturer[] =
4848 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4849 static const WCHAR szPublisher[] =
4850 {'P','u','b','l','i','s','h','e','r',0};
4851 static const WCHAR szARPREADME[] =
4852 {'A','R','P','R','E','A','D','M','E',0};
4853 static const WCHAR szReadme[] =
4854 {'R','e','a','d','M','e',0};
4855 static const WCHAR szARPSIZE[] =
4856 {'A','R','P','S','I','Z','E',0};
4857 static const WCHAR szSize[] =
4858 {'S','i','z','e',0};
4859 static const WCHAR szARPURLINFOABOUT[] =
4860 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4861 static const WCHAR szURLInfoAbout[] =
4862 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4863 static const WCHAR szARPURLUPDATEINFO[] =
4864 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4865 static const WCHAR szURLUpdateInfo[] =
4866 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4868 static const WCHAR *propval[] = {
4869 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4870 szARPCONTACT, szContact,
4871 szARPCOMMENTS, szComments,
4872 szProductName, szDisplayName,
4873 szARPHELPLINK, szHelpLink,
4874 szARPHELPTELEPHONE, szHelpTelephone,
4875 szARPINSTALLLOCATION, szInstallLocation,
4876 cszSourceDir, szInstallSource,
4877 szManufacturer, szPublisher,
4878 szARPREADME, szReadme,
4880 szARPURLINFOABOUT, szURLInfoAbout,
4881 szARPURLUPDATEINFO, szURLUpdateInfo,
4884 const WCHAR **p = propval;
4890 val = msi_dup_property(package->db, prop);
4891 msi_reg_set_val_str(hkey, key, val);
4895 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4897 size = deformat_string(package, modpath_fmt, &buffer);
4898 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4899 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4902 /* FIXME: Write real Estimated Size when we have it */
4903 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4905 GetLocalTime(&systime);
4906 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4907 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4909 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4910 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4912 buffer = msi_dup_property(package->db, szProductVersion);
4913 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4916 DWORD verdword = msi_version_str_to_dword(buffer);
4918 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4919 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4924 return ERROR_SUCCESS;
4927 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4929 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4931 LPWSTR upgrade_code;
4936 /* FIXME: also need to publish if the product is in advertise mode */
4937 if (!msi_check_publish(package))
4938 return ERROR_SUCCESS;
4940 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4941 if (rc != ERROR_SUCCESS)
4944 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4945 NULL, &props, TRUE);
4946 if (rc != ERROR_SUCCESS)
4949 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4950 msi_free( package->db->localfile );
4951 package->db->localfile = NULL;
4953 rc = msi_publish_install_properties(package, hkey);
4954 if (rc != ERROR_SUCCESS)
4957 rc = msi_publish_install_properties(package, props);
4958 if (rc != ERROR_SUCCESS)
4961 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4964 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4965 squash_guid(package->ProductCode, squashed_pc);
4966 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4967 RegCloseKey(upgrade);
4968 msi_free(upgrade_code);
4972 uirow = MSI_CreateRecord( 1 );
4973 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4974 ui_actiondata( package, szRegisterProduct, uirow );
4975 msiobj_release( &uirow->hdr );
4978 return ERROR_SUCCESS;
4981 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4983 return execute_script(package,INSTALL_SCRIPT);
4986 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4988 WCHAR *upgrade, **features;
4989 BOOL full_uninstall = TRUE;
4990 MSIFEATURE *feature;
4991 MSIPATCHINFO *patch;
4993 static const WCHAR szUpgradeCode[] =
4994 {'U','p','g','r','a','d','e','C','o','d','e',0};
4996 features = msi_split_string(remove, ',');
4999 ERR("REMOVE feature list is empty!\n");
5000 return ERROR_FUNCTION_FAILED;
5003 if (!strcmpW( features[0], szAll ))
5004 full_uninstall = TRUE;
5007 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5009 if (feature->Action != INSTALLSTATE_ABSENT)
5010 full_uninstall = FALSE;
5015 if (!full_uninstall)
5016 return ERROR_SUCCESS;
5018 MSIREG_DeleteProductKey(package->ProductCode);
5019 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5020 MSIREG_DeleteUninstallKey(package);
5022 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
5024 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5025 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5029 MSIREG_DeleteUserProductKey(package->ProductCode);
5030 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5033 upgrade = msi_dup_property(package->db, szUpgradeCode);
5036 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5040 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5042 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5045 return ERROR_SUCCESS;
5048 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5053 /* turn off scheduling */
5054 package->script->CurrentlyScripting= FALSE;
5056 /* first do the same as an InstallExecute */
5057 rc = ACTION_InstallExecute(package);
5058 if (rc != ERROR_SUCCESS)
5061 /* then handle Commit Actions */
5062 rc = execute_script(package,COMMIT_SCRIPT);
5063 if (rc != ERROR_SUCCESS)
5066 remove = msi_dup_property(package->db, szRemove);
5068 rc = msi_unpublish_product(package, remove);
5074 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5076 static const WCHAR RunOnce[] = {
5077 'S','o','f','t','w','a','r','e','\\',
5078 'M','i','c','r','o','s','o','f','t','\\',
5079 'W','i','n','d','o','w','s','\\',
5080 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5081 'R','u','n','O','n','c','e',0};
5082 static const WCHAR InstallRunOnce[] = {
5083 'S','o','f','t','w','a','r','e','\\',
5084 'M','i','c','r','o','s','o','f','t','\\',
5085 'W','i','n','d','o','w','s','\\',
5086 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5087 'I','n','s','t','a','l','l','e','r','\\',
5088 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5090 static const WCHAR msiexec_fmt[] = {
5092 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5093 '\"','%','s','\"',0};
5094 static const WCHAR install_fmt[] = {
5095 '/','I',' ','\"','%','s','\"',' ',
5096 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5097 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5098 WCHAR buffer[256], sysdir[MAX_PATH];
5100 WCHAR squished_pc[100];
5102 squash_guid(package->ProductCode,squished_pc);
5104 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5105 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5106 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5109 msi_reg_set_val_str( hkey, squished_pc, buffer );
5112 TRACE("Reboot command %s\n",debugstr_w(buffer));
5114 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5115 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5117 msi_reg_set_val_str( hkey, squished_pc, buffer );
5120 return ERROR_INSTALL_SUSPEND;
5123 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5129 * We are currently doing what should be done here in the top level Install
5130 * however for Administrative and uninstalls this step will be needed
5132 if (!package->PackagePath)
5133 return ERROR_SUCCESS;
5135 msi_set_sourcedir_props(package, TRUE);
5137 attrib = GetFileAttributesW(package->db->path);
5138 if (attrib == INVALID_FILE_ATTRIBUTES)
5144 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5145 package->Context, MSICODE_PRODUCT,
5146 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5147 if (rc == ERROR_MORE_DATA)
5149 prompt = msi_alloc(size * sizeof(WCHAR));
5150 MsiSourceListGetInfoW(package->ProductCode, NULL,
5151 package->Context, MSICODE_PRODUCT,
5152 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5155 prompt = strdupW(package->db->path);
5157 msg = generate_error_string(package,1302,1,prompt);
5158 while(attrib == INVALID_FILE_ATTRIBUTES)
5160 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5163 rc = ERROR_INSTALL_USEREXIT;
5166 attrib = GetFileAttributesW(package->db->path);
5172 return ERROR_SUCCESS;
5177 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5180 LPWSTR buffer, productid = NULL;
5181 UINT i, rc = ERROR_SUCCESS;
5184 static const WCHAR szPropKeys[][80] =
5186 {'P','r','o','d','u','c','t','I','D',0},
5187 {'U','S','E','R','N','A','M','E',0},
5188 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5192 static const WCHAR szRegKeys[][80] =
5194 {'P','r','o','d','u','c','t','I','D',0},
5195 {'R','e','g','O','w','n','e','r',0},
5196 {'R','e','g','C','o','m','p','a','n','y',0},
5200 if (msi_check_unpublish(package))
5202 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5206 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5210 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5212 if (rc != ERROR_SUCCESS)
5215 for( i = 0; szPropKeys[i][0]; i++ )
5217 buffer = msi_dup_property( package->db, szPropKeys[i] );
5218 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5223 uirow = MSI_CreateRecord( 1 );
5224 MSI_RecordSetStringW( uirow, 1, productid );
5225 ui_actiondata( package, szRegisterUser, uirow );
5226 msiobj_release( &uirow->hdr );
5228 msi_free(productid);
5234 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5238 package->script->InWhatSequence |= SEQUENCE_EXEC;
5239 rc = ACTION_ProcessExecSequence(package,FALSE);
5244 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5246 MSIPACKAGE *package = param;
5247 LPCWSTR compgroupid, component, feature, qualifier, text;
5248 LPWSTR advertise = NULL, output = NULL;
5256 feature = MSI_RecordGetString(rec, 5);
5257 feat = get_loaded_feature(package, feature);
5259 return ERROR_SUCCESS;
5261 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5262 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5263 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5265 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5266 feat->Action = feat->Installed;
5267 return ERROR_SUCCESS;
5270 component = MSI_RecordGetString(rec, 3);
5271 comp = get_loaded_component(package, component);
5273 return ERROR_SUCCESS;
5275 compgroupid = MSI_RecordGetString(rec,1);
5276 qualifier = MSI_RecordGetString(rec,2);
5278 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5279 if (rc != ERROR_SUCCESS)
5282 text = MSI_RecordGetString(rec,4);
5283 advertise = create_component_advertise_string(package, comp, feature);
5285 sz = strlenW(advertise);
5288 sz += lstrlenW(text);
5291 sz *= sizeof(WCHAR);
5293 output = msi_alloc_zero(sz);
5294 strcpyW(output,advertise);
5295 msi_free(advertise);
5298 strcatW(output,text);
5300 msi_reg_set_val_multi_str( hkey, qualifier, output );
5307 uirow = MSI_CreateRecord( 2 );
5308 MSI_RecordSetStringW( uirow, 1, compgroupid );
5309 MSI_RecordSetStringW( uirow, 2, qualifier);
5310 ui_actiondata( package, szPublishComponents, uirow);
5311 msiobj_release( &uirow->hdr );
5312 /* FIXME: call ui_progress? */
5318 * At present I am ignorning the advertised components part of this and only
5319 * focusing on the qualified component sets
5321 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5325 static const WCHAR ExecSeqQuery[] =
5326 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5327 '`','P','u','b','l','i','s','h',
5328 'C','o','m','p','o','n','e','n','t','`',0};
5330 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5331 if (rc != ERROR_SUCCESS)
5332 return ERROR_SUCCESS;
5334 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5335 msiobj_release(&view->hdr);
5340 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5342 static const WCHAR szInstallerComponents[] = {
5343 'S','o','f','t','w','a','r','e','\\',
5344 'M','i','c','r','o','s','o','f','t','\\',
5345 'I','n','s','t','a','l','l','e','r','\\',
5346 'C','o','m','p','o','n','e','n','t','s','\\',0};
5348 MSIPACKAGE *package = param;
5349 LPCWSTR compgroupid, component, feature, qualifier;
5353 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5356 feature = MSI_RecordGetString( rec, 5 );
5357 feat = get_loaded_feature( package, feature );
5359 return ERROR_SUCCESS;
5361 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5363 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5364 feat->Action = feat->Installed;
5365 return ERROR_SUCCESS;
5368 component = MSI_RecordGetString( rec, 3 );
5369 comp = get_loaded_component( package, component );
5371 return ERROR_SUCCESS;
5373 compgroupid = MSI_RecordGetString( rec, 1 );
5374 qualifier = MSI_RecordGetString( rec, 2 );
5376 squash_guid( compgroupid, squashed );
5377 strcpyW( keypath, szInstallerComponents );
5378 strcatW( keypath, squashed );
5380 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5381 if (res != ERROR_SUCCESS)
5383 WARN("Unable to delete component key %d\n", res);
5386 uirow = MSI_CreateRecord( 2 );
5387 MSI_RecordSetStringW( uirow, 1, compgroupid );
5388 MSI_RecordSetStringW( uirow, 2, qualifier );
5389 ui_actiondata( package, szUnpublishComponents, uirow );
5390 msiobj_release( &uirow->hdr );
5392 return ERROR_SUCCESS;
5395 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5399 static const WCHAR query[] =
5400 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5401 '`','P','u','b','l','i','s','h',
5402 'C','o','m','p','o','n','e','n','t','`',0};
5404 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5405 if (rc != ERROR_SUCCESS)
5406 return ERROR_SUCCESS;
5408 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5409 msiobj_release( &view->hdr );
5414 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5416 MSIPACKAGE *package = param;
5419 SC_HANDLE hscm, service = NULL;
5421 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5422 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5423 DWORD serv_type, start_type, err_control;
5424 SERVICE_DESCRIPTIONW sd = {NULL};
5426 static const WCHAR query[] =
5427 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5428 '`','C','o','m','p','o','n','e','n','t','`',' ',
5429 'W','H','E','R','E',' ',
5430 '`','C','o','m','p','o','n','e','n','t','`',' ',
5431 '=','\'','%','s','\'',0};
5433 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5436 ERR("Failed to open the SC Manager!\n");
5440 start_type = MSI_RecordGetInteger(rec, 5);
5441 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5444 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5445 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5446 serv_type = MSI_RecordGetInteger(rec, 4);
5447 err_control = MSI_RecordGetInteger(rec, 6);
5448 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5449 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5450 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5451 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5452 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5453 comp = MSI_RecordGetString(rec, 12);
5454 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5456 /* fetch the service path */
5457 row = MSI_QueryGetRecord(package->db, query, comp);
5460 ERR("Control query failed!\n");
5463 key = MSI_RecordGetString(row, 6);
5465 file = get_loaded_file(package, key);
5466 msiobj_release(&row->hdr);
5469 ERR("Failed to load the service file\n");
5473 if (!args || !args[0]) image_path = file->TargetPath;
5476 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5477 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5478 return ERROR_OUTOFMEMORY;
5480 strcpyW(image_path, file->TargetPath);
5481 strcatW(image_path, szSpace);
5482 strcatW(image_path, args);
5484 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5485 start_type, err_control, image_path, load_order,
5486 NULL, depends, serv_name, pass);
5490 if (GetLastError() != ERROR_SERVICE_EXISTS)
5491 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5493 else if (sd.lpDescription)
5495 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5496 WARN("failed to set service description %u\n", GetLastError());
5499 if (image_path != file->TargetPath) msi_free(image_path);
5501 CloseServiceHandle(service);
5502 CloseServiceHandle(hscm);
5505 msi_free(sd.lpDescription);
5506 msi_free(load_order);
5507 msi_free(serv_name);
5512 return ERROR_SUCCESS;
5515 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5519 static const WCHAR ExecSeqQuery[] =
5520 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5521 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5523 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5524 if (rc != ERROR_SUCCESS)
5525 return ERROR_SUCCESS;
5527 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5528 msiobj_release(&view->hdr);
5533 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5534 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5536 LPCWSTR *vector, *temp_vector;
5540 static const WCHAR separator[] = {'[','~',']',0};
5543 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5548 vector = msi_alloc(sizeof(LPWSTR));
5556 vector[*numargs - 1] = p;
5558 if ((q = strstrW(p, separator)))
5562 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5568 vector = temp_vector;
5577 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5579 MSIPACKAGE *package = param;
5582 SC_HANDLE scm = NULL, service = NULL;
5583 LPCWSTR component, *vector = NULL;
5584 LPWSTR name, args, display_name = NULL;
5585 DWORD event, numargs, len;
5586 UINT r = ERROR_FUNCTION_FAILED;
5588 component = MSI_RecordGetString(rec, 6);
5589 comp = get_loaded_component(package, component);
5591 return ERROR_SUCCESS;
5595 TRACE("component is disabled\n");
5596 return ERROR_SUCCESS;
5599 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5601 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5602 comp->Action = comp->Installed;
5603 return ERROR_SUCCESS;
5605 comp->Action = INSTALLSTATE_LOCAL;
5607 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5608 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5609 event = MSI_RecordGetInteger(rec, 3);
5611 if (!(event & msidbServiceControlEventStart))
5617 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5620 ERR("Failed to open the service control manager\n");
5625 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5626 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5628 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5629 GetServiceDisplayNameW( scm, name, display_name, &len );
5632 service = OpenServiceW(scm, name, SERVICE_START);
5635 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5639 vector = msi_service_args_to_vector(args, &numargs);
5641 if (!StartServiceW(service, numargs, vector) &&
5642 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5644 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5651 uirow = MSI_CreateRecord( 2 );
5652 MSI_RecordSetStringW( uirow, 1, display_name );
5653 MSI_RecordSetStringW( uirow, 2, name );
5654 ui_actiondata( package, szStartServices, uirow );
5655 msiobj_release( &uirow->hdr );
5657 CloseServiceHandle(service);
5658 CloseServiceHandle(scm);
5663 msi_free(display_name);
5667 static UINT ACTION_StartServices( MSIPACKAGE *package )
5672 static const WCHAR query[] = {
5673 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5674 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5676 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5677 if (rc != ERROR_SUCCESS)
5678 return ERROR_SUCCESS;
5680 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5681 msiobj_release(&view->hdr);
5686 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5688 DWORD i, needed, count;
5689 ENUM_SERVICE_STATUSW *dependencies;
5693 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5694 0, &needed, &count))
5697 if (GetLastError() != ERROR_MORE_DATA)
5700 dependencies = msi_alloc(needed);
5704 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5705 needed, &needed, &count))
5708 for (i = 0; i < count; i++)
5710 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5711 SERVICE_STOP | SERVICE_QUERY_STATUS);
5715 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5722 msi_free(dependencies);
5726 static UINT stop_service( LPCWSTR name )
5728 SC_HANDLE scm = NULL, service = NULL;
5729 SERVICE_STATUS status;
5730 SERVICE_STATUS_PROCESS ssp;
5733 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5736 WARN("Failed to open the SCM: %d\n", GetLastError());
5740 service = OpenServiceW(scm, name,
5742 SERVICE_QUERY_STATUS |
5743 SERVICE_ENUMERATE_DEPENDENTS);
5746 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5750 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5751 sizeof(SERVICE_STATUS_PROCESS), &needed))
5753 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5757 if (ssp.dwCurrentState == SERVICE_STOPPED)
5760 stop_service_dependents(scm, service);
5762 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5763 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5766 CloseServiceHandle(service);
5767 CloseServiceHandle(scm);
5769 return ERROR_SUCCESS;
5772 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5774 MSIPACKAGE *package = param;
5778 LPWSTR name = NULL, display_name = NULL;
5782 event = MSI_RecordGetInteger( rec, 3 );
5783 if (!(event & msidbServiceControlEventStop))
5784 return ERROR_SUCCESS;
5786 component = MSI_RecordGetString( rec, 6 );
5787 comp = get_loaded_component( package, component );
5789 return ERROR_SUCCESS;
5793 TRACE("component is disabled\n");
5794 return ERROR_SUCCESS;
5797 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5799 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5800 comp->Action = comp->Installed;
5801 return ERROR_SUCCESS;
5803 comp->Action = INSTALLSTATE_ABSENT;
5805 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5808 ERR("Failed to open the service control manager\n");
5813 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5814 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5816 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5817 GetServiceDisplayNameW( scm, name, display_name, &len );
5819 CloseServiceHandle( scm );
5821 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5822 stop_service( name );
5825 uirow = MSI_CreateRecord( 2 );
5826 MSI_RecordSetStringW( uirow, 1, display_name );
5827 MSI_RecordSetStringW( uirow, 2, name );
5828 ui_actiondata( package, szStopServices, uirow );
5829 msiobj_release( &uirow->hdr );
5832 msi_free( display_name );
5833 return ERROR_SUCCESS;
5836 static UINT ACTION_StopServices( MSIPACKAGE *package )
5841 static const WCHAR query[] = {
5842 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5843 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5845 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5846 if (rc != ERROR_SUCCESS)
5847 return ERROR_SUCCESS;
5849 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5850 msiobj_release(&view->hdr);
5855 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5857 MSIPACKAGE *package = param;
5861 LPWSTR name = NULL, display_name = NULL;
5863 SC_HANDLE scm = NULL, service = NULL;
5865 event = MSI_RecordGetInteger( rec, 3 );
5866 if (!(event & msidbServiceControlEventDelete))
5867 return ERROR_SUCCESS;
5869 component = MSI_RecordGetString(rec, 6);
5870 comp = get_loaded_component(package, component);
5872 return ERROR_SUCCESS;
5876 TRACE("component is disabled\n");
5877 return ERROR_SUCCESS;
5880 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5882 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5883 comp->Action = comp->Installed;
5884 return ERROR_SUCCESS;
5886 comp->Action = INSTALLSTATE_ABSENT;
5888 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5889 stop_service( name );
5891 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5894 WARN("Failed to open the SCM: %d\n", GetLastError());
5899 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5900 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5902 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5903 GetServiceDisplayNameW( scm, name, display_name, &len );
5906 service = OpenServiceW( scm, name, DELETE );
5909 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5913 if (!DeleteService( service ))
5914 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5917 uirow = MSI_CreateRecord( 2 );
5918 MSI_RecordSetStringW( uirow, 1, display_name );
5919 MSI_RecordSetStringW( uirow, 2, name );
5920 ui_actiondata( package, szDeleteServices, uirow );
5921 msiobj_release( &uirow->hdr );
5923 CloseServiceHandle( service );
5924 CloseServiceHandle( scm );
5926 msi_free( display_name );
5928 return ERROR_SUCCESS;
5931 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5936 static const WCHAR query[] = {
5937 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5938 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5940 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5941 if (rc != ERROR_SUCCESS)
5942 return ERROR_SUCCESS;
5944 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5945 msiobj_release( &view->hdr );
5950 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5952 MSIPACKAGE *package = param;
5953 LPWSTR driver, driver_path, ptr;
5954 WCHAR outpath[MAX_PATH];
5955 MSIFILE *driver_file = NULL, *setup_file = NULL;
5957 LPCWSTR desc, file_key;
5959 UINT r = ERROR_SUCCESS;
5961 static const WCHAR driver_fmt[] = {
5962 'D','r','i','v','e','r','=','%','s',0};
5963 static const WCHAR setup_fmt[] = {
5964 'S','e','t','u','p','=','%','s',0};
5965 static const WCHAR usage_fmt[] = {
5966 'F','i','l','e','U','s','a','g','e','=','1',0};
5968 desc = MSI_RecordGetString(rec, 3);
5970 file_key = MSI_RecordGetString( rec, 4 );
5971 if (file_key) driver_file = get_loaded_file( package, file_key );
5973 file_key = MSI_RecordGetString( rec, 5 );
5974 if (file_key) setup_file = get_loaded_file( package, file_key );
5978 ERR("ODBC Driver entry not found!\n");
5979 return ERROR_FUNCTION_FAILED;
5982 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5984 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5985 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5987 driver = msi_alloc(len * sizeof(WCHAR));
5989 return ERROR_OUTOFMEMORY;
5992 lstrcpyW(ptr, desc);
5993 ptr += lstrlenW(ptr) + 1;
5995 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6000 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6004 lstrcpyW(ptr, usage_fmt);
6005 ptr += lstrlenW(ptr) + 1;
6008 driver_path = strdupW(driver_file->TargetPath);
6009 ptr = strrchrW(driver_path, '\\');
6010 if (ptr) *ptr = '\0';
6012 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6013 NULL, ODBC_INSTALL_COMPLETE, &usage))
6015 ERR("Failed to install SQL driver!\n");
6016 r = ERROR_FUNCTION_FAILED;
6019 uirow = MSI_CreateRecord( 5 );
6020 MSI_RecordSetStringW( uirow, 1, desc );
6021 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6022 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6023 ui_actiondata( package, szInstallODBC, uirow );
6024 msiobj_release( &uirow->hdr );
6027 msi_free(driver_path);
6032 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6034 MSIPACKAGE *package = param;
6035 LPWSTR translator, translator_path, ptr;
6036 WCHAR outpath[MAX_PATH];
6037 MSIFILE *translator_file = NULL, *setup_file = NULL;
6039 LPCWSTR desc, file_key;
6041 UINT r = ERROR_SUCCESS;
6043 static const WCHAR translator_fmt[] = {
6044 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6045 static const WCHAR setup_fmt[] = {
6046 'S','e','t','u','p','=','%','s',0};
6048 desc = MSI_RecordGetString(rec, 3);
6050 file_key = MSI_RecordGetString( rec, 4 );
6051 if (file_key) translator_file = get_loaded_file( package, file_key );
6053 file_key = MSI_RecordGetString( rec, 5 );
6054 if (file_key) setup_file = get_loaded_file( package, file_key );
6056 if (!translator_file)
6058 ERR("ODBC Translator entry not found!\n");
6059 return ERROR_FUNCTION_FAILED;
6062 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6064 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6066 translator = msi_alloc(len * sizeof(WCHAR));
6068 return ERROR_OUTOFMEMORY;
6071 lstrcpyW(ptr, desc);
6072 ptr += lstrlenW(ptr) + 1;
6074 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6079 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6084 translator_path = strdupW(translator_file->TargetPath);
6085 ptr = strrchrW(translator_path, '\\');
6086 if (ptr) *ptr = '\0';
6088 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6089 NULL, ODBC_INSTALL_COMPLETE, &usage))
6091 ERR("Failed to install SQL translator!\n");
6092 r = ERROR_FUNCTION_FAILED;
6095 uirow = MSI_CreateRecord( 5 );
6096 MSI_RecordSetStringW( uirow, 1, desc );
6097 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6098 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6099 ui_actiondata( package, szInstallODBC, uirow );
6100 msiobj_release( &uirow->hdr );
6102 msi_free(translator);
6103 msi_free(translator_path);
6108 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6110 MSIPACKAGE *package = param;
6112 LPCWSTR desc, driver;
6113 WORD request = ODBC_ADD_SYS_DSN;
6116 UINT r = ERROR_SUCCESS;
6119 static const WCHAR attrs_fmt[] = {
6120 'D','S','N','=','%','s',0 };
6122 desc = MSI_RecordGetString(rec, 3);
6123 driver = MSI_RecordGetString(rec, 4);
6124 registration = MSI_RecordGetInteger(rec, 5);
6126 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6127 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6129 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6130 attrs = msi_alloc(len * sizeof(WCHAR));
6132 return ERROR_OUTOFMEMORY;
6134 len = sprintfW(attrs, attrs_fmt, desc);
6137 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6139 ERR("Failed to install SQL data source!\n");
6140 r = ERROR_FUNCTION_FAILED;
6143 uirow = MSI_CreateRecord( 5 );
6144 MSI_RecordSetStringW( uirow, 1, desc );
6145 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6146 MSI_RecordSetInteger( uirow, 3, request );
6147 ui_actiondata( package, szInstallODBC, uirow );
6148 msiobj_release( &uirow->hdr );
6155 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6160 static const WCHAR driver_query[] = {
6161 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6162 'O','D','B','C','D','r','i','v','e','r',0 };
6164 static const WCHAR translator_query[] = {
6165 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6166 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6168 static const WCHAR source_query[] = {
6169 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6170 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6172 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6173 if (rc != ERROR_SUCCESS)
6174 return ERROR_SUCCESS;
6176 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6177 msiobj_release(&view->hdr);
6179 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6180 if (rc != ERROR_SUCCESS)
6181 return ERROR_SUCCESS;
6183 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6184 msiobj_release(&view->hdr);
6186 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6187 if (rc != ERROR_SUCCESS)
6188 return ERROR_SUCCESS;
6190 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6191 msiobj_release(&view->hdr);
6196 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6198 MSIPACKAGE *package = param;
6203 desc = MSI_RecordGetString( rec, 3 );
6204 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6206 WARN("Failed to remove ODBC driver\n");
6210 FIXME("Usage count reached 0\n");
6213 uirow = MSI_CreateRecord( 2 );
6214 MSI_RecordSetStringW( uirow, 1, desc );
6215 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6216 ui_actiondata( package, szRemoveODBC, uirow );
6217 msiobj_release( &uirow->hdr );
6219 return ERROR_SUCCESS;
6222 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6224 MSIPACKAGE *package = param;
6229 desc = MSI_RecordGetString( rec, 3 );
6230 if (!SQLRemoveTranslatorW( desc, &usage ))
6232 WARN("Failed to remove ODBC translator\n");
6236 FIXME("Usage count reached 0\n");
6239 uirow = MSI_CreateRecord( 2 );
6240 MSI_RecordSetStringW( uirow, 1, desc );
6241 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6242 ui_actiondata( package, szRemoveODBC, uirow );
6243 msiobj_release( &uirow->hdr );
6245 return ERROR_SUCCESS;
6248 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6250 MSIPACKAGE *package = param;
6253 LPCWSTR desc, driver;
6254 WORD request = ODBC_REMOVE_SYS_DSN;
6258 static const WCHAR attrs_fmt[] = {
6259 'D','S','N','=','%','s',0 };
6261 desc = MSI_RecordGetString( rec, 3 );
6262 driver = MSI_RecordGetString( rec, 4 );
6263 registration = MSI_RecordGetInteger( rec, 5 );
6265 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6266 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6268 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6269 attrs = msi_alloc( len * sizeof(WCHAR) );
6271 return ERROR_OUTOFMEMORY;
6273 FIXME("Use ODBCSourceAttribute table\n");
6275 len = sprintfW( attrs, attrs_fmt, desc );
6278 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6280 WARN("Failed to remove ODBC data source\n");
6284 uirow = MSI_CreateRecord( 3 );
6285 MSI_RecordSetStringW( uirow, 1, desc );
6286 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6287 MSI_RecordSetInteger( uirow, 3, request );
6288 ui_actiondata( package, szRemoveODBC, uirow );
6289 msiobj_release( &uirow->hdr );
6291 return ERROR_SUCCESS;
6294 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6299 static const WCHAR driver_query[] = {
6300 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6301 'O','D','B','C','D','r','i','v','e','r',0 };
6303 static const WCHAR translator_query[] = {
6304 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6305 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6307 static const WCHAR source_query[] = {
6308 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6309 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6311 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6312 if (rc != ERROR_SUCCESS)
6313 return ERROR_SUCCESS;
6315 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6316 msiobj_release( &view->hdr );
6318 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6319 if (rc != ERROR_SUCCESS)
6320 return ERROR_SUCCESS;
6322 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6323 msiobj_release( &view->hdr );
6325 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6326 if (rc != ERROR_SUCCESS)
6327 return ERROR_SUCCESS;
6329 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6330 msiobj_release( &view->hdr );
6335 #define ENV_ACT_SETALWAYS 0x1
6336 #define ENV_ACT_SETABSENT 0x2
6337 #define ENV_ACT_REMOVE 0x4
6338 #define ENV_ACT_REMOVEMATCH 0x8
6340 #define ENV_MOD_MACHINE 0x20000000
6341 #define ENV_MOD_APPEND 0x40000000
6342 #define ENV_MOD_PREFIX 0x80000000
6343 #define ENV_MOD_MASK 0xC0000000
6345 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6347 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6349 LPCWSTR cptr = *name;
6351 static const WCHAR prefix[] = {'[','~',']',0};
6352 static const int prefix_len = 3;
6358 *flags |= ENV_ACT_SETALWAYS;
6359 else if (*cptr == '+')
6360 *flags |= ENV_ACT_SETABSENT;
6361 else if (*cptr == '-')
6362 *flags |= ENV_ACT_REMOVE;
6363 else if (*cptr == '!')
6364 *flags |= ENV_ACT_REMOVEMATCH;
6365 else if (*cptr == '*')
6366 *flags |= ENV_MOD_MACHINE;
6376 ERR("Missing environment variable\n");
6377 return ERROR_FUNCTION_FAILED;
6382 LPCWSTR ptr = *value;
6383 if (!strncmpW(ptr, prefix, prefix_len))
6385 if (ptr[prefix_len] == szSemiColon[0])
6387 *flags |= ENV_MOD_APPEND;
6388 *value += lstrlenW(prefix);
6395 else if (lstrlenW(*value) >= prefix_len)
6397 ptr += lstrlenW(ptr) - prefix_len;
6398 if (!strcmpW( ptr, prefix ))
6400 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6402 *flags |= ENV_MOD_PREFIX;
6403 /* the "[~]" will be removed by deformat_string */;
6413 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6414 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6415 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6416 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6418 ERR("Invalid flags: %08x\n", *flags);
6419 return ERROR_FUNCTION_FAILED;
6423 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6425 return ERROR_SUCCESS;
6428 static UINT open_env_key( DWORD flags, HKEY *key )
6430 static const WCHAR user_env[] =
6431 {'E','n','v','i','r','o','n','m','e','n','t',0};
6432 static const WCHAR machine_env[] =
6433 {'S','y','s','t','e','m','\\',
6434 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6435 'C','o','n','t','r','o','l','\\',
6436 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6437 'E','n','v','i','r','o','n','m','e','n','t',0};
6442 if (flags & ENV_MOD_MACHINE)
6445 root = HKEY_LOCAL_MACHINE;
6450 root = HKEY_CURRENT_USER;
6453 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6454 if (res != ERROR_SUCCESS)
6456 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6457 return ERROR_FUNCTION_FAILED;
6460 return ERROR_SUCCESS;
6463 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6465 MSIPACKAGE *package = param;
6466 LPCWSTR name, value, component;
6467 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6468 DWORD flags, type, size;
6475 component = MSI_RecordGetString(rec, 4);
6476 comp = get_loaded_component(package, component);
6478 return ERROR_SUCCESS;
6482 TRACE("component is disabled\n");
6483 return ERROR_SUCCESS;
6486 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6488 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6489 comp->Action = comp->Installed;
6490 return ERROR_SUCCESS;
6492 comp->Action = INSTALLSTATE_LOCAL;
6494 name = MSI_RecordGetString(rec, 2);
6495 value = MSI_RecordGetString(rec, 3);
6497 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6499 res = env_parse_flags(&name, &value, &flags);
6500 if (res != ERROR_SUCCESS || !value)
6503 if (value && !deformat_string(package, value, &deformatted))
6505 res = ERROR_OUTOFMEMORY;
6509 value = deformatted;
6511 res = open_env_key( flags, &env );
6512 if (res != ERROR_SUCCESS)
6515 if (flags & ENV_MOD_MACHINE)
6516 action |= 0x20000000;
6520 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6521 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6522 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6525 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6529 /* Nothing to do. */
6532 res = ERROR_SUCCESS;
6536 /* If we are appending but the string was empty, strip ; */
6537 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6539 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6540 newval = strdupW(value);
6543 res = ERROR_OUTOFMEMORY;
6551 /* Contrary to MSDN, +-variable to [~];path works */
6552 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6554 res = ERROR_SUCCESS;
6558 data = msi_alloc(size);
6562 return ERROR_OUTOFMEMORY;
6565 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6566 if (res != ERROR_SUCCESS)
6569 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6572 res = RegDeleteValueW(env, name);
6573 if (res != ERROR_SUCCESS)
6574 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6578 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6579 if (flags & ENV_MOD_MASK)
6583 if (flags & ENV_MOD_APPEND) multiplier++;
6584 if (flags & ENV_MOD_PREFIX) multiplier++;
6585 mod_size = lstrlenW(value) * multiplier;
6586 size += mod_size * sizeof(WCHAR);
6589 newval = msi_alloc(size);
6593 res = ERROR_OUTOFMEMORY;
6597 if (flags & ENV_MOD_PREFIX)
6599 lstrcpyW(newval, value);
6600 ptr = newval + lstrlenW(value);
6601 action |= 0x80000000;
6604 lstrcpyW(ptr, data);
6606 if (flags & ENV_MOD_APPEND)
6608 lstrcatW(newval, value);
6609 action |= 0x40000000;
6612 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6613 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6616 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6620 uirow = MSI_CreateRecord( 3 );
6621 MSI_RecordSetStringW( uirow, 1, name );
6622 MSI_RecordSetStringW( uirow, 2, newval );
6623 MSI_RecordSetInteger( uirow, 3, action );
6624 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6625 msiobj_release( &uirow->hdr );
6627 if (env) RegCloseKey(env);
6628 msi_free(deformatted);
6634 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6638 static const WCHAR ExecSeqQuery[] =
6639 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6640 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6641 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6642 if (rc != ERROR_SUCCESS)
6643 return ERROR_SUCCESS;
6645 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6646 msiobj_release(&view->hdr);
6651 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6653 MSIPACKAGE *package = param;
6654 LPCWSTR name, value, component;
6655 LPWSTR deformatted = NULL;
6664 component = MSI_RecordGetString( rec, 4 );
6665 comp = get_loaded_component( package, component );
6667 return ERROR_SUCCESS;
6671 TRACE("component is disabled\n");
6672 return ERROR_SUCCESS;
6675 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6677 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6678 comp->Action = comp->Installed;
6679 return ERROR_SUCCESS;
6681 comp->Action = INSTALLSTATE_ABSENT;
6683 name = MSI_RecordGetString( rec, 2 );
6684 value = MSI_RecordGetString( rec, 3 );
6686 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6688 r = env_parse_flags( &name, &value, &flags );
6689 if (r != ERROR_SUCCESS)
6692 if (!(flags & ENV_ACT_REMOVE))
6694 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6695 return ERROR_SUCCESS;
6698 if (value && !deformat_string( package, value, &deformatted ))
6699 return ERROR_OUTOFMEMORY;
6701 value = deformatted;
6703 r = open_env_key( flags, &env );
6704 if (r != ERROR_SUCCESS)
6710 if (flags & ENV_MOD_MACHINE)
6711 action |= 0x20000000;
6713 TRACE("Removing %s\n", debugstr_w(name));
6715 res = RegDeleteValueW( env, name );
6716 if (res != ERROR_SUCCESS)
6718 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6723 uirow = MSI_CreateRecord( 3 );
6724 MSI_RecordSetStringW( uirow, 1, name );
6725 MSI_RecordSetStringW( uirow, 2, value );
6726 MSI_RecordSetInteger( uirow, 3, action );
6727 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6728 msiobj_release( &uirow->hdr );
6730 if (env) RegCloseKey( env );
6731 msi_free( deformatted );
6735 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6739 static const WCHAR query[] =
6740 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6741 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6743 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6744 if (rc != ERROR_SUCCESS)
6745 return ERROR_SUCCESS;
6747 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6748 msiobj_release( &view->hdr );
6753 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6755 LPWSTR key, template, id;
6756 UINT r = ERROR_SUCCESS;
6758 id = msi_dup_property( package->db, szProductID );
6762 return ERROR_SUCCESS;
6764 template = msi_dup_property( package->db, szPIDTemplate );
6765 key = msi_dup_property( package->db, szPIDKEY );
6767 if (key && template)
6769 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6770 r = msi_set_property( package->db, szProductID, key );
6772 msi_free( template );
6777 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6780 package->need_reboot = 1;
6781 return ERROR_SUCCESS;
6784 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6786 static const WCHAR szAvailableFreeReg[] =
6787 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6789 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6791 TRACE("%p %d kilobytes\n", package, space);
6793 uirow = MSI_CreateRecord( 1 );
6794 MSI_RecordSetInteger( uirow, 1, space );
6795 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6796 msiobj_release( &uirow->hdr );
6798 return ERROR_SUCCESS;
6801 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6803 FIXME("%p\n", package);
6804 return ERROR_SUCCESS;
6807 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6809 FIXME("%p\n", package);
6810 return ERROR_SUCCESS;
6813 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6818 static const WCHAR driver_query[] = {
6819 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6820 'O','D','B','C','D','r','i','v','e','r',0 };
6822 static const WCHAR translator_query[] = {
6823 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6824 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6826 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6827 if (r == ERROR_SUCCESS)
6830 r = MSI_IterateRecords( view, &count, NULL, package );
6831 msiobj_release( &view->hdr );
6832 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6835 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6836 if (r == ERROR_SUCCESS)
6839 r = MSI_IterateRecords( view, &count, NULL, package );
6840 msiobj_release( &view->hdr );
6841 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6844 return ERROR_SUCCESS;
6847 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6849 MSIPACKAGE *package = param;
6850 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6853 if ((value = msi_dup_property( package->db, property )))
6855 FIXME("remove %s\n", debugstr_w(value));
6858 return ERROR_SUCCESS;
6861 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6866 static const WCHAR query[] =
6867 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
6868 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
6870 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6871 if (r == ERROR_SUCCESS)
6873 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6874 msiobj_release( &view->hdr );
6876 return ERROR_SUCCESS;
6879 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6881 MSIPACKAGE *package = param;
6882 int attributes = MSI_RecordGetInteger( rec, 5 );
6884 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6886 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6887 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6888 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6889 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6893 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6895 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6896 if (r != ERROR_SUCCESS)
6897 return ERROR_SUCCESS;
6901 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6902 if (r != ERROR_SUCCESS)
6903 return ERROR_SUCCESS;
6905 RegCloseKey( hkey );
6907 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6908 debugstr_w(upgrade_code), debugstr_w(version_min),
6909 debugstr_w(version_max), debugstr_w(language));
6911 return ERROR_SUCCESS;
6914 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6919 static const WCHAR query[] =
6920 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
6922 if (msi_get_property_int( package->db, szInstalled, 0 ))
6924 TRACE("product is installed, skipping action\n");
6925 return ERROR_SUCCESS;
6927 if (msi_get_property_int( package->db, szPreselected, 0 ))
6929 TRACE("Preselected property is set, not migrating feature states\n");
6930 return ERROR_SUCCESS;
6933 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6934 if (r == ERROR_SUCCESS)
6936 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
6937 msiobj_release( &view->hdr );
6939 return ERROR_SUCCESS;
6942 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6943 LPCSTR action, LPCWSTR table )
6945 static const WCHAR query[] = {
6946 'S','E','L','E','C','T',' ','*',' ',
6947 'F','R','O','M',' ','`','%','s','`',0 };
6948 MSIQUERY *view = NULL;
6952 r = MSI_OpenQuery( package->db, &view, query, table );
6953 if (r == ERROR_SUCCESS)
6955 r = MSI_IterateRecords(view, &count, NULL, package);
6956 msiobj_release(&view->hdr);
6960 FIXME("%s -> %u ignored %s table values\n",
6961 action, count, debugstr_w(table));
6963 return ERROR_SUCCESS;
6966 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6968 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6969 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6972 static UINT ACTION_BindImage( MSIPACKAGE *package )
6974 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6975 return msi_unimplemented_action_stub( package, "BindImage", table );
6978 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6980 static const WCHAR table[] = {
6981 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6982 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6985 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6987 static const WCHAR table[] = {
6988 'M','s','i','A','s','s','e','m','b','l','y',0 };
6989 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6992 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6994 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6995 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6998 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7000 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7001 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7004 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7006 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7007 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7010 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7012 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7013 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7016 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7020 const WCHAR *action;
7021 UINT (*handler)(MSIPACKAGE *);
7025 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7026 { szAppSearch, ACTION_AppSearch },
7027 { szBindImage, ACTION_BindImage },
7028 { szCCPSearch, ACTION_CCPSearch },
7029 { szCostFinalize, ACTION_CostFinalize },
7030 { szCostInitialize, ACTION_CostInitialize },
7031 { szCreateFolders, ACTION_CreateFolders },
7032 { szCreateShortcuts, ACTION_CreateShortcuts },
7033 { szDeleteServices, ACTION_DeleteServices },
7034 { szDisableRollback, ACTION_DisableRollback },
7035 { szDuplicateFiles, ACTION_DuplicateFiles },
7036 { szExecuteAction, ACTION_ExecuteAction },
7037 { szFileCost, ACTION_FileCost },
7038 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7039 { szForceReboot, ACTION_ForceReboot },
7040 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7041 { szInstallExecute, ACTION_InstallExecute },
7042 { szInstallExecuteAgain, ACTION_InstallExecute },
7043 { szInstallFiles, ACTION_InstallFiles},
7044 { szInstallFinalize, ACTION_InstallFinalize },
7045 { szInstallInitialize, ACTION_InstallInitialize },
7046 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7047 { szInstallValidate, ACTION_InstallValidate },
7048 { szIsolateComponents, ACTION_IsolateComponents },
7049 { szLaunchConditions, ACTION_LaunchConditions },
7050 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7051 { szMoveFiles, ACTION_MoveFiles },
7052 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7053 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7054 { szInstallODBC, ACTION_InstallODBC },
7055 { szInstallServices, ACTION_InstallServices },
7056 { szPatchFiles, ACTION_PatchFiles },
7057 { szProcessComponents, ACTION_ProcessComponents },
7058 { szPublishComponents, ACTION_PublishComponents },
7059 { szPublishFeatures, ACTION_PublishFeatures },
7060 { szPublishProduct, ACTION_PublishProduct },
7061 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7062 { szRegisterComPlus, ACTION_RegisterComPlus},
7063 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7064 { szRegisterFonts, ACTION_RegisterFonts },
7065 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7066 { szRegisterProduct, ACTION_RegisterProduct },
7067 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7068 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7069 { szRegisterUser, ACTION_RegisterUser },
7070 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7071 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7072 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7073 { szRemoveFiles, ACTION_RemoveFiles },
7074 { szRemoveFolders, ACTION_RemoveFolders },
7075 { szRemoveIniValues, ACTION_RemoveIniValues },
7076 { szRemoveODBC, ACTION_RemoveODBC },
7077 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7078 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7079 { szResolveSource, ACTION_ResolveSource },
7080 { szRMCCPSearch, ACTION_RMCCPSearch },
7081 { szScheduleReboot, ACTION_ScheduleReboot },
7082 { szSelfRegModules, ACTION_SelfRegModules },
7083 { szSelfUnregModules, ACTION_SelfUnregModules },
7084 { szSetODBCFolders, ACTION_SetODBCFolders },
7085 { szStartServices, ACTION_StartServices },
7086 { szStopServices, ACTION_StopServices },
7087 { szUnpublishComponents, ACTION_UnpublishComponents },
7088 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7089 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7090 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7091 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7092 { szUnregisterFonts, ACTION_UnregisterFonts },
7093 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7094 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7095 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7096 { szValidateProductID, ACTION_ValidateProductID },
7097 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7098 { szWriteIniValues, ACTION_WriteIniValues },
7099 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7103 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7109 while (StandardActions[i].action != NULL)
7111 if (!strcmpW( StandardActions[i].action, action ))
7113 ui_actionstart( package, action );
7114 if (StandardActions[i].handler)
7116 ui_actioninfo( package, action, TRUE, 0 );
7117 *rc = StandardActions[i].handler( package );
7118 ui_actioninfo( package, action, FALSE, *rc );
7122 FIXME("unhandled standard action %s\n", debugstr_w(action));
7123 *rc = ERROR_SUCCESS;
7133 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7135 UINT rc = ERROR_SUCCESS;
7138 TRACE("Performing action (%s)\n", debugstr_w(action));
7140 handled = ACTION_HandleStandardAction(package, action, &rc);
7143 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7147 WARN("unhandled msi action %s\n", debugstr_w(action));
7148 rc = ERROR_FUNCTION_NOT_CALLED;
7154 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7156 UINT rc = ERROR_SUCCESS;
7157 BOOL handled = FALSE;
7159 TRACE("Performing action (%s)\n", debugstr_w(action));
7161 handled = ACTION_HandleStandardAction(package, action, &rc);
7164 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7166 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7171 WARN("unhandled msi action %s\n", debugstr_w(action));
7172 rc = ERROR_FUNCTION_NOT_CALLED;
7178 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7180 UINT rc = ERROR_SUCCESS;
7183 static const WCHAR ExecSeqQuery[] =
7184 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7185 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7186 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7187 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7188 static const WCHAR UISeqQuery[] =
7189 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7190 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7191 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7192 ' ', '=',' ','%','i',0};
7194 if (needs_ui_sequence(package))
7195 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7197 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7201 LPCWSTR action, cond;
7203 TRACE("Running the actions\n");
7205 /* check conditions */
7206 cond = MSI_RecordGetString(row, 2);
7208 /* this is a hack to skip errors in the condition code */
7209 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7211 msiobj_release(&row->hdr);
7212 return ERROR_SUCCESS;
7215 action = MSI_RecordGetString(row, 1);
7218 ERR("failed to fetch action\n");
7219 msiobj_release(&row->hdr);
7220 return ERROR_FUNCTION_FAILED;
7223 if (needs_ui_sequence(package))
7224 rc = ACTION_PerformUIAction(package, action, -1);
7226 rc = ACTION_PerformAction(package, action, -1);
7228 msiobj_release(&row->hdr);
7234 /****************************************************
7235 * TOP level entry points
7236 *****************************************************/
7238 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7239 LPCWSTR szCommandLine )
7244 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7245 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7247 msi_set_property( package->db, szAction, szInstall );
7249 package->script->InWhatSequence = SEQUENCE_INSTALL;
7256 dir = strdupW(szPackagePath);
7257 p = strrchrW(dir, '\\');
7261 file = szPackagePath + (p - dir);
7266 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7267 GetCurrentDirectoryW(MAX_PATH, dir);
7268 lstrcatW(dir, szBackSlash);
7269 file = szPackagePath;
7272 msi_free( package->PackagePath );
7273 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7274 if (!package->PackagePath)
7277 return ERROR_OUTOFMEMORY;
7280 lstrcpyW(package->PackagePath, dir);
7281 lstrcatW(package->PackagePath, file);
7284 msi_set_sourcedir_props(package, FALSE);
7287 msi_parse_command_line( package, szCommandLine, FALSE );
7289 msi_apply_transforms( package );
7290 msi_apply_patches( package );
7292 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7294 TRACE("setting reinstall property\n");
7295 msi_set_property( package->db, szReinstall, szAll );
7298 /* properties may have been added by a transform */
7299 msi_clone_properties( package );
7301 msi_parse_command_line( package, szCommandLine, FALSE );
7302 msi_adjust_privilege_properties( package );
7303 msi_set_context( package );
7305 if (needs_ui_sequence( package))
7307 package->script->InWhatSequence |= SEQUENCE_UI;
7308 rc = ACTION_ProcessUISequence(package);
7309 ui_exists = ui_sequence_exists(package);
7310 if (rc == ERROR_SUCCESS || !ui_exists)
7312 package->script->InWhatSequence |= SEQUENCE_EXEC;
7313 rc = ACTION_ProcessExecSequence(package, ui_exists);
7317 rc = ACTION_ProcessExecSequence(package, FALSE);
7319 package->script->CurrentlyScripting = FALSE;
7321 /* process the ending type action */
7322 if (rc == ERROR_SUCCESS)
7323 ACTION_PerformActionSequence(package, -1);
7324 else if (rc == ERROR_INSTALL_USEREXIT)
7325 ACTION_PerformActionSequence(package, -2);
7326 else if (rc == ERROR_INSTALL_SUSPEND)
7327 ACTION_PerformActionSequence(package, -4);
7329 ACTION_PerformActionSequence(package, -3);
7331 /* finish up running custom actions */
7332 ACTION_FinishCustomActions(package);
7334 if (rc == ERROR_SUCCESS && package->need_reboot)
7335 return ERROR_SUCCESS_REBOOT_REQUIRED;