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] );
767 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
771 msi_free( xform_list );
776 static BOOL ui_sequence_exists( MSIPACKAGE *package )
781 static const WCHAR ExecSeqQuery [] =
782 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
783 '`','I','n','s','t','a','l','l',
784 'U','I','S','e','q','u','e','n','c','e','`',
785 ' ','W','H','E','R','E',' ',
786 '`','S','e','q','u','e','n','c','e','`',' ',
787 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
788 '`','S','e','q','u','e','n','c','e','`',0};
790 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
791 if (rc == ERROR_SUCCESS)
793 msiobj_release(&view->hdr);
800 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
802 LPWSTR source, check;
804 if (msi_get_property_int( package->db, szInstalled, 0 ))
808 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
809 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
817 db = msi_dup_property( package->db, szOriginalDatabase );
819 return ERROR_OUTOFMEMORY;
821 p = strrchrW( db, '\\' );
824 p = strrchrW( db, '/' );
828 return ERROR_SUCCESS;
833 source = msi_alloc( len * sizeof(WCHAR) );
834 lstrcpynW( source, db, len );
838 check = msi_dup_property( package->db, cszSourceDir );
839 if (!check || replace)
841 UINT r = msi_set_property( package->db, cszSourceDir, source );
842 if (r == ERROR_SUCCESS)
843 msi_reset_folders( package, TRUE );
847 check = msi_dup_property( package->db, cszSOURCEDIR );
848 if (!check || replace)
849 msi_set_property( package->db, cszSOURCEDIR, source );
854 return ERROR_SUCCESS;
857 static BOOL needs_ui_sequence(MSIPACKAGE *package)
859 INT level = msi_get_property_int(package->db, szUILevel, 0);
860 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
863 UINT msi_set_context(MSIPACKAGE *package)
867 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
869 num = msi_get_property_int(package->db, szAllUsers, 0);
870 if (num == 1 || num == 2)
871 package->Context = MSIINSTALLCONTEXT_MACHINE;
873 return ERROR_SUCCESS;
876 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
879 LPCWSTR cond, action;
880 MSIPACKAGE *package = param;
882 action = MSI_RecordGetString(row,1);
885 ERR("Error is retrieving action name\n");
886 return ERROR_FUNCTION_FAILED;
889 /* check conditions */
890 cond = MSI_RecordGetString(row,2);
892 /* this is a hack to skip errors in the condition code */
893 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
895 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
896 return ERROR_SUCCESS;
899 if (needs_ui_sequence(package))
900 rc = ACTION_PerformUIAction(package, action, -1);
902 rc = ACTION_PerformAction(package, action, -1);
904 msi_dialog_check_messages( NULL );
906 if (package->CurrentInstallState != ERROR_SUCCESS)
907 rc = package->CurrentInstallState;
909 if (rc == ERROR_FUNCTION_NOT_CALLED)
912 if (rc != ERROR_SUCCESS)
913 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
918 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
922 static const WCHAR query[] =
923 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
925 ' ','W','H','E','R','E',' ',
926 '`','S','e','q','u','e','n','c','e','`',' ',
927 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
928 '`','S','e','q','u','e','n','c','e','`',0};
930 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
932 r = MSI_OpenQuery( package->db, &view, query, szTable );
933 if (r == ERROR_SUCCESS)
935 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
936 msiobj_release(&view->hdr);
942 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
946 static const WCHAR ExecSeqQuery[] =
947 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
948 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
949 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
950 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
951 'O','R','D','E','R',' ', 'B','Y',' ',
952 '`','S','e','q','u','e','n','c','e','`',0 };
953 static const WCHAR IVQuery[] =
954 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
955 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
956 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
957 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
958 ' ','\'', 'I','n','s','t','a','l','l',
959 'V','a','l','i','d','a','t','e','\'', 0};
962 if (package->script->ExecuteSequenceRun)
964 TRACE("Execute Sequence already Run\n");
965 return ERROR_SUCCESS;
968 package->script->ExecuteSequenceRun = TRUE;
970 /* get the sequence number */
973 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
975 return ERROR_FUNCTION_FAILED;
976 seq = MSI_RecordGetInteger(row,1);
977 msiobj_release(&row->hdr);
980 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
981 if (rc == ERROR_SUCCESS)
983 TRACE("Running the actions\n");
985 msi_set_property(package->db, cszSourceDir, NULL);
987 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
988 msiobj_release(&view->hdr);
994 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
998 static const WCHAR ExecSeqQuery [] =
999 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1000 '`','I','n','s','t','a','l','l',
1001 'U','I','S','e','q','u','e','n','c','e','`',
1002 ' ','W','H','E','R','E',' ',
1003 '`','S','e','q','u','e','n','c','e','`',' ',
1004 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1005 '`','S','e','q','u','e','n','c','e','`',0};
1007 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1008 if (rc == ERROR_SUCCESS)
1010 TRACE("Running the actions\n");
1012 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1013 msiobj_release(&view->hdr);
1019 /********************************************************
1020 * ACTION helper functions and functions that perform the actions
1021 *******************************************************/
1022 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1023 UINT* rc, UINT script, BOOL force )
1028 arc = ACTION_CustomAction(package, action, script, force);
1030 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1039 * Actual Action Handlers
1042 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1044 MSIPACKAGE *package = param;
1045 LPCWSTR dir, component;
1051 component = MSI_RecordGetString(row, 2);
1053 return ERROR_SUCCESS;
1055 comp = get_loaded_component(package, component);
1057 return ERROR_SUCCESS;
1061 TRACE("component is disabled\n");
1062 return ERROR_SUCCESS;
1065 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1067 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1068 comp->Action = comp->Installed;
1069 return ERROR_SUCCESS;
1071 comp->Action = INSTALLSTATE_LOCAL;
1073 dir = MSI_RecordGetString(row,1);
1076 ERR("Unable to get folder id\n");
1077 return ERROR_SUCCESS;
1080 uirow = MSI_CreateRecord(1);
1081 MSI_RecordSetStringW(uirow, 1, dir);
1082 ui_actiondata(package, szCreateFolders, uirow);
1083 msiobj_release(&uirow->hdr);
1085 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1088 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1089 return ERROR_SUCCESS;
1092 TRACE("Folder is %s\n",debugstr_w(full_path));
1094 if (folder->State == 0)
1095 create_full_pathW(full_path);
1099 msi_free(full_path);
1100 return ERROR_SUCCESS;
1103 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1105 static const WCHAR query[] =
1106 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1107 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1111 /* create all the empty folders specified in the CreateFolder table */
1112 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1113 if (rc != ERROR_SUCCESS)
1114 return ERROR_SUCCESS;
1116 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1117 msiobj_release(&view->hdr);
1122 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1124 MSIPACKAGE *package = param;
1125 LPCWSTR dir, component;
1131 component = MSI_RecordGetString(row, 2);
1133 return ERROR_SUCCESS;
1135 comp = get_loaded_component(package, component);
1137 return ERROR_SUCCESS;
1141 TRACE("component is disabled\n");
1142 return ERROR_SUCCESS;
1145 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1147 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1148 comp->Action = comp->Installed;
1149 return ERROR_SUCCESS;
1151 comp->Action = INSTALLSTATE_ABSENT;
1153 dir = MSI_RecordGetString( row, 1 );
1156 ERR("Unable to get folder id\n");
1157 return ERROR_SUCCESS;
1160 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1163 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1164 return ERROR_SUCCESS;
1167 TRACE("folder is %s\n", debugstr_w(full_path));
1169 uirow = MSI_CreateRecord( 1 );
1170 MSI_RecordSetStringW( uirow, 1, dir );
1171 ui_actiondata( package, szRemoveFolders, uirow );
1172 msiobj_release( &uirow->hdr );
1174 RemoveDirectoryW( full_path );
1177 msi_free( full_path );
1178 return ERROR_SUCCESS;
1181 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1183 static const WCHAR query[] =
1184 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1185 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1190 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1191 if (rc != ERROR_SUCCESS)
1192 return ERROR_SUCCESS;
1194 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1195 msiobj_release( &view->hdr );
1200 static UINT load_component( MSIRECORD *row, LPVOID param )
1202 MSIPACKAGE *package = param;
1205 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1207 return ERROR_FUNCTION_FAILED;
1209 list_add_tail( &package->components, &comp->entry );
1211 /* fill in the data */
1212 comp->Component = msi_dup_record_field( row, 1 );
1214 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1216 comp->ComponentId = msi_dup_record_field( row, 2 );
1217 comp->Directory = msi_dup_record_field( row, 3 );
1218 comp->Attributes = MSI_RecordGetInteger(row,4);
1219 comp->Condition = msi_dup_record_field( row, 5 );
1220 comp->KeyPath = msi_dup_record_field( row, 6 );
1222 comp->Installed = INSTALLSTATE_UNKNOWN;
1223 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1225 comp->assembly = load_assembly( package, comp );
1226 return ERROR_SUCCESS;
1229 static UINT load_all_components( MSIPACKAGE *package )
1231 static const WCHAR query[] = {
1232 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1233 '`','C','o','m','p','o','n','e','n','t','`',0 };
1237 if (!list_empty(&package->components))
1238 return ERROR_SUCCESS;
1240 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1241 if (r != ERROR_SUCCESS)
1244 r = MSI_IterateRecords(view, NULL, load_component, package);
1245 msiobj_release(&view->hdr);
1250 MSIPACKAGE *package;
1251 MSIFEATURE *feature;
1254 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1258 cl = msi_alloc( sizeof (*cl) );
1260 return ERROR_NOT_ENOUGH_MEMORY;
1261 cl->component = comp;
1262 list_add_tail( &feature->Components, &cl->entry );
1264 return ERROR_SUCCESS;
1267 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1271 fl = msi_alloc( sizeof(*fl) );
1273 return ERROR_NOT_ENOUGH_MEMORY;
1274 fl->feature = child;
1275 list_add_tail( &parent->Children, &fl->entry );
1277 return ERROR_SUCCESS;
1280 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1282 _ilfs* ilfs = param;
1286 component = MSI_RecordGetString(row,1);
1288 /* check to see if the component is already loaded */
1289 comp = get_loaded_component( ilfs->package, component );
1292 ERR("unknown component %s\n", debugstr_w(component));
1293 return ERROR_FUNCTION_FAILED;
1296 add_feature_component( ilfs->feature, comp );
1297 comp->Enabled = TRUE;
1299 return ERROR_SUCCESS;
1302 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1304 MSIFEATURE *feature;
1309 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1311 if ( !strcmpW( feature->Feature, name ) )
1318 static UINT load_feature(MSIRECORD * row, LPVOID param)
1320 MSIPACKAGE* package = param;
1321 MSIFEATURE* feature;
1322 static const WCHAR Query1[] =
1323 {'S','E','L','E','C','T',' ',
1324 '`','C','o','m','p','o','n','e','n','t','_','`',
1325 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1326 'C','o','m','p','o','n','e','n','t','s','`',' ',
1327 'W','H','E','R','E',' ',
1328 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1333 /* fill in the data */
1335 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1337 return ERROR_NOT_ENOUGH_MEMORY;
1339 list_init( &feature->Children );
1340 list_init( &feature->Components );
1342 feature->Feature = msi_dup_record_field( row, 1 );
1344 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1346 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1347 feature->Title = msi_dup_record_field( row, 3 );
1348 feature->Description = msi_dup_record_field( row, 4 );
1350 if (!MSI_RecordIsNull(row,5))
1351 feature->Display = MSI_RecordGetInteger(row,5);
1353 feature->Level= MSI_RecordGetInteger(row,6);
1354 feature->Directory = msi_dup_record_field( row, 7 );
1355 feature->Attributes = MSI_RecordGetInteger(row,8);
1357 feature->Installed = INSTALLSTATE_UNKNOWN;
1358 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1360 list_add_tail( &package->features, &feature->entry );
1362 /* load feature components */
1364 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1365 if (rc != ERROR_SUCCESS)
1366 return ERROR_SUCCESS;
1368 ilfs.package = package;
1369 ilfs.feature = feature;
1371 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1372 msiobj_release(&view->hdr);
1374 return ERROR_SUCCESS;
1377 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1379 MSIPACKAGE* package = param;
1380 MSIFEATURE *parent, *child;
1382 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1384 return ERROR_FUNCTION_FAILED;
1386 if (!child->Feature_Parent)
1387 return ERROR_SUCCESS;
1389 parent = find_feature_by_name( package, child->Feature_Parent );
1391 return ERROR_FUNCTION_FAILED;
1393 add_feature_child( parent, child );
1394 return ERROR_SUCCESS;
1397 static UINT load_all_features( MSIPACKAGE *package )
1399 static const WCHAR query[] = {
1400 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1401 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1402 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1406 if (!list_empty(&package->features))
1407 return ERROR_SUCCESS;
1409 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1410 if (r != ERROR_SUCCESS)
1413 r = MSI_IterateRecords( view, NULL, load_feature, package );
1414 if (r != ERROR_SUCCESS)
1417 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1418 msiobj_release( &view->hdr );
1423 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1434 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1436 static const WCHAR query[] = {
1437 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1438 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1439 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1440 MSIQUERY *view = NULL;
1441 MSIRECORD *row = NULL;
1444 TRACE("%s\n", debugstr_w(file->File));
1446 r = MSI_OpenQuery(package->db, &view, query, file->File);
1447 if (r != ERROR_SUCCESS)
1450 r = MSI_ViewExecute(view, NULL);
1451 if (r != ERROR_SUCCESS)
1454 r = MSI_ViewFetch(view, &row);
1455 if (r != ERROR_SUCCESS)
1458 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1459 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1460 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1461 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1462 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1465 if (view) msiobj_release(&view->hdr);
1466 if (row) msiobj_release(&row->hdr);
1470 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1473 static const WCHAR query[] = {
1474 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1475 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1476 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1478 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1481 WARN("query failed\n");
1482 return ERROR_FUNCTION_FAILED;
1485 file->disk_id = MSI_RecordGetInteger( row, 1 );
1486 msiobj_release( &row->hdr );
1487 return ERROR_SUCCESS;
1490 static UINT load_file(MSIRECORD *row, LPVOID param)
1492 MSIPACKAGE* package = param;
1496 /* fill in the data */
1498 file = msi_alloc_zero( sizeof (MSIFILE) );
1500 return ERROR_NOT_ENOUGH_MEMORY;
1502 file->File = msi_dup_record_field( row, 1 );
1504 component = MSI_RecordGetString( row, 2 );
1505 file->Component = get_loaded_component( package, component );
1507 if (!file->Component)
1509 WARN("Component not found: %s\n", debugstr_w(component));
1510 msi_free(file->File);
1512 return ERROR_SUCCESS;
1515 file->FileName = msi_dup_record_field( row, 3 );
1516 reduce_to_longfilename( file->FileName );
1518 file->ShortName = msi_dup_record_field( row, 3 );
1519 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1521 file->FileSize = MSI_RecordGetInteger( row, 4 );
1522 file->Version = msi_dup_record_field( row, 5 );
1523 file->Language = msi_dup_record_field( row, 6 );
1524 file->Attributes = MSI_RecordGetInteger( row, 7 );
1525 file->Sequence = MSI_RecordGetInteger( row, 8 );
1527 file->state = msifs_invalid;
1529 /* if the compressed bits are not set in the file attributes,
1530 * then read the information from the package word count property
1532 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1534 file->IsCompressed = FALSE;
1536 else if (file->Attributes &
1537 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1539 file->IsCompressed = TRUE;
1541 else if (file->Attributes & msidbFileAttributesNoncompressed)
1543 file->IsCompressed = FALSE;
1547 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1550 load_file_hash(package, file);
1551 load_file_disk_id(package, file);
1553 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1555 list_add_tail( &package->files, &file->entry );
1557 return ERROR_SUCCESS;
1560 static UINT load_all_files(MSIPACKAGE *package)
1564 static const WCHAR Query[] =
1565 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1566 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1567 '`','S','e','q','u','e','n','c','e','`', 0};
1569 if (!list_empty(&package->files))
1570 return ERROR_SUCCESS;
1572 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1573 if (rc != ERROR_SUCCESS)
1574 return ERROR_SUCCESS;
1576 rc = MSI_IterateRecords(view, NULL, load_file, package);
1577 msiobj_release(&view->hdr);
1579 return ERROR_SUCCESS;
1582 static UINT load_folder( MSIRECORD *row, LPVOID param )
1584 MSIPACKAGE *package = param;
1585 static WCHAR szEmpty[] = { 0 };
1586 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1589 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1591 return ERROR_NOT_ENOUGH_MEMORY;
1593 folder->Directory = msi_dup_record_field( row, 1 );
1595 TRACE("%s\n", debugstr_w(folder->Directory));
1597 p = msi_dup_record_field(row, 3);
1599 /* split src and target dir */
1601 src_short = folder_split_path( p, ':' );
1603 /* split the long and short paths */
1604 tgt_long = folder_split_path( tgt_short, '|' );
1605 src_long = folder_split_path( src_short, '|' );
1607 /* check for no-op dirs */
1608 if (tgt_short && !strcmpW( szDot, tgt_short ))
1609 tgt_short = szEmpty;
1610 if (src_short && !strcmpW( szDot, src_short ))
1611 src_short = szEmpty;
1614 tgt_long = tgt_short;
1617 src_short = tgt_short;
1618 src_long = tgt_long;
1622 src_long = src_short;
1624 /* FIXME: use the target short path too */
1625 folder->TargetDefault = strdupW(tgt_long);
1626 folder->SourceShortPath = strdupW(src_short);
1627 folder->SourceLongPath = strdupW(src_long);
1630 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1631 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1632 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1634 folder->Parent = msi_dup_record_field( row, 2 );
1636 folder->Property = msi_dup_property( package->db, folder->Directory );
1638 list_add_tail( &package->folders, &folder->entry );
1640 TRACE("returning %p\n", folder);
1642 return ERROR_SUCCESS;
1645 static UINT load_all_folders( MSIPACKAGE *package )
1647 static const WCHAR query[] = {
1648 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1649 '`','D','i','r','e','c','t','o','r','y','`',0 };
1653 if (!list_empty(&package->folders))
1654 return ERROR_SUCCESS;
1656 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1657 if (r != ERROR_SUCCESS)
1660 r = MSI_IterateRecords(view, NULL, load_folder, package);
1661 msiobj_release(&view->hdr);
1666 * I am not doing any of the costing functionality yet.
1667 * Mostly looking at doing the Component and Feature loading
1669 * The native MSI does A LOT of modification to tables here. Mostly adding
1670 * a lot of temporary columns to the Feature and Component tables.
1672 * note: Native msi also tracks the short filename. But I am only going to
1673 * track the long ones. Also looking at this directory table
1674 * it appears that the directory table does not get the parents
1675 * resolved base on property only based on their entries in the
1678 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1680 static const WCHAR szCosting[] =
1681 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1683 msi_set_property( package->db, szCosting, szZero );
1684 msi_set_property( package->db, cszRootDrive, c_colon );
1686 load_all_folders( package );
1687 load_all_components( package );
1688 load_all_features( package );
1689 load_all_files( package );
1691 return ERROR_SUCCESS;
1694 static UINT execute_script(MSIPACKAGE *package, UINT script )
1697 UINT rc = ERROR_SUCCESS;
1699 TRACE("Executing Script %i\n",script);
1701 if (!package->script)
1703 ERR("no script!\n");
1704 return ERROR_FUNCTION_FAILED;
1707 for (i = 0; i < package->script->ActionCount[script]; i++)
1710 action = package->script->Actions[script][i];
1711 ui_actionstart(package, action);
1712 TRACE("Executing Action (%s)\n",debugstr_w(action));
1713 rc = ACTION_PerformAction(package, action, script);
1714 if (rc != ERROR_SUCCESS)
1717 msi_free_action_script(package, script);
1721 static UINT ACTION_FileCost(MSIPACKAGE *package)
1723 return ERROR_SUCCESS;
1726 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1732 state = MsiQueryProductStateW(package->ProductCode);
1734 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1736 if (!comp->ComponentId)
1739 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1740 comp->Installed = INSTALLSTATE_ABSENT;
1743 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1744 package->Context, comp->ComponentId,
1746 if (r != ERROR_SUCCESS)
1747 comp->Installed = INSTALLSTATE_ABSENT;
1752 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1754 MSIFEATURE *feature;
1757 state = MsiQueryProductStateW(package->ProductCode);
1759 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1761 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1762 feature->Installed = INSTALLSTATE_ABSENT;
1765 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1771 static BOOL process_state_property(MSIPACKAGE* package, int level,
1772 LPCWSTR property, INSTALLSTATE state)
1775 MSIFEATURE *feature;
1777 override = msi_dup_property( package->db, property );
1781 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1783 if (strcmpW( property, szRemove ) &&
1784 (feature->Level <= 0 || feature->Level > level))
1787 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1789 if (!strcmpiW( override, szAll ))
1790 msi_feature_set_state(package, feature, state);
1793 LPWSTR ptr = override;
1794 LPWSTR ptr2 = strchrW(override,',');
1798 int len = ptr2 - ptr;
1800 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1801 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1803 msi_feature_set_state(package, feature, state);
1809 ptr2 = strchrW(ptr,',');
1821 static BOOL process_overrides( MSIPACKAGE *package, int level )
1823 static const WCHAR szAddLocal[] =
1824 {'A','D','D','L','O','C','A','L',0};
1825 static const WCHAR szAddSource[] =
1826 {'A','D','D','S','O','U','R','C','E',0};
1827 static const WCHAR szAdvertise[] =
1828 {'A','D','V','E','R','T','I','S','E',0};
1831 /* all these activation/deactivation things happen in order and things
1832 * later on the list override things earlier on the list.
1834 * 0 INSTALLLEVEL processing
1847 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1848 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1849 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1850 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1851 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1854 msi_set_property( package->db, szPreselected, szOne );
1859 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1862 static const WCHAR szlevel[] =
1863 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1864 MSICOMPONENT* component;
1865 MSIFEATURE *feature;
1867 TRACE("Checking Install Level\n");
1869 level = msi_get_property_int(package->db, szlevel, 1);
1871 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1873 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1875 BOOL feature_state = ((feature->Level > 0) &&
1876 (feature->Level <= level));
1878 if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1880 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1881 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1882 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1883 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1885 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1889 /* disable child features of unselected parent features */
1890 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1894 if (feature->Level > 0 && feature->Level <= level)
1897 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1898 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1903 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1905 BOOL selected = feature->Level > 0 && feature->Level <= level;
1907 if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1909 msi_feature_set_state(package, feature, feature->Installed);
1915 * now we want to enable or disable components based on feature
1917 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1921 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1922 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1923 feature->ActionRequest, feature->Action);
1925 if (!feature->Level)
1928 /* features with components that have compressed files are made local */
1929 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1931 if (cl->component->ForceLocalState &&
1932 feature->ActionRequest == INSTALLSTATE_SOURCE)
1934 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1939 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1941 component = cl->component;
1943 switch (feature->ActionRequest)
1945 case INSTALLSTATE_ABSENT:
1946 component->anyAbsent = 1;
1948 case INSTALLSTATE_ADVERTISED:
1949 component->hasAdvertiseFeature = 1;
1951 case INSTALLSTATE_SOURCE:
1952 component->hasSourceFeature = 1;
1954 case INSTALLSTATE_LOCAL:
1955 component->hasLocalFeature = 1;
1957 case INSTALLSTATE_DEFAULT:
1958 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1959 component->hasAdvertiseFeature = 1;
1960 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1961 component->hasSourceFeature = 1;
1963 component->hasLocalFeature = 1;
1971 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1973 /* check if it's local or source */
1974 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1975 (component->hasLocalFeature || component->hasSourceFeature))
1977 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1978 !component->ForceLocalState)
1979 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1981 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1985 /* if any feature is local, the component must be local too */
1986 if (component->hasLocalFeature)
1988 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1992 if (component->hasSourceFeature)
1994 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1998 if (component->hasAdvertiseFeature)
2000 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2004 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2005 if (component->anyAbsent)
2006 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2009 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2011 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2013 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2014 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2017 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2018 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2021 return ERROR_SUCCESS;
2024 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2026 MSIPACKAGE *package = param;
2031 name = MSI_RecordGetString(row,1);
2033 f = get_loaded_folder(package, name);
2034 if (!f) return ERROR_SUCCESS;
2036 /* reset the ResolvedTarget */
2037 msi_free(f->ResolvedTarget);
2038 f->ResolvedTarget = NULL;
2040 /* This helper function now does ALL the work */
2041 TRACE("Dir %s ...\n",debugstr_w(name));
2042 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2043 TRACE("resolves to %s\n",debugstr_w(path));
2046 return ERROR_SUCCESS;
2049 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2051 MSIPACKAGE *package = param;
2053 MSIFEATURE *feature;
2055 name = MSI_RecordGetString( row, 1 );
2057 feature = get_loaded_feature( package, name );
2059 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2063 Condition = MSI_RecordGetString(row,3);
2065 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2067 int level = MSI_RecordGetInteger(row,2);
2068 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2069 feature->Level = level;
2072 return ERROR_SUCCESS;
2075 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2077 static const WCHAR name[] = {'\\',0};
2078 VS_FIXEDFILEINFO *ptr, *ret;
2080 DWORD versize, handle;
2083 TRACE("%s\n", debugstr_w(filename));
2085 versize = GetFileVersionInfoSizeW( filename, &handle );
2089 version = msi_alloc( versize );
2093 GetFileVersionInfoW( filename, 0, versize, version );
2095 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2097 msi_free( version );
2101 ret = msi_alloc( sz );
2102 memcpy( ret, ptr, sz );
2104 msi_free( version );
2108 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2112 msi_parse_version_string( version, &ms, &ls );
2114 if (fi->dwFileVersionMS > ms) return 1;
2115 else if (fi->dwFileVersionMS < ms) return -1;
2116 else if (fi->dwFileVersionLS > ls) return 1;
2117 else if (fi->dwFileVersionLS < ls) return -1;
2121 static DWORD get_disk_file_size( LPCWSTR filename )
2126 TRACE("%s\n", debugstr_w(filename));
2128 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2129 if (file == INVALID_HANDLE_VALUE)
2130 return INVALID_FILE_SIZE;
2132 size = GetFileSize( file, NULL );
2133 CloseHandle( file );
2137 static BOOL hash_matches( MSIFILE *file )
2140 MSIFILEHASHINFO hash;
2142 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2143 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2144 if (r != ERROR_SUCCESS)
2147 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2150 static WCHAR *get_temp_dir( void )
2153 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2155 GetTempPathW( MAX_PATH, tmp );
2158 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2159 if (CreateDirectoryW( dir, NULL )) break;
2161 return strdupW( dir );
2164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2166 MSIASSEMBLY *assembly = file->Component->assembly;
2168 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2170 msi_free( file->TargetPath );
2171 if (assembly && !assembly->application)
2173 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2174 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2175 track_tempfile( package, file->TargetPath );
2179 WCHAR *dir = resolve_folder( package, file->Component->Directory, FALSE, FALSE, TRUE, NULL );
2180 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2184 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2187 static UINT set_file_install_states( MSIPACKAGE *package )
2189 VS_FIXEDFILEINFO *file_version;
2192 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2194 MSICOMPONENT *comp = file->Component;
2197 if (!comp->Enabled) continue;
2199 if (file->IsCompressed)
2200 comp->ForceLocalState = TRUE;
2202 set_target_path( package, file );
2204 if ((comp->assembly && !comp->assembly->installed) ||
2205 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2207 file->state = msifs_missing;
2208 comp->Cost += file->FileSize;
2211 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2213 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2214 HIWORD(file_version->dwFileVersionMS),
2215 LOWORD(file_version->dwFileVersionMS),
2216 HIWORD(file_version->dwFileVersionLS),
2217 LOWORD(file_version->dwFileVersionLS));
2219 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2221 file->state = msifs_overwrite;
2222 comp->Cost += file->FileSize;
2226 TRACE("Destination file version equal or greater, not overwriting\n");
2227 file->state = msifs_present;
2229 msi_free( file_version );
2232 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2234 file->state = msifs_overwrite;
2235 comp->Cost += file->FileSize - file_size;
2238 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2240 TRACE("File hashes match, not overwriting\n");
2241 file->state = msifs_present;
2244 file->state = msifs_overwrite;
2245 comp->Cost += file->FileSize - file_size;
2248 return ERROR_SUCCESS;
2252 * A lot is done in this function aside from just the costing.
2253 * The costing needs to be implemented at some point but for now I am going
2254 * to focus on the directory building
2257 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2259 static const WCHAR ExecSeqQuery[] =
2260 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2261 '`','D','i','r','e','c','t','o','r','y','`',0};
2262 static const WCHAR ConditionQuery[] =
2263 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2264 '`','C','o','n','d','i','t','i','o','n','`',0};
2265 static const WCHAR szCosting[] =
2266 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2267 static const WCHAR szlevel[] =
2268 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2269 static const WCHAR szOutOfDiskSpace[] =
2270 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2272 UINT rc = ERROR_SUCCESS;
2276 TRACE("Building Directory properties\n");
2278 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2279 if (rc == ERROR_SUCCESS)
2281 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2283 msiobj_release(&view->hdr);
2286 /* read components states from the registry */
2287 ACTION_GetComponentInstallStates(package);
2288 ACTION_GetFeatureInstallStates(package);
2290 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2292 TRACE("Evaluating feature conditions\n");
2294 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2295 if (rc == ERROR_SUCCESS)
2297 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2298 msiobj_release( &view->hdr );
2301 TRACE("Evaluating component conditions\n");
2303 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2305 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2307 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2308 comp->Enabled = FALSE;
2311 comp->Enabled = TRUE;
2314 TRACE("Calculating file install states\n");
2315 set_file_install_states( package );
2317 msi_set_property( package->db, szCosting, szOne );
2318 /* set default run level if not set */
2319 level = msi_dup_property( package->db, szlevel );
2321 msi_set_property( package->db, szlevel, szOne );
2324 /* FIXME: check volume disk space */
2325 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2327 return MSI_SetFeatureStates(package);
2330 /* OK this value is "interpreted" and then formatted based on the
2331 first few characters */
2332 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2337 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2343 LPWSTR deformated = NULL;
2346 deformat_string(package, &value[2], &deformated);
2348 /* binary value type */
2352 *size = (strlenW(ptr)/2)+1;
2354 *size = strlenW(ptr)/2;
2356 data = msi_alloc(*size);
2362 /* if uneven pad with a zero in front */
2368 data[count] = (BYTE)strtol(byte,NULL,0);
2370 TRACE("Uneven byte count\n");
2378 data[count] = (BYTE)strtol(byte,NULL,0);
2381 msi_free(deformated);
2383 TRACE("Data %i bytes(%i)\n",*size,count);
2390 deformat_string(package, &value[1], &deformated);
2393 *size = sizeof(DWORD);
2394 data = msi_alloc(*size);
2400 if ( (*p < '0') || (*p > '9') )
2406 if (deformated[0] == '-')
2409 TRACE("DWORD %i\n",*(LPDWORD)data);
2411 msi_free(deformated);
2416 static const WCHAR szMulti[] = {'[','~',']',0};
2425 *type=REG_EXPAND_SZ;
2433 if (strstrW(value, szMulti))
2434 *type = REG_MULTI_SZ;
2436 /* remove initial delimiter */
2437 if (!strncmpW(value, szMulti, 3))
2440 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2442 /* add double NULL terminator */
2443 if (*type == REG_MULTI_SZ)
2445 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2446 data = msi_realloc_zero(data, *size);
2452 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2459 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2461 *root_key = HKEY_LOCAL_MACHINE;
2466 *root_key = HKEY_CURRENT_USER;
2471 *root_key = HKEY_CLASSES_ROOT;
2475 *root_key = HKEY_CURRENT_USER;
2479 *root_key = HKEY_LOCAL_MACHINE;
2483 *root_key = HKEY_USERS;
2487 ERR("Unknown root %i\n", root);
2494 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2496 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2497 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2499 if (is_64bit && package->platform == PLATFORM_INTEL &&
2500 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2505 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2506 path_32node = msi_alloc( size );
2510 memcpy( path_32node, path, len * sizeof(WCHAR) );
2511 path_32node[len] = 0;
2512 strcatW( path_32node, szWow6432Node );
2513 strcatW( path_32node, szBackSlash );
2514 strcatW( path_32node, path + len );
2518 return strdupW( path );
2521 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2523 MSIPACKAGE *package = param;
2524 LPSTR value_data = NULL;
2525 HKEY root_key, hkey;
2527 LPWSTR deformated, uikey, keypath;
2528 LPCWSTR szRoot, component, name, key, value;
2532 BOOL check_first = FALSE;
2535 ui_progress(package,2,0,0,0);
2537 component = MSI_RecordGetString(row, 6);
2538 comp = get_loaded_component(package,component);
2540 return ERROR_SUCCESS;
2544 TRACE("component is disabled\n");
2545 return ERROR_SUCCESS;
2548 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2550 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2551 comp->Action = comp->Installed;
2552 return ERROR_SUCCESS;
2554 comp->Action = INSTALLSTATE_LOCAL;
2556 name = MSI_RecordGetString(row, 4);
2557 if( MSI_RecordIsNull(row,5) && name )
2559 /* null values can have special meanings */
2560 if (name[0]=='-' && name[1] == 0)
2561 return ERROR_SUCCESS;
2562 else if ((name[0]=='+' && name[1] == 0) ||
2563 (name[0] == '*' && name[1] == 0))
2568 root = MSI_RecordGetInteger(row,2);
2569 key = MSI_RecordGetString(row, 3);
2571 szRoot = get_root_key( package, root, &root_key );
2573 return ERROR_SUCCESS;
2575 deformat_string(package, key , &deformated);
2576 size = strlenW(deformated) + strlenW(szRoot) + 1;
2577 uikey = msi_alloc(size*sizeof(WCHAR));
2578 strcpyW(uikey,szRoot);
2579 strcatW(uikey,deformated);
2581 keypath = get_keypath( package, root_key, deformated );
2582 msi_free( deformated );
2583 if (RegCreateKeyW( root_key, keypath, &hkey ))
2585 ERR("Could not create key %s\n", debugstr_w(keypath));
2587 return ERROR_SUCCESS;
2590 value = MSI_RecordGetString(row,5);
2592 value_data = parse_value(package, value, &type, &size);
2595 value_data = (LPSTR)strdupW(szEmpty);
2596 size = sizeof(szEmpty);
2600 deformat_string(package, name, &deformated);
2604 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2606 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2611 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2612 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2614 TRACE("value %s of %s checked already exists\n",
2615 debugstr_w(deformated), debugstr_w(uikey));
2619 TRACE("Checked and setting value %s of %s\n",
2620 debugstr_w(deformated), debugstr_w(uikey));
2621 if (deformated || size)
2622 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2627 uirow = MSI_CreateRecord(3);
2628 MSI_RecordSetStringW(uirow,2,deformated);
2629 MSI_RecordSetStringW(uirow,1,uikey);
2630 if (type == REG_SZ || type == REG_EXPAND_SZ)
2631 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2632 ui_actiondata(package,szWriteRegistryValues,uirow);
2633 msiobj_release( &uirow->hdr );
2635 msi_free(value_data);
2636 msi_free(deformated);
2639 return ERROR_SUCCESS;
2642 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2646 static const WCHAR ExecSeqQuery[] =
2647 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2648 '`','R','e','g','i','s','t','r','y','`',0 };
2650 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2651 if (rc != ERROR_SUCCESS)
2652 return ERROR_SUCCESS;
2654 /* increment progress bar each time action data is sent */
2655 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2657 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2659 msiobj_release(&view->hdr);
2663 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2667 DWORD num_subkeys, num_values;
2671 if ((res = RegDeleteTreeW( hkey_root, key )))
2673 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2678 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2680 if ((res = RegDeleteValueW( hkey, value )))
2682 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2684 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2685 NULL, NULL, NULL, NULL );
2686 RegCloseKey( hkey );
2687 if (!res && !num_subkeys && !num_values)
2689 TRACE("Removing empty key %s\n", debugstr_w(key));
2690 RegDeleteKeyW( hkey_root, key );
2694 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2698 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2700 MSIPACKAGE *package = param;
2701 LPCWSTR component, name, key_str, root_key_str;
2702 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2705 BOOL delete_key = FALSE;
2710 ui_progress( package, 2, 0, 0, 0 );
2712 component = MSI_RecordGetString( row, 6 );
2713 comp = get_loaded_component( package, component );
2715 return ERROR_SUCCESS;
2719 TRACE("component is disabled\n");
2720 return ERROR_SUCCESS;
2723 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2725 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2726 comp->Action = comp->Installed;
2727 return ERROR_SUCCESS;
2729 comp->Action = INSTALLSTATE_ABSENT;
2731 name = MSI_RecordGetString( row, 4 );
2732 if (MSI_RecordIsNull( row, 5 ) && name )
2734 if (name[0] == '+' && !name[1])
2735 return ERROR_SUCCESS;
2736 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2743 root = MSI_RecordGetInteger( row, 2 );
2744 key_str = MSI_RecordGetString( row, 3 );
2746 root_key_str = get_root_key( package, root, &hkey_root );
2748 return ERROR_SUCCESS;
2750 deformat_string( package, key_str, &deformated_key );
2751 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2752 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2753 strcpyW( ui_key_str, root_key_str );
2754 strcatW( ui_key_str, deformated_key );
2756 deformat_string( package, name, &deformated_name );
2758 keypath = get_keypath( package, hkey_root, deformated_key );
2759 msi_free( deformated_key );
2760 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2761 msi_free( keypath );
2763 uirow = MSI_CreateRecord( 2 );
2764 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2765 MSI_RecordSetStringW( uirow, 2, deformated_name );
2767 ui_actiondata( package, szRemoveRegistryValues, uirow );
2768 msiobj_release( &uirow->hdr );
2770 msi_free( ui_key_str );
2771 msi_free( deformated_name );
2772 return ERROR_SUCCESS;
2775 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2777 MSIPACKAGE *package = param;
2778 LPCWSTR component, name, key_str, root_key_str;
2779 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2782 BOOL delete_key = FALSE;
2787 ui_progress( package, 2, 0, 0, 0 );
2789 component = MSI_RecordGetString( row, 5 );
2790 comp = get_loaded_component( package, component );
2792 return ERROR_SUCCESS;
2796 TRACE("component is disabled\n");
2797 return ERROR_SUCCESS;
2800 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2802 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2803 comp->Action = comp->Installed;
2804 return ERROR_SUCCESS;
2806 comp->Action = INSTALLSTATE_LOCAL;
2808 if ((name = MSI_RecordGetString( row, 4 )))
2810 if (name[0] == '-' && !name[1])
2817 root = MSI_RecordGetInteger( row, 2 );
2818 key_str = MSI_RecordGetString( row, 3 );
2820 root_key_str = get_root_key( package, root, &hkey_root );
2822 return ERROR_SUCCESS;
2824 deformat_string( package, key_str, &deformated_key );
2825 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2826 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2827 strcpyW( ui_key_str, root_key_str );
2828 strcatW( ui_key_str, deformated_key );
2830 deformat_string( package, name, &deformated_name );
2832 keypath = get_keypath( package, hkey_root, deformated_key );
2833 msi_free( deformated_key );
2834 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2835 msi_free( keypath );
2837 uirow = MSI_CreateRecord( 2 );
2838 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2839 MSI_RecordSetStringW( uirow, 2, deformated_name );
2841 ui_actiondata( package, szRemoveRegistryValues, uirow );
2842 msiobj_release( &uirow->hdr );
2844 msi_free( ui_key_str );
2845 msi_free( deformated_name );
2846 return ERROR_SUCCESS;
2849 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2853 static const WCHAR registry_query[] =
2854 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2855 '`','R','e','g','i','s','t','r','y','`',0 };
2856 static const WCHAR remove_registry_query[] =
2857 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2858 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2860 /* increment progress bar each time action data is sent */
2861 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2863 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2864 if (rc == ERROR_SUCCESS)
2866 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2867 msiobj_release( &view->hdr );
2868 if (rc != ERROR_SUCCESS)
2872 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2873 if (rc == ERROR_SUCCESS)
2875 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2876 msiobj_release( &view->hdr );
2877 if (rc != ERROR_SUCCESS)
2881 return ERROR_SUCCESS;
2884 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2886 package->script->CurrentlyScripting = TRUE;
2888 return ERROR_SUCCESS;
2892 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2897 static const WCHAR q1[]=
2898 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2899 '`','R','e','g','i','s','t','r','y','`',0};
2902 MSIFEATURE *feature;
2905 TRACE("InstallValidate\n");
2907 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2908 if (rc == ERROR_SUCCESS)
2910 MSI_IterateRecords( view, &progress, NULL, package );
2911 msiobj_release( &view->hdr );
2912 total += progress * REG_PROGRESS_VALUE;
2915 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2916 total += COMPONENT_PROGRESS_VALUE;
2918 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2919 total += file->FileSize;
2921 ui_progress(package,0,total,0,0);
2923 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2925 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2926 debugstr_w(feature->Feature), feature->Installed,
2927 feature->ActionRequest, feature->Action);
2930 return ERROR_SUCCESS;
2933 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2935 MSIPACKAGE* package = param;
2936 LPCWSTR cond = NULL;
2937 LPCWSTR message = NULL;
2940 static const WCHAR title[]=
2941 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2943 cond = MSI_RecordGetString(row,1);
2945 r = MSI_EvaluateConditionW(package,cond);
2946 if (r == MSICONDITION_FALSE)
2948 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2951 message = MSI_RecordGetString(row,2);
2952 deformat_string(package,message,&deformated);
2953 MessageBoxW(NULL,deformated,title,MB_OK);
2954 msi_free(deformated);
2957 return ERROR_INSTALL_FAILURE;
2960 return ERROR_SUCCESS;
2963 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2966 MSIQUERY * view = NULL;
2967 static const WCHAR ExecSeqQuery[] =
2968 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2969 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2971 TRACE("Checking launch conditions\n");
2973 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2974 if (rc != ERROR_SUCCESS)
2975 return ERROR_SUCCESS;
2977 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2978 msiobj_release(&view->hdr);
2983 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2987 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2989 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2991 MSIRECORD * row = 0;
2993 LPWSTR deformated,buffer,deformated_name;
2995 static const WCHAR ExecSeqQuery[] =
2996 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2997 '`','R','e','g','i','s','t','r','y','`',' ',
2998 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2999 ' ','=',' ' ,'\'','%','s','\'',0 };
3000 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3001 static const WCHAR fmt2[]=
3002 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3004 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3008 root = MSI_RecordGetInteger(row,2);
3009 key = MSI_RecordGetString(row, 3);
3010 name = MSI_RecordGetString(row, 4);
3011 deformat_string(package, key , &deformated);
3012 deformat_string(package, name, &deformated_name);
3014 len = strlenW(deformated) + 6;
3015 if (deformated_name)
3016 len+=strlenW(deformated_name);
3018 buffer = msi_alloc( len *sizeof(WCHAR));
3020 if (deformated_name)
3021 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3023 sprintfW(buffer,fmt,root,deformated);
3025 msi_free(deformated);
3026 msi_free(deformated_name);
3027 msiobj_release(&row->hdr);
3031 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3033 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3038 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3041 return strdupW( file->TargetPath );
3046 static HKEY openSharedDLLsKey(void)
3049 static const WCHAR path[] =
3050 {'S','o','f','t','w','a','r','e','\\',
3051 'M','i','c','r','o','s','o','f','t','\\',
3052 'W','i','n','d','o','w','s','\\',
3053 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3054 'S','h','a','r','e','d','D','L','L','s',0};
3056 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3060 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3065 DWORD sz = sizeof(count);
3068 hkey = openSharedDLLsKey();
3069 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3070 if (rc != ERROR_SUCCESS)
3076 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3080 hkey = openSharedDLLsKey();
3082 msi_reg_set_val_dword( hkey, path, count );
3084 RegDeleteValueW(hkey,path);
3090 * Return TRUE if the count should be written out and FALSE if not
3092 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3094 MSIFEATURE *feature;
3098 /* only refcount DLLs */
3099 if (comp->KeyPath == NULL ||
3100 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3101 comp->Attributes & msidbComponentAttributesODBCDataSource)
3105 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3106 write = (count > 0);
3108 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3112 /* increment counts */
3113 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3117 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3120 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3122 if ( cl->component == comp )
3127 /* decrement counts */
3128 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3132 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3135 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3137 if ( cl->component == comp )
3142 /* ref count all the files in the component */
3147 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3149 if (file->Component == comp)
3150 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3154 /* add a count for permanent */
3155 if (comp->Attributes & msidbComponentAttributesPermanent)
3158 comp->RefCount = count;
3161 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3164 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3166 WCHAR squished_pc[GUID_SIZE];
3167 WCHAR squished_cc[GUID_SIZE];
3174 squash_guid(package->ProductCode,squished_pc);
3175 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3177 msi_set_sourcedir_props(package, FALSE);
3179 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3183 ui_progress(package,2,0,0,0);
3184 if (!comp->ComponentId)
3187 squash_guid(comp->ComponentId,squished_cc);
3189 msi_free(comp->FullKeypath);
3190 comp->FullKeypath = resolve_keypath( package, comp );
3192 ACTION_RefCountComponent( package, comp );
3194 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3195 debugstr_w(comp->Component),
3196 debugstr_w(squished_cc),
3197 debugstr_w(comp->FullKeypath),
3199 comp->ActionRequest);
3201 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3202 comp->ActionRequest == INSTALLSTATE_SOURCE)
3204 if (!comp->FullKeypath)
3207 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3208 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3211 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3214 if (rc != ERROR_SUCCESS)
3217 if (comp->Attributes & msidbComponentAttributesPermanent)
3219 static const WCHAR szPermKey[] =
3220 { '0','0','0','0','0','0','0','0','0','0','0','0',
3221 '0','0','0','0','0','0','0','0','0','0','0','0',
3222 '0','0','0','0','0','0','0','0',0 };
3224 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3227 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3228 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3234 WCHAR source[MAX_PATH];
3235 WCHAR base[MAX_PATH];
3238 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3239 static const WCHAR query[] = {
3240 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3241 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3242 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3243 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3244 '`','D','i','s','k','I','d','`',0};
3246 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3249 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3250 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3251 ptr2 = strrchrW(source, '\\') + 1;
3252 msiobj_release(&row->hdr);
3254 lstrcpyW(base, package->PackagePath);
3255 ptr = strrchrW(base, '\\');
3258 sourcepath = resolve_file_source(package, file);
3259 ptr = sourcepath + lstrlenW(base);
3260 lstrcpyW(ptr2, ptr);
3261 msi_free(sourcepath);
3263 msi_reg_set_val_str(hkey, squished_pc, source);
3267 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3269 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3270 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3272 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3274 comp->Action = comp->ActionRequest;
3277 uirow = MSI_CreateRecord(3);
3278 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3279 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3280 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3281 ui_actiondata(package,szProcessComponents,uirow);
3282 msiobj_release( &uirow->hdr );
3285 return ERROR_SUCCESS;
3296 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3297 LPWSTR lpszName, LONG_PTR lParam)
3300 typelib_struct *tl_struct = (typelib_struct*) lParam;
3301 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3305 if (!IS_INTRESOURCE(lpszName))
3307 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3311 sz = strlenW(tl_struct->source)+4;
3312 sz *= sizeof(WCHAR);
3314 if ((INT_PTR)lpszName == 1)
3315 tl_struct->path = strdupW(tl_struct->source);
3318 tl_struct->path = msi_alloc(sz);
3319 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3322 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3323 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3326 msi_free(tl_struct->path);
3327 tl_struct->path = NULL;
3332 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3333 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3335 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3339 msi_free(tl_struct->path);
3340 tl_struct->path = NULL;
3342 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3343 ITypeLib_Release(tl_struct->ptLib);
3348 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3350 MSIPACKAGE* package = param;
3354 typelib_struct tl_struct;
3359 component = MSI_RecordGetString(row,3);
3360 comp = get_loaded_component(package,component);
3362 return ERROR_SUCCESS;
3366 TRACE("component is disabled\n");
3367 return ERROR_SUCCESS;
3370 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3372 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3373 comp->Action = comp->Installed;
3374 return ERROR_SUCCESS;
3376 comp->Action = INSTALLSTATE_LOCAL;
3378 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3380 TRACE("component has no key path\n");
3381 return ERROR_SUCCESS;
3383 ui_actiondata( package, szRegisterTypeLibraries, row );
3385 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3389 guid = MSI_RecordGetString(row,1);
3390 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3391 tl_struct.source = strdupW( file->TargetPath );
3392 tl_struct.path = NULL;
3394 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3395 (LONG_PTR)&tl_struct);
3403 helpid = MSI_RecordGetString(row,6);
3406 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3407 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3411 ERR("Failed to register type library %s\n",
3412 debugstr_w(tl_struct.path));
3414 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3416 ITypeLib_Release(tl_struct.ptLib);
3417 msi_free(tl_struct.path);
3420 ERR("Failed to load type library %s\n",
3421 debugstr_w(tl_struct.source));
3423 FreeLibrary(module);
3424 msi_free(tl_struct.source);
3428 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3431 ERR("Failed to load type library: %08x\n", hr);
3432 return ERROR_INSTALL_FAILURE;
3435 ITypeLib_Release(tlib);
3438 return ERROR_SUCCESS;
3441 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3444 * OK this is a bit confusing.. I am given a _Component key and I believe
3445 * that the file that is being registered as a type library is the "key file
3446 * of that component" which I interpret to mean "The file in the KeyPath of
3451 static const WCHAR Query[] =
3452 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3453 '`','T','y','p','e','L','i','b','`',0};
3455 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3456 if (rc != ERROR_SUCCESS)
3457 return ERROR_SUCCESS;
3459 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3460 msiobj_release(&view->hdr);
3464 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3466 MSIPACKAGE *package = param;
3467 LPCWSTR component, guid;
3475 component = MSI_RecordGetString( row, 3 );
3476 comp = get_loaded_component( package, component );
3478 return ERROR_SUCCESS;
3482 TRACE("component is disabled\n");
3483 return ERROR_SUCCESS;
3486 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3488 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3489 comp->Action = comp->Installed;
3490 return ERROR_SUCCESS;
3492 comp->Action = INSTALLSTATE_ABSENT;
3494 ui_actiondata( package, szUnregisterTypeLibraries, row );
3496 guid = MSI_RecordGetString( row, 1 );
3497 CLSIDFromString( (LPCWSTR)guid, &libid );
3498 version = MSI_RecordGetInteger( row, 4 );
3499 language = MSI_RecordGetInteger( row, 2 );
3502 syskind = SYS_WIN64;
3504 syskind = SYS_WIN32;
3507 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3510 WARN("Failed to unregister typelib: %08x\n", hr);
3513 return ERROR_SUCCESS;
3516 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3520 static const WCHAR query[] =
3521 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3522 '`','T','y','p','e','L','i','b','`',0};
3524 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3525 if (rc != ERROR_SUCCESS)
3526 return ERROR_SUCCESS;
3528 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3529 msiobj_release( &view->hdr );
3533 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3535 static const WCHAR szlnk[] = {'.','l','n','k',0};
3536 LPCWSTR directory, extension;
3537 LPWSTR link_folder, link_file, filename;
3539 directory = MSI_RecordGetString( row, 2 );
3540 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3542 /* may be needed because of a bug somewhere else */
3543 create_full_pathW( link_folder );
3545 filename = msi_dup_record_field( row, 3 );
3546 reduce_to_longfilename( filename );
3548 extension = strchrW( filename, '.' );
3549 if (!extension || strcmpiW( extension, szlnk ))
3551 int len = strlenW( filename );
3552 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3553 memcpy( filename + len, szlnk, sizeof(szlnk) );
3555 link_file = build_directory_name( 2, link_folder, filename );
3556 msi_free( link_folder );
3557 msi_free( filename );
3562 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3564 MSIPACKAGE *package = param;
3565 LPWSTR link_file, deformated, path;
3566 LPCWSTR component, target;
3568 IShellLinkW *sl = NULL;
3569 IPersistFile *pf = NULL;
3572 component = MSI_RecordGetString(row, 4);
3573 comp = get_loaded_component(package, component);
3575 return ERROR_SUCCESS;
3579 TRACE("component is disabled\n");
3580 return ERROR_SUCCESS;
3583 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3585 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3586 comp->Action = comp->Installed;
3587 return ERROR_SUCCESS;
3589 comp->Action = INSTALLSTATE_LOCAL;
3591 ui_actiondata(package,szCreateShortcuts,row);
3593 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3594 &IID_IShellLinkW, (LPVOID *) &sl );
3598 ERR("CLSID_ShellLink not available\n");
3602 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3605 ERR("QueryInterface(IID_IPersistFile) failed\n");
3609 target = MSI_RecordGetString(row, 5);
3610 if (strchrW(target, '['))
3612 deformat_string(package, target, &deformated);
3613 IShellLinkW_SetPath(sl,deformated);
3614 msi_free(deformated);
3618 FIXME("poorly handled shortcut format, advertised shortcut\n");
3619 IShellLinkW_SetPath(sl,comp->FullKeypath);
3622 if (!MSI_RecordIsNull(row,6))
3624 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3625 deformat_string(package, arguments, &deformated);
3626 IShellLinkW_SetArguments(sl,deformated);
3627 msi_free(deformated);
3630 if (!MSI_RecordIsNull(row,7))
3632 LPCWSTR description = MSI_RecordGetString(row, 7);
3633 IShellLinkW_SetDescription(sl, description);
3636 if (!MSI_RecordIsNull(row,8))
3637 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3639 if (!MSI_RecordIsNull(row,9))
3642 LPCWSTR icon = MSI_RecordGetString(row, 9);
3644 path = build_icon_path(package, icon);
3645 index = MSI_RecordGetInteger(row,10);
3647 /* no value means 0 */
3648 if (index == MSI_NULL_INTEGER)
3651 IShellLinkW_SetIconLocation(sl, path, index);
3655 if (!MSI_RecordIsNull(row,11))
3656 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3658 if (!MSI_RecordIsNull(row,12))
3660 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3661 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3663 IShellLinkW_SetWorkingDirectory(sl, path);
3667 link_file = get_link_file(package, row);
3669 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3670 IPersistFile_Save(pf, link_file, FALSE);
3672 msi_free(link_file);
3676 IPersistFile_Release( pf );
3678 IShellLinkW_Release( sl );
3680 return ERROR_SUCCESS;
3683 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3688 static const WCHAR Query[] =
3689 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3690 '`','S','h','o','r','t','c','u','t','`',0};
3692 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3693 if (rc != ERROR_SUCCESS)
3694 return ERROR_SUCCESS;
3696 res = CoInitialize( NULL );
3698 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3699 msiobj_release(&view->hdr);
3707 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3709 MSIPACKAGE *package = param;
3714 component = MSI_RecordGetString( row, 4 );
3715 comp = get_loaded_component( package, component );
3717 return ERROR_SUCCESS;
3721 TRACE("component is disabled\n");
3722 return ERROR_SUCCESS;
3725 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3727 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3728 comp->Action = comp->Installed;
3729 return ERROR_SUCCESS;
3731 comp->Action = INSTALLSTATE_ABSENT;
3733 ui_actiondata( package, szRemoveShortcuts, row );
3735 link_file = get_link_file( package, row );
3737 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3738 if (!DeleteFileW( link_file ))
3740 WARN("Failed to remove shortcut file %u\n", GetLastError());
3742 msi_free( link_file );
3744 return ERROR_SUCCESS;
3747 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3751 static const WCHAR query[] =
3752 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3753 '`','S','h','o','r','t','c','u','t','`',0};
3755 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3756 if (rc != ERROR_SUCCESS)
3757 return ERROR_SUCCESS;
3759 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3760 msiobj_release( &view->hdr );
3765 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3767 MSIPACKAGE* package = param;
3775 FileName = MSI_RecordGetString(row,1);
3778 ERR("Unable to get FileName\n");
3779 return ERROR_SUCCESS;
3782 FilePath = build_icon_path(package,FileName);
3784 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3786 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3787 FILE_ATTRIBUTE_NORMAL, NULL);
3789 if (the_file == INVALID_HANDLE_VALUE)
3791 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3793 return ERROR_SUCCESS;
3800 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3801 if (rc != ERROR_SUCCESS)
3803 ERR("Failed to get stream\n");
3804 CloseHandle(the_file);
3805 DeleteFileW(FilePath);
3808 WriteFile(the_file,buffer,sz,&write,NULL);
3809 } while (sz == 1024);
3812 CloseHandle(the_file);
3814 return ERROR_SUCCESS;
3817 static UINT msi_publish_icons(MSIPACKAGE *package)
3822 static const WCHAR query[]= {
3823 'S','E','L','E','C','T',' ','*',' ',
3824 'F','R','O','M',' ','`','I','c','o','n','`',0};
3826 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3827 if (r == ERROR_SUCCESS)
3829 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3830 msiobj_release(&view->hdr);
3833 return ERROR_SUCCESS;
3836 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3842 MSISOURCELISTINFO *info;
3844 r = RegCreateKeyW(hkey, szSourceList, &source);
3845 if (r != ERROR_SUCCESS)
3848 RegCloseKey(source);
3850 buffer = strrchrW(package->PackagePath, '\\') + 1;
3851 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3852 package->Context, MSICODE_PRODUCT,
3853 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3854 if (r != ERROR_SUCCESS)
3857 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3858 package->Context, MSICODE_PRODUCT,
3859 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3860 if (r != ERROR_SUCCESS)
3863 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3864 package->Context, MSICODE_PRODUCT,
3865 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3866 if (r != ERROR_SUCCESS)
3869 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3871 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3872 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3873 info->options, info->value);
3875 MsiSourceListSetInfoW(package->ProductCode, NULL,
3876 info->context, info->options,
3877 info->property, info->value);
3880 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3882 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3883 disk->context, disk->options,
3884 disk->disk_id, disk->volume_label, disk->disk_prompt);
3887 return ERROR_SUCCESS;
3890 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3892 MSIHANDLE hdb, suminfo;
3893 WCHAR guids[MAX_PATH];
3894 WCHAR packcode[SQUISH_GUID_SIZE];
3901 static const WCHAR szProductLanguage[] =
3902 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3903 static const WCHAR szARPProductIcon[] =
3904 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3905 static const WCHAR szProductVersion[] =
3906 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3907 static const WCHAR szAssignment[] =
3908 {'A','s','s','i','g','n','m','e','n','t',0};
3909 static const WCHAR szAdvertiseFlags[] =
3910 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3911 static const WCHAR szClients[] =
3912 {'C','l','i','e','n','t','s',0};
3913 static const WCHAR szColon[] = {':',0};
3915 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3916 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3919 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3923 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3925 buffer = msi_dup_property(package->db, szARPProductIcon);
3928 LPWSTR path = build_icon_path(package,buffer);
3929 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3934 buffer = msi_dup_property(package->db, szProductVersion);
3937 DWORD verdword = msi_version_str_to_dword(buffer);
3938 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3942 msi_reg_set_val_dword(hkey, szAssignment, 0);
3943 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3944 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3945 msi_reg_set_val_str(hkey, szClients, szColon);
3947 hdb = alloc_msihandle(&package->db->hdr);
3949 return ERROR_NOT_ENOUGH_MEMORY;
3951 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3952 MsiCloseHandle(hdb);
3953 if (r != ERROR_SUCCESS)
3957 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3958 NULL, guids, &size);
3959 if (r != ERROR_SUCCESS)
3962 ptr = strchrW(guids, ';');
3964 squash_guid(guids, packcode);
3965 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3968 MsiCloseHandle(suminfo);
3969 return ERROR_SUCCESS;
3972 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3977 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3979 upgrade = msi_dup_property(package->db, szUpgradeCode);
3981 return ERROR_SUCCESS;
3983 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3985 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3986 if (r != ERROR_SUCCESS)
3991 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3992 if (r != ERROR_SUCCESS)
3996 squash_guid(package->ProductCode, squashed_pc);
3997 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4006 static BOOL msi_check_publish(MSIPACKAGE *package)
4008 MSIFEATURE *feature;
4010 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4012 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4019 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4021 MSIFEATURE *feature;
4023 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4025 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4032 static UINT msi_publish_patches( MSIPACKAGE *package )
4034 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4035 WCHAR patch_squashed[GUID_SIZE];
4036 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4038 MSIPATCHINFO *patch;
4040 WCHAR *p, *all_patches = NULL;
4043 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4044 if (r != ERROR_SUCCESS)
4045 return ERROR_FUNCTION_FAILED;
4047 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4048 if (res != ERROR_SUCCESS)
4050 r = ERROR_FUNCTION_FAILED;
4054 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4055 if (r != ERROR_SUCCESS)
4058 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4060 squash_guid( patch->patchcode, patch_squashed );
4061 len += strlenW( patch_squashed ) + 1;
4064 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4068 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4072 squash_guid( patch->patchcode, p );
4073 p += strlenW( p ) + 1;
4075 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4076 (const BYTE *)patch->transforms,
4077 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4078 if (res != ERROR_SUCCESS)
4081 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4082 if (r != ERROR_SUCCESS)
4085 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4086 (const BYTE *)patch->localfile,
4087 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4088 RegCloseKey( patch_key );
4089 if (res != ERROR_SUCCESS)
4092 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4093 if (res != ERROR_SUCCESS)
4096 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4097 RegCloseKey( patch_key );
4098 if (res != ERROR_SUCCESS)
4102 all_patches[len] = 0;
4103 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4104 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4105 if (res != ERROR_SUCCESS)
4108 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4109 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4110 if (res != ERROR_SUCCESS)
4111 r = ERROR_FUNCTION_FAILED;
4114 RegCloseKey( product_patches_key );
4115 RegCloseKey( patches_key );
4116 RegCloseKey( product_key );
4117 msi_free( all_patches );
4122 * 99% of the work done here is only done for
4123 * advertised installs. However this is where the
4124 * Icon table is processed and written out
4125 * so that is what I am going to do here.
4127 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4130 HKEY hukey = NULL, hudkey = NULL;
4133 if (!list_empty(&package->patches))
4135 rc = msi_publish_patches(package);
4136 if (rc != ERROR_SUCCESS)
4140 /* FIXME: also need to publish if the product is in advertise mode */
4141 if (!msi_check_publish(package))
4142 return ERROR_SUCCESS;
4144 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4146 if (rc != ERROR_SUCCESS)
4149 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4150 NULL, &hudkey, TRUE);
4151 if (rc != ERROR_SUCCESS)
4154 rc = msi_publish_upgrade_code(package);
4155 if (rc != ERROR_SUCCESS)
4158 rc = msi_publish_product_properties(package, hukey);
4159 if (rc != ERROR_SUCCESS)
4162 rc = msi_publish_sourcelist(package, hukey);
4163 if (rc != ERROR_SUCCESS)
4166 rc = msi_publish_icons(package);
4169 uirow = MSI_CreateRecord( 1 );
4170 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4171 ui_actiondata( package, szPublishProduct, uirow );
4172 msiobj_release( &uirow->hdr );
4175 RegCloseKey(hudkey);
4180 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4182 WCHAR *filename, *ptr, *folder, *ret;
4183 const WCHAR *dirprop;
4185 filename = msi_dup_record_field( row, 2 );
4186 if (filename && (ptr = strchrW( filename, '|' )))
4191 dirprop = MSI_RecordGetString( row, 3 );
4194 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4196 folder = msi_dup_property( package->db, dirprop );
4199 folder = msi_dup_property( package->db, szWindowsFolder );
4203 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4204 msi_free( filename );
4208 ret = build_directory_name( 2, folder, ptr );
4210 msi_free( filename );
4215 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4217 MSIPACKAGE *package = param;
4218 LPCWSTR component, section, key, value, identifier;
4219 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4224 component = MSI_RecordGetString(row, 8);
4225 comp = get_loaded_component(package,component);
4227 return ERROR_SUCCESS;
4231 TRACE("component is disabled\n");
4232 return ERROR_SUCCESS;
4235 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4237 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4238 comp->Action = comp->Installed;
4239 return ERROR_SUCCESS;
4241 comp->Action = INSTALLSTATE_LOCAL;
4243 identifier = MSI_RecordGetString(row,1);
4244 section = MSI_RecordGetString(row,4);
4245 key = MSI_RecordGetString(row,5);
4246 value = MSI_RecordGetString(row,6);
4247 action = MSI_RecordGetInteger(row,7);
4249 deformat_string(package,section,&deformated_section);
4250 deformat_string(package,key,&deformated_key);
4251 deformat_string(package,value,&deformated_value);
4253 fullname = get_ini_file_name(package, row);
4257 TRACE("Adding value %s to section %s in %s\n",
4258 debugstr_w(deformated_key), debugstr_w(deformated_section),
4259 debugstr_w(fullname));
4260 WritePrivateProfileStringW(deformated_section, deformated_key,
4261 deformated_value, fullname);
4263 else if (action == 1)
4266 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4267 returned, 10, fullname);
4268 if (returned[0] == 0)
4270 TRACE("Adding value %s to section %s in %s\n",
4271 debugstr_w(deformated_key), debugstr_w(deformated_section),
4272 debugstr_w(fullname));
4274 WritePrivateProfileStringW(deformated_section, deformated_key,
4275 deformated_value, fullname);
4278 else if (action == 3)
4279 FIXME("Append to existing section not yet implemented\n");
4281 uirow = MSI_CreateRecord(4);
4282 MSI_RecordSetStringW(uirow,1,identifier);
4283 MSI_RecordSetStringW(uirow,2,deformated_section);
4284 MSI_RecordSetStringW(uirow,3,deformated_key);
4285 MSI_RecordSetStringW(uirow,4,deformated_value);
4286 ui_actiondata(package,szWriteIniValues,uirow);
4287 msiobj_release( &uirow->hdr );
4290 msi_free(deformated_key);
4291 msi_free(deformated_value);
4292 msi_free(deformated_section);
4293 return ERROR_SUCCESS;
4296 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4300 static const WCHAR ExecSeqQuery[] =
4301 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4302 '`','I','n','i','F','i','l','e','`',0};
4304 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4305 if (rc != ERROR_SUCCESS)
4307 TRACE("no IniFile table\n");
4308 return ERROR_SUCCESS;
4311 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4312 msiobj_release(&view->hdr);
4316 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4318 MSIPACKAGE *package = param;
4319 LPCWSTR component, section, key, value, identifier;
4320 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4325 component = MSI_RecordGetString( row, 8 );
4326 comp = get_loaded_component( package, component );
4328 return ERROR_SUCCESS;
4332 TRACE("component is disabled\n");
4333 return ERROR_SUCCESS;
4336 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4338 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4339 comp->Action = comp->Installed;
4340 return ERROR_SUCCESS;
4342 comp->Action = INSTALLSTATE_ABSENT;
4344 identifier = MSI_RecordGetString( row, 1 );
4345 section = MSI_RecordGetString( row, 4 );
4346 key = MSI_RecordGetString( row, 5 );
4347 value = MSI_RecordGetString( row, 6 );
4348 action = MSI_RecordGetInteger( row, 7 );
4350 deformat_string( package, section, &deformated_section );
4351 deformat_string( package, key, &deformated_key );
4352 deformat_string( package, value, &deformated_value );
4354 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4356 filename = get_ini_file_name( package, row );
4358 TRACE("Removing key %s from section %s in %s\n",
4359 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4361 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4363 WARN("Unable to remove key %u\n", GetLastError());
4365 msi_free( filename );
4368 FIXME("Unsupported action %d\n", action);
4371 uirow = MSI_CreateRecord( 4 );
4372 MSI_RecordSetStringW( uirow, 1, identifier );
4373 MSI_RecordSetStringW( uirow, 2, deformated_section );
4374 MSI_RecordSetStringW( uirow, 3, deformated_key );
4375 MSI_RecordSetStringW( uirow, 4, deformated_value );
4376 ui_actiondata( package, szRemoveIniValues, uirow );
4377 msiobj_release( &uirow->hdr );
4379 msi_free( deformated_key );
4380 msi_free( deformated_value );
4381 msi_free( deformated_section );
4382 return ERROR_SUCCESS;
4385 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4387 MSIPACKAGE *package = param;
4388 LPCWSTR component, section, key, value, identifier;
4389 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4394 component = MSI_RecordGetString( row, 8 );
4395 comp = get_loaded_component( package, component );
4397 return ERROR_SUCCESS;
4401 TRACE("component is disabled\n");
4402 return ERROR_SUCCESS;
4405 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4407 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4408 comp->Action = comp->Installed;
4409 return ERROR_SUCCESS;
4411 comp->Action = INSTALLSTATE_LOCAL;
4413 identifier = MSI_RecordGetString( row, 1 );
4414 section = MSI_RecordGetString( row, 4 );
4415 key = MSI_RecordGetString( row, 5 );
4416 value = MSI_RecordGetString( row, 6 );
4417 action = MSI_RecordGetInteger( row, 7 );
4419 deformat_string( package, section, &deformated_section );
4420 deformat_string( package, key, &deformated_key );
4421 deformat_string( package, value, &deformated_value );
4423 if (action == msidbIniFileActionRemoveLine)
4425 filename = get_ini_file_name( package, row );
4427 TRACE("Removing key %s from section %s in %s\n",
4428 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4430 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4432 WARN("Unable to remove key %u\n", GetLastError());
4434 msi_free( filename );
4437 FIXME("Unsupported action %d\n", action);
4439 uirow = MSI_CreateRecord( 4 );
4440 MSI_RecordSetStringW( uirow, 1, identifier );
4441 MSI_RecordSetStringW( uirow, 2, deformated_section );
4442 MSI_RecordSetStringW( uirow, 3, deformated_key );
4443 MSI_RecordSetStringW( uirow, 4, deformated_value );
4444 ui_actiondata( package, szRemoveIniValues, uirow );
4445 msiobj_release( &uirow->hdr );
4447 msi_free( deformated_key );
4448 msi_free( deformated_value );
4449 msi_free( deformated_section );
4450 return ERROR_SUCCESS;
4453 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4457 static const WCHAR query[] =
4458 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4459 '`','I','n','i','F','i','l','e','`',0};
4460 static const WCHAR remove_query[] =
4461 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4462 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4464 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4465 if (rc == ERROR_SUCCESS)
4467 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4468 msiobj_release( &view->hdr );
4469 if (rc != ERROR_SUCCESS)
4473 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4474 if (rc == ERROR_SUCCESS)
4476 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4477 msiobj_release( &view->hdr );
4478 if (rc != ERROR_SUCCESS)
4482 return ERROR_SUCCESS;
4485 static void register_dll( const WCHAR *dll, BOOL unregister )
4489 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4492 HRESULT (WINAPI *func_ptr)( void );
4493 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4495 func_ptr = (void *)GetProcAddress( hmod, func );
4498 HRESULT hr = func_ptr();
4500 WARN("failed to register dll 0x%08x\n", hr);
4503 WARN("entry point %s not found\n", func);
4504 FreeLibrary( hmod );
4507 WARN("failed to load library %u\n", GetLastError());
4510 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4512 MSIPACKAGE *package = param;
4517 filename = MSI_RecordGetString(row,1);
4518 file = get_loaded_file( package, filename );
4522 ERR("Unable to find file id %s\n",debugstr_w(filename));
4523 return ERROR_SUCCESS;
4526 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4528 register_dll( file->TargetPath, FALSE );
4530 uirow = MSI_CreateRecord( 2 );
4531 MSI_RecordSetStringW( uirow, 1, filename );
4532 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4533 ui_actiondata( package, szSelfRegModules, uirow );
4534 msiobj_release( &uirow->hdr );
4536 return ERROR_SUCCESS;
4539 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4543 static const WCHAR ExecSeqQuery[] =
4544 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4545 '`','S','e','l','f','R','e','g','`',0};
4547 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4548 if (rc != ERROR_SUCCESS)
4550 TRACE("no SelfReg table\n");
4551 return ERROR_SUCCESS;
4554 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4555 msiobj_release(&view->hdr);
4557 return ERROR_SUCCESS;
4560 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4562 MSIPACKAGE *package = param;
4567 filename = MSI_RecordGetString( row, 1 );
4568 file = get_loaded_file( package, filename );
4572 ERR("Unable to find file id %s\n", debugstr_w(filename));
4573 return ERROR_SUCCESS;
4576 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4578 register_dll( file->TargetPath, TRUE );
4580 uirow = MSI_CreateRecord( 2 );
4581 MSI_RecordSetStringW( uirow, 1, filename );
4582 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4583 ui_actiondata( package, szSelfUnregModules, uirow );
4584 msiobj_release( &uirow->hdr );
4586 return ERROR_SUCCESS;
4589 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4593 static const WCHAR query[] =
4594 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4595 '`','S','e','l','f','R','e','g','`',0};
4597 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4598 if (rc != ERROR_SUCCESS)
4600 TRACE("no SelfReg table\n");
4601 return ERROR_SUCCESS;
4604 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4605 msiobj_release( &view->hdr );
4607 return ERROR_SUCCESS;
4610 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4612 MSIFEATURE *feature;
4614 HKEY hkey = NULL, userdata = NULL;
4616 if (!msi_check_publish(package))
4617 return ERROR_SUCCESS;
4619 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4621 if (rc != ERROR_SUCCESS)
4624 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4626 if (rc != ERROR_SUCCESS)
4629 /* here the guids are base 85 encoded */
4630 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4636 BOOL absent = FALSE;
4639 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4640 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4641 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4644 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4648 if (feature->Feature_Parent)
4649 size += strlenW( feature->Feature_Parent )+2;
4651 data = msi_alloc(size * sizeof(WCHAR));
4654 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4656 MSICOMPONENT* component = cl->component;
4660 if (component->ComponentId)
4662 TRACE("From %s\n",debugstr_w(component->ComponentId));
4663 CLSIDFromString(component->ComponentId, &clsid);
4664 encode_base85_guid(&clsid,buf);
4665 TRACE("to %s\n",debugstr_w(buf));
4670 if (feature->Feature_Parent)
4672 static const WCHAR sep[] = {'\2',0};
4674 strcatW(data,feature->Feature_Parent);
4677 msi_reg_set_val_str( userdata, feature->Feature, data );
4681 if (feature->Feature_Parent)
4682 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4685 size += sizeof(WCHAR);
4686 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4687 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4691 size += 2*sizeof(WCHAR);
4692 data = msi_alloc(size);
4695 if (feature->Feature_Parent)
4696 strcpyW( &data[1], feature->Feature_Parent );
4697 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4703 uirow = MSI_CreateRecord( 1 );
4704 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4705 ui_actiondata( package, szPublishFeatures, uirow);
4706 msiobj_release( &uirow->hdr );
4707 /* FIXME: call ui_progress? */
4712 RegCloseKey(userdata);
4716 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4722 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4724 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4726 if (r == ERROR_SUCCESS)
4728 RegDeleteValueW(hkey, feature->Feature);
4732 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4734 if (r == ERROR_SUCCESS)
4736 RegDeleteValueW(hkey, feature->Feature);
4740 uirow = MSI_CreateRecord( 1 );
4741 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4742 ui_actiondata( package, szUnpublishFeatures, uirow );
4743 msiobj_release( &uirow->hdr );
4745 return ERROR_SUCCESS;
4748 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4750 MSIFEATURE *feature;
4752 if (!msi_check_unpublish(package))
4753 return ERROR_SUCCESS;
4755 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4757 msi_unpublish_feature(package, feature);
4760 return ERROR_SUCCESS;
4763 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4767 WCHAR date[9], *val, *buffer;
4768 const WCHAR *prop, *key;
4770 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4771 static const WCHAR szWindowsInstaller[] =
4772 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4773 static const WCHAR modpath_fmt[] =
4774 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4775 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4776 static const WCHAR szModifyPath[] =
4777 {'M','o','d','i','f','y','P','a','t','h',0};
4778 static const WCHAR szUninstallString[] =
4779 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4780 static const WCHAR szEstimatedSize[] =
4781 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4782 static const WCHAR szProductLanguage[] =
4783 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4784 static const WCHAR szProductVersion[] =
4785 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4786 static const WCHAR szDisplayVersion[] =
4787 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4788 static const WCHAR szInstallSource[] =
4789 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4790 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4791 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4792 static const WCHAR szAuthorizedCDFPrefix[] =
4793 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4794 static const WCHAR szARPCONTACT[] =
4795 {'A','R','P','C','O','N','T','A','C','T',0};
4796 static const WCHAR szContact[] =
4797 {'C','o','n','t','a','c','t',0};
4798 static const WCHAR szARPCOMMENTS[] =
4799 {'A','R','P','C','O','M','M','E','N','T','S',0};
4800 static const WCHAR szComments[] =
4801 {'C','o','m','m','e','n','t','s',0};
4802 static const WCHAR szProductName[] =
4803 {'P','r','o','d','u','c','t','N','a','m','e',0};
4804 static const WCHAR szDisplayName[] =
4805 {'D','i','s','p','l','a','y','N','a','m','e',0};
4806 static const WCHAR szARPHELPLINK[] =
4807 {'A','R','P','H','E','L','P','L','I','N','K',0};
4808 static const WCHAR szHelpLink[] =
4809 {'H','e','l','p','L','i','n','k',0};
4810 static const WCHAR szARPHELPTELEPHONE[] =
4811 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4812 static const WCHAR szHelpTelephone[] =
4813 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4814 static const WCHAR szARPINSTALLLOCATION[] =
4815 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4816 static const WCHAR szInstallLocation[] =
4817 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4818 static const WCHAR szManufacturer[] =
4819 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4820 static const WCHAR szPublisher[] =
4821 {'P','u','b','l','i','s','h','e','r',0};
4822 static const WCHAR szARPREADME[] =
4823 {'A','R','P','R','E','A','D','M','E',0};
4824 static const WCHAR szReadme[] =
4825 {'R','e','a','d','M','e',0};
4826 static const WCHAR szARPSIZE[] =
4827 {'A','R','P','S','I','Z','E',0};
4828 static const WCHAR szSize[] =
4829 {'S','i','z','e',0};
4830 static const WCHAR szARPURLINFOABOUT[] =
4831 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4832 static const WCHAR szURLInfoAbout[] =
4833 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4834 static const WCHAR szARPURLUPDATEINFO[] =
4835 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4836 static const WCHAR szURLUpdateInfo[] =
4837 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4839 static const WCHAR *propval[] = {
4840 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4841 szARPCONTACT, szContact,
4842 szARPCOMMENTS, szComments,
4843 szProductName, szDisplayName,
4844 szARPHELPLINK, szHelpLink,
4845 szARPHELPTELEPHONE, szHelpTelephone,
4846 szARPINSTALLLOCATION, szInstallLocation,
4847 cszSourceDir, szInstallSource,
4848 szManufacturer, szPublisher,
4849 szARPREADME, szReadme,
4851 szARPURLINFOABOUT, szURLInfoAbout,
4852 szARPURLUPDATEINFO, szURLUpdateInfo,
4855 const WCHAR **p = propval;
4861 val = msi_dup_property(package->db, prop);
4862 msi_reg_set_val_str(hkey, key, val);
4866 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4868 size = deformat_string(package, modpath_fmt, &buffer);
4869 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4870 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4873 /* FIXME: Write real Estimated Size when we have it */
4874 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4876 GetLocalTime(&systime);
4877 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4878 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4880 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4881 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4883 buffer = msi_dup_property(package->db, szProductVersion);
4884 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4887 DWORD verdword = msi_version_str_to_dword(buffer);
4889 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4890 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4891 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4895 return ERROR_SUCCESS;
4898 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4900 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4902 LPWSTR upgrade_code;
4907 /* FIXME: also need to publish if the product is in advertise mode */
4908 if (!msi_check_publish(package))
4909 return ERROR_SUCCESS;
4911 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4912 if (rc != ERROR_SUCCESS)
4915 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4916 NULL, &props, TRUE);
4917 if (rc != ERROR_SUCCESS)
4920 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4921 msi_free( package->db->localfile );
4922 package->db->localfile = NULL;
4924 rc = msi_publish_install_properties(package, hkey);
4925 if (rc != ERROR_SUCCESS)
4928 rc = msi_publish_install_properties(package, props);
4929 if (rc != ERROR_SUCCESS)
4932 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4935 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4936 squash_guid(package->ProductCode, squashed_pc);
4937 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4938 RegCloseKey(upgrade);
4939 msi_free(upgrade_code);
4943 uirow = MSI_CreateRecord( 1 );
4944 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4945 ui_actiondata( package, szRegisterProduct, uirow );
4946 msiobj_release( &uirow->hdr );
4949 return ERROR_SUCCESS;
4952 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4954 return execute_script(package,INSTALL_SCRIPT);
4957 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4959 WCHAR *upgrade, **features;
4960 BOOL full_uninstall = TRUE;
4961 MSIFEATURE *feature;
4962 MSIPATCHINFO *patch;
4964 static const WCHAR szUpgradeCode[] =
4965 {'U','p','g','r','a','d','e','C','o','d','e',0};
4967 features = msi_split_string(remove, ',');
4970 ERR("REMOVE feature list is empty!\n");
4971 return ERROR_FUNCTION_FAILED;
4974 if (!strcmpW( features[0], szAll ))
4975 full_uninstall = TRUE;
4978 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4980 if (feature->Action != INSTALLSTATE_ABSENT)
4981 full_uninstall = FALSE;
4986 if (!full_uninstall)
4987 return ERROR_SUCCESS;
4989 MSIREG_DeleteProductKey(package->ProductCode);
4990 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4991 MSIREG_DeleteUninstallKey(package);
4993 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4995 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4996 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5000 MSIREG_DeleteUserProductKey(package->ProductCode);
5001 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5004 upgrade = msi_dup_property(package->db, szUpgradeCode);
5007 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5011 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5013 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5016 return ERROR_SUCCESS;
5019 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5024 /* turn off scheduling */
5025 package->script->CurrentlyScripting= FALSE;
5027 /* first do the same as an InstallExecute */
5028 rc = ACTION_InstallExecute(package);
5029 if (rc != ERROR_SUCCESS)
5032 /* then handle Commit Actions */
5033 rc = execute_script(package,COMMIT_SCRIPT);
5034 if (rc != ERROR_SUCCESS)
5037 remove = msi_dup_property(package->db, szRemove);
5039 rc = msi_unpublish_product(package, remove);
5045 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5047 static const WCHAR RunOnce[] = {
5048 'S','o','f','t','w','a','r','e','\\',
5049 'M','i','c','r','o','s','o','f','t','\\',
5050 'W','i','n','d','o','w','s','\\',
5051 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5052 'R','u','n','O','n','c','e',0};
5053 static const WCHAR InstallRunOnce[] = {
5054 'S','o','f','t','w','a','r','e','\\',
5055 'M','i','c','r','o','s','o','f','t','\\',
5056 'W','i','n','d','o','w','s','\\',
5057 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5058 'I','n','s','t','a','l','l','e','r','\\',
5059 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5061 static const WCHAR msiexec_fmt[] = {
5063 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5064 '\"','%','s','\"',0};
5065 static const WCHAR install_fmt[] = {
5066 '/','I',' ','\"','%','s','\"',' ',
5067 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5068 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5069 WCHAR buffer[256], sysdir[MAX_PATH];
5071 WCHAR squished_pc[100];
5073 squash_guid(package->ProductCode,squished_pc);
5075 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5076 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5077 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5080 msi_reg_set_val_str( hkey, squished_pc, buffer );
5083 TRACE("Reboot command %s\n",debugstr_w(buffer));
5085 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5086 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5088 msi_reg_set_val_str( hkey, squished_pc, buffer );
5091 return ERROR_INSTALL_SUSPEND;
5094 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5100 * We are currently doing what should be done here in the top level Install
5101 * however for Administrative and uninstalls this step will be needed
5103 if (!package->PackagePath)
5104 return ERROR_SUCCESS;
5106 msi_set_sourcedir_props(package, TRUE);
5108 attrib = GetFileAttributesW(package->db->path);
5109 if (attrib == INVALID_FILE_ATTRIBUTES)
5115 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5116 package->Context, MSICODE_PRODUCT,
5117 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5118 if (rc == ERROR_MORE_DATA)
5120 prompt = msi_alloc(size * sizeof(WCHAR));
5121 MsiSourceListGetInfoW(package->ProductCode, NULL,
5122 package->Context, MSICODE_PRODUCT,
5123 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5126 prompt = strdupW(package->db->path);
5128 msg = generate_error_string(package,1302,1,prompt);
5129 while(attrib == INVALID_FILE_ATTRIBUTES)
5131 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5134 rc = ERROR_INSTALL_USEREXIT;
5137 attrib = GetFileAttributesW(package->db->path);
5143 return ERROR_SUCCESS;
5148 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5151 LPWSTR buffer, productid = NULL;
5152 UINT i, rc = ERROR_SUCCESS;
5155 static const WCHAR szPropKeys[][80] =
5157 {'P','r','o','d','u','c','t','I','D',0},
5158 {'U','S','E','R','N','A','M','E',0},
5159 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5163 static const WCHAR szRegKeys[][80] =
5165 {'P','r','o','d','u','c','t','I','D',0},
5166 {'R','e','g','O','w','n','e','r',0},
5167 {'R','e','g','C','o','m','p','a','n','y',0},
5171 if (msi_check_unpublish(package))
5173 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5177 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5181 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5183 if (rc != ERROR_SUCCESS)
5186 for( i = 0; szPropKeys[i][0]; i++ )
5188 buffer = msi_dup_property( package->db, szPropKeys[i] );
5189 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5194 uirow = MSI_CreateRecord( 1 );
5195 MSI_RecordSetStringW( uirow, 1, productid );
5196 ui_actiondata( package, szRegisterUser, uirow );
5197 msiobj_release( &uirow->hdr );
5199 msi_free(productid);
5205 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5209 package->script->InWhatSequence |= SEQUENCE_EXEC;
5210 rc = ACTION_ProcessExecSequence(package,FALSE);
5215 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5217 MSIPACKAGE *package = param;
5218 LPCWSTR compgroupid, component, feature, qualifier, text;
5219 LPWSTR advertise = NULL, output = NULL;
5227 feature = MSI_RecordGetString(rec, 5);
5228 feat = get_loaded_feature(package, feature);
5230 return ERROR_SUCCESS;
5232 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5233 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5234 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5236 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5237 feat->Action = feat->Installed;
5238 return ERROR_SUCCESS;
5241 component = MSI_RecordGetString(rec, 3);
5242 comp = get_loaded_component(package, component);
5244 return ERROR_SUCCESS;
5246 compgroupid = MSI_RecordGetString(rec,1);
5247 qualifier = MSI_RecordGetString(rec,2);
5249 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5250 if (rc != ERROR_SUCCESS)
5253 text = MSI_RecordGetString(rec,4);
5254 advertise = create_component_advertise_string(package, comp, feature);
5256 sz = strlenW(advertise);
5259 sz += lstrlenW(text);
5262 sz *= sizeof(WCHAR);
5264 output = msi_alloc_zero(sz);
5265 strcpyW(output,advertise);
5266 msi_free(advertise);
5269 strcatW(output,text);
5271 msi_reg_set_val_multi_str( hkey, qualifier, output );
5278 uirow = MSI_CreateRecord( 2 );
5279 MSI_RecordSetStringW( uirow, 1, compgroupid );
5280 MSI_RecordSetStringW( uirow, 2, qualifier);
5281 ui_actiondata( package, szPublishComponents, uirow);
5282 msiobj_release( &uirow->hdr );
5283 /* FIXME: call ui_progress? */
5289 * At present I am ignorning the advertised components part of this and only
5290 * focusing on the qualified component sets
5292 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5296 static const WCHAR ExecSeqQuery[] =
5297 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5298 '`','P','u','b','l','i','s','h',
5299 'C','o','m','p','o','n','e','n','t','`',0};
5301 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5302 if (rc != ERROR_SUCCESS)
5303 return ERROR_SUCCESS;
5305 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5306 msiobj_release(&view->hdr);
5311 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5313 static const WCHAR szInstallerComponents[] = {
5314 'S','o','f','t','w','a','r','e','\\',
5315 'M','i','c','r','o','s','o','f','t','\\',
5316 'I','n','s','t','a','l','l','e','r','\\',
5317 'C','o','m','p','o','n','e','n','t','s','\\',0};
5319 MSIPACKAGE *package = param;
5320 LPCWSTR compgroupid, component, feature, qualifier;
5324 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5327 feature = MSI_RecordGetString( rec, 5 );
5328 feat = get_loaded_feature( package, feature );
5330 return ERROR_SUCCESS;
5332 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5334 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5335 feat->Action = feat->Installed;
5336 return ERROR_SUCCESS;
5339 component = MSI_RecordGetString( rec, 3 );
5340 comp = get_loaded_component( package, component );
5342 return ERROR_SUCCESS;
5344 compgroupid = MSI_RecordGetString( rec, 1 );
5345 qualifier = MSI_RecordGetString( rec, 2 );
5347 squash_guid( compgroupid, squashed );
5348 strcpyW( keypath, szInstallerComponents );
5349 strcatW( keypath, squashed );
5351 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5352 if (res != ERROR_SUCCESS)
5354 WARN("Unable to delete component key %d\n", res);
5357 uirow = MSI_CreateRecord( 2 );
5358 MSI_RecordSetStringW( uirow, 1, compgroupid );
5359 MSI_RecordSetStringW( uirow, 2, qualifier );
5360 ui_actiondata( package, szUnpublishComponents, uirow );
5361 msiobj_release( &uirow->hdr );
5363 return ERROR_SUCCESS;
5366 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5370 static const WCHAR query[] =
5371 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5372 '`','P','u','b','l','i','s','h',
5373 'C','o','m','p','o','n','e','n','t','`',0};
5375 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5376 if (rc != ERROR_SUCCESS)
5377 return ERROR_SUCCESS;
5379 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5380 msiobj_release( &view->hdr );
5385 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5387 MSIPACKAGE *package = param;
5390 SC_HANDLE hscm, service = NULL;
5392 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5393 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5394 DWORD serv_type, start_type, err_control;
5395 SERVICE_DESCRIPTIONW sd = {NULL};
5397 static const WCHAR query[] =
5398 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5399 '`','C','o','m','p','o','n','e','n','t','`',' ',
5400 'W','H','E','R','E',' ',
5401 '`','C','o','m','p','o','n','e','n','t','`',' ',
5402 '=','\'','%','s','\'',0};
5404 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5407 ERR("Failed to open the SC Manager!\n");
5411 start_type = MSI_RecordGetInteger(rec, 5);
5412 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5415 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5416 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5417 serv_type = MSI_RecordGetInteger(rec, 4);
5418 err_control = MSI_RecordGetInteger(rec, 6);
5419 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5420 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5421 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5422 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5423 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5424 comp = MSI_RecordGetString(rec, 12);
5425 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5427 /* fetch the service path */
5428 row = MSI_QueryGetRecord(package->db, query, comp);
5431 ERR("Control query failed!\n");
5434 key = MSI_RecordGetString(row, 6);
5436 file = get_loaded_file(package, key);
5437 msiobj_release(&row->hdr);
5440 ERR("Failed to load the service file\n");
5444 if (!args || !args[0]) image_path = file->TargetPath;
5447 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5448 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5449 return ERROR_OUTOFMEMORY;
5451 strcpyW(image_path, file->TargetPath);
5452 strcatW(image_path, szSpace);
5453 strcatW(image_path, args);
5455 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5456 start_type, err_control, image_path, load_order,
5457 NULL, depends, serv_name, pass);
5461 if (GetLastError() != ERROR_SERVICE_EXISTS)
5462 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5464 else if (sd.lpDescription)
5466 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5467 WARN("failed to set service description %u\n", GetLastError());
5470 if (image_path != file->TargetPath) msi_free(image_path);
5472 CloseServiceHandle(service);
5473 CloseServiceHandle(hscm);
5476 msi_free(sd.lpDescription);
5477 msi_free(load_order);
5478 msi_free(serv_name);
5483 return ERROR_SUCCESS;
5486 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5490 static const WCHAR ExecSeqQuery[] =
5491 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5492 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5494 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5495 if (rc != ERROR_SUCCESS)
5496 return ERROR_SUCCESS;
5498 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5499 msiobj_release(&view->hdr);
5504 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5505 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5507 LPCWSTR *vector, *temp_vector;
5511 static const WCHAR separator[] = {'[','~',']',0};
5514 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5519 vector = msi_alloc(sizeof(LPWSTR));
5527 vector[*numargs - 1] = p;
5529 if ((q = strstrW(p, separator)))
5533 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5539 vector = temp_vector;
5548 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5550 MSIPACKAGE *package = param;
5553 SC_HANDLE scm = NULL, service = NULL;
5554 LPCWSTR component, *vector = NULL;
5555 LPWSTR name, args, display_name = NULL;
5556 DWORD event, numargs, len;
5557 UINT r = ERROR_FUNCTION_FAILED;
5559 component = MSI_RecordGetString(rec, 6);
5560 comp = get_loaded_component(package, component);
5562 return ERROR_SUCCESS;
5566 TRACE("component is disabled\n");
5567 return ERROR_SUCCESS;
5570 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5572 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5573 comp->Action = comp->Installed;
5574 return ERROR_SUCCESS;
5576 comp->Action = INSTALLSTATE_LOCAL;
5578 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5579 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5580 event = MSI_RecordGetInteger(rec, 3);
5582 if (!(event & msidbServiceControlEventStart))
5588 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5591 ERR("Failed to open the service control manager\n");
5596 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5597 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5599 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5600 GetServiceDisplayNameW( scm, name, display_name, &len );
5603 service = OpenServiceW(scm, name, SERVICE_START);
5606 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5610 vector = msi_service_args_to_vector(args, &numargs);
5612 if (!StartServiceW(service, numargs, vector) &&
5613 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5615 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5622 uirow = MSI_CreateRecord( 2 );
5623 MSI_RecordSetStringW( uirow, 1, display_name );
5624 MSI_RecordSetStringW( uirow, 2, name );
5625 ui_actiondata( package, szStartServices, uirow );
5626 msiobj_release( &uirow->hdr );
5628 CloseServiceHandle(service);
5629 CloseServiceHandle(scm);
5634 msi_free(display_name);
5638 static UINT ACTION_StartServices( MSIPACKAGE *package )
5643 static const WCHAR query[] = {
5644 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5645 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5647 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5648 if (rc != ERROR_SUCCESS)
5649 return ERROR_SUCCESS;
5651 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5652 msiobj_release(&view->hdr);
5657 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5659 DWORD i, needed, count;
5660 ENUM_SERVICE_STATUSW *dependencies;
5664 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5665 0, &needed, &count))
5668 if (GetLastError() != ERROR_MORE_DATA)
5671 dependencies = msi_alloc(needed);
5675 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5676 needed, &needed, &count))
5679 for (i = 0; i < count; i++)
5681 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5682 SERVICE_STOP | SERVICE_QUERY_STATUS);
5686 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5693 msi_free(dependencies);
5697 static UINT stop_service( LPCWSTR name )
5699 SC_HANDLE scm = NULL, service = NULL;
5700 SERVICE_STATUS status;
5701 SERVICE_STATUS_PROCESS ssp;
5704 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5707 WARN("Failed to open the SCM: %d\n", GetLastError());
5711 service = OpenServiceW(scm, name,
5713 SERVICE_QUERY_STATUS |
5714 SERVICE_ENUMERATE_DEPENDENTS);
5717 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5721 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5722 sizeof(SERVICE_STATUS_PROCESS), &needed))
5724 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5728 if (ssp.dwCurrentState == SERVICE_STOPPED)
5731 stop_service_dependents(scm, service);
5733 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5734 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5737 CloseServiceHandle(service);
5738 CloseServiceHandle(scm);
5740 return ERROR_SUCCESS;
5743 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5745 MSIPACKAGE *package = param;
5749 LPWSTR name = NULL, display_name = NULL;
5753 event = MSI_RecordGetInteger( rec, 3 );
5754 if (!(event & msidbServiceControlEventStop))
5755 return ERROR_SUCCESS;
5757 component = MSI_RecordGetString( rec, 6 );
5758 comp = get_loaded_component( package, component );
5760 return ERROR_SUCCESS;
5764 TRACE("component is disabled\n");
5765 return ERROR_SUCCESS;
5768 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5770 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5771 comp->Action = comp->Installed;
5772 return ERROR_SUCCESS;
5774 comp->Action = INSTALLSTATE_ABSENT;
5776 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5779 ERR("Failed to open the service control manager\n");
5784 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5785 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5787 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5788 GetServiceDisplayNameW( scm, name, display_name, &len );
5790 CloseServiceHandle( scm );
5792 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5793 stop_service( name );
5796 uirow = MSI_CreateRecord( 2 );
5797 MSI_RecordSetStringW( uirow, 1, display_name );
5798 MSI_RecordSetStringW( uirow, 2, name );
5799 ui_actiondata( package, szStopServices, uirow );
5800 msiobj_release( &uirow->hdr );
5803 msi_free( display_name );
5804 return ERROR_SUCCESS;
5807 static UINT ACTION_StopServices( MSIPACKAGE *package )
5812 static const WCHAR query[] = {
5813 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5814 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5816 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5817 if (rc != ERROR_SUCCESS)
5818 return ERROR_SUCCESS;
5820 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5821 msiobj_release(&view->hdr);
5826 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5828 MSIPACKAGE *package = param;
5832 LPWSTR name = NULL, display_name = NULL;
5834 SC_HANDLE scm = NULL, service = NULL;
5836 event = MSI_RecordGetInteger( rec, 3 );
5837 if (!(event & msidbServiceControlEventDelete))
5838 return ERROR_SUCCESS;
5840 component = MSI_RecordGetString(rec, 6);
5841 comp = get_loaded_component(package, component);
5843 return ERROR_SUCCESS;
5847 TRACE("component is disabled\n");
5848 return ERROR_SUCCESS;
5851 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5853 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5854 comp->Action = comp->Installed;
5855 return ERROR_SUCCESS;
5857 comp->Action = INSTALLSTATE_ABSENT;
5859 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5860 stop_service( name );
5862 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5865 WARN("Failed to open the SCM: %d\n", GetLastError());
5870 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5871 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5873 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5874 GetServiceDisplayNameW( scm, name, display_name, &len );
5877 service = OpenServiceW( scm, name, DELETE );
5880 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5884 if (!DeleteService( service ))
5885 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5888 uirow = MSI_CreateRecord( 2 );
5889 MSI_RecordSetStringW( uirow, 1, display_name );
5890 MSI_RecordSetStringW( uirow, 2, name );
5891 ui_actiondata( package, szDeleteServices, uirow );
5892 msiobj_release( &uirow->hdr );
5894 CloseServiceHandle( service );
5895 CloseServiceHandle( scm );
5897 msi_free( display_name );
5899 return ERROR_SUCCESS;
5902 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5907 static const WCHAR query[] = {
5908 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5909 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5911 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5912 if (rc != ERROR_SUCCESS)
5913 return ERROR_SUCCESS;
5915 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5916 msiobj_release( &view->hdr );
5921 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5923 MSIPACKAGE *package = param;
5924 LPWSTR driver, driver_path, ptr;
5925 WCHAR outpath[MAX_PATH];
5926 MSIFILE *driver_file = NULL, *setup_file = NULL;
5928 LPCWSTR desc, file_key;
5930 UINT r = ERROR_SUCCESS;
5932 static const WCHAR driver_fmt[] = {
5933 'D','r','i','v','e','r','=','%','s',0};
5934 static const WCHAR setup_fmt[] = {
5935 'S','e','t','u','p','=','%','s',0};
5936 static const WCHAR usage_fmt[] = {
5937 'F','i','l','e','U','s','a','g','e','=','1',0};
5939 desc = MSI_RecordGetString(rec, 3);
5941 file_key = MSI_RecordGetString( rec, 4 );
5942 if (file_key) driver_file = get_loaded_file( package, file_key );
5944 file_key = MSI_RecordGetString( rec, 5 );
5945 if (file_key) setup_file = get_loaded_file( package, file_key );
5949 ERR("ODBC Driver entry not found!\n");
5950 return ERROR_FUNCTION_FAILED;
5953 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5955 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5956 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5958 driver = msi_alloc(len * sizeof(WCHAR));
5960 return ERROR_OUTOFMEMORY;
5963 lstrcpyW(ptr, desc);
5964 ptr += lstrlenW(ptr) + 1;
5966 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5971 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5975 lstrcpyW(ptr, usage_fmt);
5976 ptr += lstrlenW(ptr) + 1;
5979 driver_path = strdupW(driver_file->TargetPath);
5980 ptr = strrchrW(driver_path, '\\');
5981 if (ptr) *ptr = '\0';
5983 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5984 NULL, ODBC_INSTALL_COMPLETE, &usage))
5986 ERR("Failed to install SQL driver!\n");
5987 r = ERROR_FUNCTION_FAILED;
5990 uirow = MSI_CreateRecord( 5 );
5991 MSI_RecordSetStringW( uirow, 1, desc );
5992 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5993 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5994 ui_actiondata( package, szInstallODBC, uirow );
5995 msiobj_release( &uirow->hdr );
5998 msi_free(driver_path);
6003 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6005 MSIPACKAGE *package = param;
6006 LPWSTR translator, translator_path, ptr;
6007 WCHAR outpath[MAX_PATH];
6008 MSIFILE *translator_file = NULL, *setup_file = NULL;
6010 LPCWSTR desc, file_key;
6012 UINT r = ERROR_SUCCESS;
6014 static const WCHAR translator_fmt[] = {
6015 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6016 static const WCHAR setup_fmt[] = {
6017 'S','e','t','u','p','=','%','s',0};
6019 desc = MSI_RecordGetString(rec, 3);
6021 file_key = MSI_RecordGetString( rec, 4 );
6022 if (file_key) translator_file = get_loaded_file( package, file_key );
6024 file_key = MSI_RecordGetString( rec, 5 );
6025 if (file_key) setup_file = get_loaded_file( package, file_key );
6027 if (!translator_file)
6029 ERR("ODBC Translator entry not found!\n");
6030 return ERROR_FUNCTION_FAILED;
6033 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6035 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6037 translator = msi_alloc(len * sizeof(WCHAR));
6039 return ERROR_OUTOFMEMORY;
6042 lstrcpyW(ptr, desc);
6043 ptr += lstrlenW(ptr) + 1;
6045 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6050 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6055 translator_path = strdupW(translator_file->TargetPath);
6056 ptr = strrchrW(translator_path, '\\');
6057 if (ptr) *ptr = '\0';
6059 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6060 NULL, ODBC_INSTALL_COMPLETE, &usage))
6062 ERR("Failed to install SQL translator!\n");
6063 r = ERROR_FUNCTION_FAILED;
6066 uirow = MSI_CreateRecord( 5 );
6067 MSI_RecordSetStringW( uirow, 1, desc );
6068 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6069 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6070 ui_actiondata( package, szInstallODBC, uirow );
6071 msiobj_release( &uirow->hdr );
6073 msi_free(translator);
6074 msi_free(translator_path);
6079 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6081 MSIPACKAGE *package = param;
6083 LPCWSTR desc, driver;
6084 WORD request = ODBC_ADD_SYS_DSN;
6087 UINT r = ERROR_SUCCESS;
6090 static const WCHAR attrs_fmt[] = {
6091 'D','S','N','=','%','s',0 };
6093 desc = MSI_RecordGetString(rec, 3);
6094 driver = MSI_RecordGetString(rec, 4);
6095 registration = MSI_RecordGetInteger(rec, 5);
6097 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6098 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6100 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6101 attrs = msi_alloc(len * sizeof(WCHAR));
6103 return ERROR_OUTOFMEMORY;
6105 len = sprintfW(attrs, attrs_fmt, desc);
6108 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6110 ERR("Failed to install SQL data source!\n");
6111 r = ERROR_FUNCTION_FAILED;
6114 uirow = MSI_CreateRecord( 5 );
6115 MSI_RecordSetStringW( uirow, 1, desc );
6116 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6117 MSI_RecordSetInteger( uirow, 3, request );
6118 ui_actiondata( package, szInstallODBC, uirow );
6119 msiobj_release( &uirow->hdr );
6126 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6131 static const WCHAR driver_query[] = {
6132 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6133 'O','D','B','C','D','r','i','v','e','r',0 };
6135 static const WCHAR translator_query[] = {
6136 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6137 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6139 static const WCHAR source_query[] = {
6140 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6141 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6143 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6144 if (rc != ERROR_SUCCESS)
6145 return ERROR_SUCCESS;
6147 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6148 msiobj_release(&view->hdr);
6150 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6151 if (rc != ERROR_SUCCESS)
6152 return ERROR_SUCCESS;
6154 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6155 msiobj_release(&view->hdr);
6157 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6158 if (rc != ERROR_SUCCESS)
6159 return ERROR_SUCCESS;
6161 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6162 msiobj_release(&view->hdr);
6167 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6169 MSIPACKAGE *package = param;
6174 desc = MSI_RecordGetString( rec, 3 );
6175 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6177 WARN("Failed to remove ODBC driver\n");
6181 FIXME("Usage count reached 0\n");
6184 uirow = MSI_CreateRecord( 2 );
6185 MSI_RecordSetStringW( uirow, 1, desc );
6186 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6187 ui_actiondata( package, szRemoveODBC, uirow );
6188 msiobj_release( &uirow->hdr );
6190 return ERROR_SUCCESS;
6193 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6195 MSIPACKAGE *package = param;
6200 desc = MSI_RecordGetString( rec, 3 );
6201 if (!SQLRemoveTranslatorW( desc, &usage ))
6203 WARN("Failed to remove ODBC translator\n");
6207 FIXME("Usage count reached 0\n");
6210 uirow = MSI_CreateRecord( 2 );
6211 MSI_RecordSetStringW( uirow, 1, desc );
6212 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6213 ui_actiondata( package, szRemoveODBC, uirow );
6214 msiobj_release( &uirow->hdr );
6216 return ERROR_SUCCESS;
6219 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6221 MSIPACKAGE *package = param;
6224 LPCWSTR desc, driver;
6225 WORD request = ODBC_REMOVE_SYS_DSN;
6229 static const WCHAR attrs_fmt[] = {
6230 'D','S','N','=','%','s',0 };
6232 desc = MSI_RecordGetString( rec, 3 );
6233 driver = MSI_RecordGetString( rec, 4 );
6234 registration = MSI_RecordGetInteger( rec, 5 );
6236 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6237 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6239 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6240 attrs = msi_alloc( len * sizeof(WCHAR) );
6242 return ERROR_OUTOFMEMORY;
6244 FIXME("Use ODBCSourceAttribute table\n");
6246 len = sprintfW( attrs, attrs_fmt, desc );
6249 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6251 WARN("Failed to remove ODBC data source\n");
6255 uirow = MSI_CreateRecord( 3 );
6256 MSI_RecordSetStringW( uirow, 1, desc );
6257 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6258 MSI_RecordSetInteger( uirow, 3, request );
6259 ui_actiondata( package, szRemoveODBC, uirow );
6260 msiobj_release( &uirow->hdr );
6262 return ERROR_SUCCESS;
6265 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6270 static const WCHAR driver_query[] = {
6271 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6272 'O','D','B','C','D','r','i','v','e','r',0 };
6274 static const WCHAR translator_query[] = {
6275 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6276 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6278 static const WCHAR source_query[] = {
6279 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6280 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6282 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6283 if (rc != ERROR_SUCCESS)
6284 return ERROR_SUCCESS;
6286 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6287 msiobj_release( &view->hdr );
6289 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6290 if (rc != ERROR_SUCCESS)
6291 return ERROR_SUCCESS;
6293 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6294 msiobj_release( &view->hdr );
6296 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6297 if (rc != ERROR_SUCCESS)
6298 return ERROR_SUCCESS;
6300 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6301 msiobj_release( &view->hdr );
6306 #define ENV_ACT_SETALWAYS 0x1
6307 #define ENV_ACT_SETABSENT 0x2
6308 #define ENV_ACT_REMOVE 0x4
6309 #define ENV_ACT_REMOVEMATCH 0x8
6311 #define ENV_MOD_MACHINE 0x20000000
6312 #define ENV_MOD_APPEND 0x40000000
6313 #define ENV_MOD_PREFIX 0x80000000
6314 #define ENV_MOD_MASK 0xC0000000
6316 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6318 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6320 LPCWSTR cptr = *name;
6322 static const WCHAR prefix[] = {'[','~',']',0};
6323 static const int prefix_len = 3;
6329 *flags |= ENV_ACT_SETALWAYS;
6330 else if (*cptr == '+')
6331 *flags |= ENV_ACT_SETABSENT;
6332 else if (*cptr == '-')
6333 *flags |= ENV_ACT_REMOVE;
6334 else if (*cptr == '!')
6335 *flags |= ENV_ACT_REMOVEMATCH;
6336 else if (*cptr == '*')
6337 *flags |= ENV_MOD_MACHINE;
6347 ERR("Missing environment variable\n");
6348 return ERROR_FUNCTION_FAILED;
6353 LPCWSTR ptr = *value;
6354 if (!strncmpW(ptr, prefix, prefix_len))
6356 if (ptr[prefix_len] == szSemiColon[0])
6358 *flags |= ENV_MOD_APPEND;
6359 *value += lstrlenW(prefix);
6366 else if (lstrlenW(*value) >= prefix_len)
6368 ptr += lstrlenW(ptr) - prefix_len;
6369 if (!strcmpW( ptr, prefix ))
6371 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6373 *flags |= ENV_MOD_PREFIX;
6374 /* the "[~]" will be removed by deformat_string */;
6384 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6385 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6386 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6387 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6389 ERR("Invalid flags: %08x\n", *flags);
6390 return ERROR_FUNCTION_FAILED;
6394 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6396 return ERROR_SUCCESS;
6399 static UINT open_env_key( DWORD flags, HKEY *key )
6401 static const WCHAR user_env[] =
6402 {'E','n','v','i','r','o','n','m','e','n','t',0};
6403 static const WCHAR machine_env[] =
6404 {'S','y','s','t','e','m','\\',
6405 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6406 'C','o','n','t','r','o','l','\\',
6407 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6408 'E','n','v','i','r','o','n','m','e','n','t',0};
6413 if (flags & ENV_MOD_MACHINE)
6416 root = HKEY_LOCAL_MACHINE;
6421 root = HKEY_CURRENT_USER;
6424 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6425 if (res != ERROR_SUCCESS)
6427 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6428 return ERROR_FUNCTION_FAILED;
6431 return ERROR_SUCCESS;
6434 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6436 MSIPACKAGE *package = param;
6437 LPCWSTR name, value, component;
6438 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6439 DWORD flags, type, size;
6446 component = MSI_RecordGetString(rec, 4);
6447 comp = get_loaded_component(package, component);
6449 return ERROR_SUCCESS;
6453 TRACE("component is disabled\n");
6454 return ERROR_SUCCESS;
6457 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6459 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6460 comp->Action = comp->Installed;
6461 return ERROR_SUCCESS;
6463 comp->Action = INSTALLSTATE_LOCAL;
6465 name = MSI_RecordGetString(rec, 2);
6466 value = MSI_RecordGetString(rec, 3);
6468 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6470 res = env_parse_flags(&name, &value, &flags);
6471 if (res != ERROR_SUCCESS || !value)
6474 if (value && !deformat_string(package, value, &deformatted))
6476 res = ERROR_OUTOFMEMORY;
6480 value = deformatted;
6482 res = open_env_key( flags, &env );
6483 if (res != ERROR_SUCCESS)
6486 if (flags & ENV_MOD_MACHINE)
6487 action |= 0x20000000;
6491 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6492 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6493 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6496 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6500 /* Nothing to do. */
6503 res = ERROR_SUCCESS;
6507 /* If we are appending but the string was empty, strip ; */
6508 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6510 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6511 newval = strdupW(value);
6514 res = ERROR_OUTOFMEMORY;
6522 /* Contrary to MSDN, +-variable to [~];path works */
6523 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6525 res = ERROR_SUCCESS;
6529 data = msi_alloc(size);
6533 return ERROR_OUTOFMEMORY;
6536 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6537 if (res != ERROR_SUCCESS)
6540 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6543 res = RegDeleteValueW(env, name);
6544 if (res != ERROR_SUCCESS)
6545 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6549 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6550 if (flags & ENV_MOD_MASK)
6554 if (flags & ENV_MOD_APPEND) multiplier++;
6555 if (flags & ENV_MOD_PREFIX) multiplier++;
6556 mod_size = lstrlenW(value) * multiplier;
6557 size += mod_size * sizeof(WCHAR);
6560 newval = msi_alloc(size);
6564 res = ERROR_OUTOFMEMORY;
6568 if (flags & ENV_MOD_PREFIX)
6570 lstrcpyW(newval, value);
6571 ptr = newval + lstrlenW(value);
6572 action |= 0x80000000;
6575 lstrcpyW(ptr, data);
6577 if (flags & ENV_MOD_APPEND)
6579 lstrcatW(newval, value);
6580 action |= 0x40000000;
6583 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6584 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6587 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6591 uirow = MSI_CreateRecord( 3 );
6592 MSI_RecordSetStringW( uirow, 1, name );
6593 MSI_RecordSetStringW( uirow, 2, newval );
6594 MSI_RecordSetInteger( uirow, 3, action );
6595 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6596 msiobj_release( &uirow->hdr );
6598 if (env) RegCloseKey(env);
6599 msi_free(deformatted);
6605 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6609 static const WCHAR ExecSeqQuery[] =
6610 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6611 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6612 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6613 if (rc != ERROR_SUCCESS)
6614 return ERROR_SUCCESS;
6616 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6617 msiobj_release(&view->hdr);
6622 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6624 MSIPACKAGE *package = param;
6625 LPCWSTR name, value, component;
6626 LPWSTR deformatted = NULL;
6635 component = MSI_RecordGetString( rec, 4 );
6636 comp = get_loaded_component( package, component );
6638 return ERROR_SUCCESS;
6642 TRACE("component is disabled\n");
6643 return ERROR_SUCCESS;
6646 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6648 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6649 comp->Action = comp->Installed;
6650 return ERROR_SUCCESS;
6652 comp->Action = INSTALLSTATE_ABSENT;
6654 name = MSI_RecordGetString( rec, 2 );
6655 value = MSI_RecordGetString( rec, 3 );
6657 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6659 r = env_parse_flags( &name, &value, &flags );
6660 if (r != ERROR_SUCCESS)
6663 if (!(flags & ENV_ACT_REMOVE))
6665 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6666 return ERROR_SUCCESS;
6669 if (value && !deformat_string( package, value, &deformatted ))
6670 return ERROR_OUTOFMEMORY;
6672 value = deformatted;
6674 r = open_env_key( flags, &env );
6675 if (r != ERROR_SUCCESS)
6681 if (flags & ENV_MOD_MACHINE)
6682 action |= 0x20000000;
6684 TRACE("Removing %s\n", debugstr_w(name));
6686 res = RegDeleteValueW( env, name );
6687 if (res != ERROR_SUCCESS)
6689 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6694 uirow = MSI_CreateRecord( 3 );
6695 MSI_RecordSetStringW( uirow, 1, name );
6696 MSI_RecordSetStringW( uirow, 2, value );
6697 MSI_RecordSetInteger( uirow, 3, action );
6698 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6699 msiobj_release( &uirow->hdr );
6701 if (env) RegCloseKey( env );
6702 msi_free( deformatted );
6706 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6710 static const WCHAR query[] =
6711 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6712 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6714 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6715 if (rc != ERROR_SUCCESS)
6716 return ERROR_SUCCESS;
6718 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6719 msiobj_release( &view->hdr );
6724 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6726 LPWSTR key, template, id;
6727 UINT r = ERROR_SUCCESS;
6729 id = msi_dup_property( package->db, szProductID );
6733 return ERROR_SUCCESS;
6735 template = msi_dup_property( package->db, szPIDTemplate );
6736 key = msi_dup_property( package->db, szPIDKEY );
6738 if (key && template)
6740 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6741 r = msi_set_property( package->db, szProductID, key );
6743 msi_free( template );
6748 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6751 package->need_reboot = 1;
6752 return ERROR_SUCCESS;
6755 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6757 static const WCHAR szAvailableFreeReg[] =
6758 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6760 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6762 TRACE("%p %d kilobytes\n", package, space);
6764 uirow = MSI_CreateRecord( 1 );
6765 MSI_RecordSetInteger( uirow, 1, space );
6766 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6767 msiobj_release( &uirow->hdr );
6769 return ERROR_SUCCESS;
6772 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6774 FIXME("%p\n", package);
6775 return ERROR_SUCCESS;
6778 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6780 FIXME("%p\n", package);
6781 return ERROR_SUCCESS;
6784 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6789 static const WCHAR driver_query[] = {
6790 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6791 'O','D','B','C','D','r','i','v','e','r',0 };
6793 static const WCHAR translator_query[] = {
6794 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6795 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6797 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6798 if (r == ERROR_SUCCESS)
6801 r = MSI_IterateRecords( view, &count, NULL, package );
6802 msiobj_release( &view->hdr );
6803 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6806 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6807 if (r == ERROR_SUCCESS)
6810 r = MSI_IterateRecords( view, &count, NULL, package );
6811 msiobj_release( &view->hdr );
6812 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6815 return ERROR_SUCCESS;
6818 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6819 LPCSTR action, LPCWSTR table )
6821 static const WCHAR query[] = {
6822 'S','E','L','E','C','T',' ','*',' ',
6823 'F','R','O','M',' ','`','%','s','`',0 };
6824 MSIQUERY *view = NULL;
6828 r = MSI_OpenQuery( package->db, &view, query, table );
6829 if (r == ERROR_SUCCESS)
6831 r = MSI_IterateRecords(view, &count, NULL, package);
6832 msiobj_release(&view->hdr);
6836 FIXME("%s -> %u ignored %s table values\n",
6837 action, count, debugstr_w(table));
6839 return ERROR_SUCCESS;
6842 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6844 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6845 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6848 static UINT ACTION_BindImage( MSIPACKAGE *package )
6850 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6851 return msi_unimplemented_action_stub( package, "BindImage", table );
6854 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6856 static const WCHAR table[] = {
6857 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6858 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6861 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6863 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6864 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6867 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6869 static const WCHAR table[] = {
6870 'M','s','i','A','s','s','e','m','b','l','y',0 };
6871 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6874 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6876 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6877 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6880 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6882 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6883 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6886 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6888 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6889 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6892 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6894 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6895 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6898 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6900 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6901 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6904 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6908 const WCHAR *action;
6909 UINT (*handler)(MSIPACKAGE *);
6913 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6914 { szAppSearch, ACTION_AppSearch },
6915 { szBindImage, ACTION_BindImage },
6916 { szCCPSearch, ACTION_CCPSearch },
6917 { szCostFinalize, ACTION_CostFinalize },
6918 { szCostInitialize, ACTION_CostInitialize },
6919 { szCreateFolders, ACTION_CreateFolders },
6920 { szCreateShortcuts, ACTION_CreateShortcuts },
6921 { szDeleteServices, ACTION_DeleteServices },
6922 { szDisableRollback, ACTION_DisableRollback },
6923 { szDuplicateFiles, ACTION_DuplicateFiles },
6924 { szExecuteAction, ACTION_ExecuteAction },
6925 { szFileCost, ACTION_FileCost },
6926 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6927 { szForceReboot, ACTION_ForceReboot },
6928 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6929 { szInstallExecute, ACTION_InstallExecute },
6930 { szInstallExecuteAgain, ACTION_InstallExecute },
6931 { szInstallFiles, ACTION_InstallFiles},
6932 { szInstallFinalize, ACTION_InstallFinalize },
6933 { szInstallInitialize, ACTION_InstallInitialize },
6934 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6935 { szInstallValidate, ACTION_InstallValidate },
6936 { szIsolateComponents, ACTION_IsolateComponents },
6937 { szLaunchConditions, ACTION_LaunchConditions },
6938 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6939 { szMoveFiles, ACTION_MoveFiles },
6940 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6941 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6942 { szInstallODBC, ACTION_InstallODBC },
6943 { szInstallServices, ACTION_InstallServices },
6944 { szPatchFiles, ACTION_PatchFiles },
6945 { szProcessComponents, ACTION_ProcessComponents },
6946 { szPublishComponents, ACTION_PublishComponents },
6947 { szPublishFeatures, ACTION_PublishFeatures },
6948 { szPublishProduct, ACTION_PublishProduct },
6949 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6950 { szRegisterComPlus, ACTION_RegisterComPlus},
6951 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6952 { szRegisterFonts, ACTION_RegisterFonts },
6953 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6954 { szRegisterProduct, ACTION_RegisterProduct },
6955 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6956 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6957 { szRegisterUser, ACTION_RegisterUser },
6958 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6959 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6960 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6961 { szRemoveFiles, ACTION_RemoveFiles },
6962 { szRemoveFolders, ACTION_RemoveFolders },
6963 { szRemoveIniValues, ACTION_RemoveIniValues },
6964 { szRemoveODBC, ACTION_RemoveODBC },
6965 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6966 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6967 { szResolveSource, ACTION_ResolveSource },
6968 { szRMCCPSearch, ACTION_RMCCPSearch },
6969 { szScheduleReboot, ACTION_ScheduleReboot },
6970 { szSelfRegModules, ACTION_SelfRegModules },
6971 { szSelfUnregModules, ACTION_SelfUnregModules },
6972 { szSetODBCFolders, ACTION_SetODBCFolders },
6973 { szStartServices, ACTION_StartServices },
6974 { szStopServices, ACTION_StopServices },
6975 { szUnpublishComponents, ACTION_UnpublishComponents },
6976 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6977 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6978 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6979 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6980 { szUnregisterFonts, ACTION_UnregisterFonts },
6981 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6982 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6983 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6984 { szValidateProductID, ACTION_ValidateProductID },
6985 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6986 { szWriteIniValues, ACTION_WriteIniValues },
6987 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6991 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
6997 while (StandardActions[i].action != NULL)
6999 if (!strcmpW( StandardActions[i].action, action ))
7001 ui_actionstart( package, action );
7002 if (StandardActions[i].handler)
7004 ui_actioninfo( package, action, TRUE, 0 );
7005 *rc = StandardActions[i].handler( package );
7006 ui_actioninfo( package, action, FALSE, *rc );
7010 FIXME("unhandled standard action %s\n", debugstr_w(action));
7011 *rc = ERROR_SUCCESS;
7021 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7023 UINT rc = ERROR_SUCCESS;
7026 TRACE("Performing action (%s)\n", debugstr_w(action));
7028 handled = ACTION_HandleStandardAction(package, action, &rc);
7031 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7035 WARN("unhandled msi action %s\n", debugstr_w(action));
7036 rc = ERROR_FUNCTION_NOT_CALLED;
7042 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7044 UINT rc = ERROR_SUCCESS;
7045 BOOL handled = FALSE;
7047 TRACE("Performing action (%s)\n", debugstr_w(action));
7049 handled = ACTION_HandleStandardAction(package, action, &rc);
7052 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7054 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7059 WARN("unhandled msi action %s\n", debugstr_w(action));
7060 rc = ERROR_FUNCTION_NOT_CALLED;
7066 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7068 UINT rc = ERROR_SUCCESS;
7071 static const WCHAR ExecSeqQuery[] =
7072 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7073 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7074 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7075 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7076 static const WCHAR UISeqQuery[] =
7077 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7078 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7079 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7080 ' ', '=',' ','%','i',0};
7082 if (needs_ui_sequence(package))
7083 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7085 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7089 LPCWSTR action, cond;
7091 TRACE("Running the actions\n");
7093 /* check conditions */
7094 cond = MSI_RecordGetString(row, 2);
7096 /* this is a hack to skip errors in the condition code */
7097 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7099 msiobj_release(&row->hdr);
7100 return ERROR_SUCCESS;
7103 action = MSI_RecordGetString(row, 1);
7106 ERR("failed to fetch action\n");
7107 msiobj_release(&row->hdr);
7108 return ERROR_FUNCTION_FAILED;
7111 if (needs_ui_sequence(package))
7112 rc = ACTION_PerformUIAction(package, action, -1);
7114 rc = ACTION_PerformAction(package, action, -1);
7116 msiobj_release(&row->hdr);
7122 /****************************************************
7123 * TOP level entry points
7124 *****************************************************/
7126 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7127 LPCWSTR szCommandLine )
7132 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7133 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7135 msi_set_property( package->db, szAction, szInstall );
7137 package->script->InWhatSequence = SEQUENCE_INSTALL;
7144 dir = strdupW(szPackagePath);
7145 p = strrchrW(dir, '\\');
7149 file = szPackagePath + (p - dir);
7154 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7155 GetCurrentDirectoryW(MAX_PATH, dir);
7156 lstrcatW(dir, szBackSlash);
7157 file = szPackagePath;
7160 msi_free( package->PackagePath );
7161 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7162 if (!package->PackagePath)
7165 return ERROR_OUTOFMEMORY;
7168 lstrcpyW(package->PackagePath, dir);
7169 lstrcatW(package->PackagePath, file);
7172 msi_set_sourcedir_props(package, FALSE);
7175 msi_parse_command_line( package, szCommandLine, FALSE );
7177 msi_apply_transforms( package );
7178 msi_apply_patches( package );
7180 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7182 TRACE("setting reinstall property\n");
7183 msi_set_property( package->db, szReinstall, szAll );
7186 /* properties may have been added by a transform */
7187 msi_clone_properties( package );
7189 msi_parse_command_line( package, szCommandLine, FALSE );
7190 msi_adjust_privilege_properties( package );
7191 msi_set_context( package );
7193 if (needs_ui_sequence( package))
7195 package->script->InWhatSequence |= SEQUENCE_UI;
7196 rc = ACTION_ProcessUISequence(package);
7197 ui_exists = ui_sequence_exists(package);
7198 if (rc == ERROR_SUCCESS || !ui_exists)
7200 package->script->InWhatSequence |= SEQUENCE_EXEC;
7201 rc = ACTION_ProcessExecSequence(package, ui_exists);
7205 rc = ACTION_ProcessExecSequence(package, FALSE);
7207 package->script->CurrentlyScripting = FALSE;
7209 /* process the ending type action */
7210 if (rc == ERROR_SUCCESS)
7211 ACTION_PerformActionSequence(package, -1);
7212 else if (rc == ERROR_INSTALL_USEREXIT)
7213 ACTION_PerformActionSequence(package, -2);
7214 else if (rc == ERROR_INSTALL_SUSPEND)
7215 ACTION_PerformActionSequence(package, -4);
7217 ACTION_PerformActionSequence(package, -3);
7219 /* finish up running custom actions */
7220 ACTION_FinishCustomActions(package);
7222 if (rc == ERROR_SUCCESS && package->need_reboot)
7223 return ERROR_SUCCESS_REBOOT_REQUIRED;