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 ExecSeqQuery[] =
1106 {'S','E','L','E','C','T',' ',
1107 '`','D','i','r','e','c','t','o','r','y','_','`',
1108 ' ','F','R','O','M',' ',
1109 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1113 /* create all the empty folders specified in the CreateFolder table */
1114 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1115 if (rc != ERROR_SUCCESS)
1116 return ERROR_SUCCESS;
1118 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1119 msiobj_release(&view->hdr);
1124 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1126 MSIPACKAGE *package = param;
1127 LPCWSTR dir, component;
1133 component = MSI_RecordGetString(row, 2);
1135 return ERROR_SUCCESS;
1137 comp = get_loaded_component(package, component);
1139 return ERROR_SUCCESS;
1143 TRACE("component is disabled\n");
1144 return ERROR_SUCCESS;
1147 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1149 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1150 comp->Action = comp->Installed;
1151 return ERROR_SUCCESS;
1153 comp->Action = INSTALLSTATE_ABSENT;
1155 dir = MSI_RecordGetString( row, 1 );
1158 ERR("Unable to get folder id\n");
1159 return ERROR_SUCCESS;
1162 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1165 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1166 return ERROR_SUCCESS;
1169 TRACE("folder is %s\n", debugstr_w(full_path));
1171 uirow = MSI_CreateRecord( 1 );
1172 MSI_RecordSetStringW( uirow, 1, dir );
1173 ui_actiondata( package, szRemoveFolders, uirow );
1174 msiobj_release( &uirow->hdr );
1176 RemoveDirectoryW( full_path );
1179 msi_free( full_path );
1180 return ERROR_SUCCESS;
1183 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1185 static const WCHAR query[] =
1186 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1187 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1192 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1193 if (rc != ERROR_SUCCESS)
1194 return ERROR_SUCCESS;
1196 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1197 msiobj_release( &view->hdr );
1202 static UINT load_component( MSIRECORD *row, LPVOID param )
1204 MSIPACKAGE *package = param;
1207 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1209 return ERROR_FUNCTION_FAILED;
1211 list_add_tail( &package->components, &comp->entry );
1213 /* fill in the data */
1214 comp->Component = msi_dup_record_field( row, 1 );
1216 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1218 comp->ComponentId = msi_dup_record_field( row, 2 );
1219 comp->Directory = msi_dup_record_field( row, 3 );
1220 comp->Attributes = MSI_RecordGetInteger(row,4);
1221 comp->Condition = msi_dup_record_field( row, 5 );
1222 comp->KeyPath = msi_dup_record_field( row, 6 );
1224 comp->Installed = INSTALLSTATE_UNKNOWN;
1225 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1227 comp->assembly = load_assembly( package, comp );
1228 return ERROR_SUCCESS;
1231 static UINT load_all_components( MSIPACKAGE *package )
1233 static const WCHAR query[] = {
1234 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1235 '`','C','o','m','p','o','n','e','n','t','`',0 };
1239 if (!list_empty(&package->components))
1240 return ERROR_SUCCESS;
1242 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1243 if (r != ERROR_SUCCESS)
1246 r = MSI_IterateRecords(view, NULL, load_component, package);
1247 msiobj_release(&view->hdr);
1252 MSIPACKAGE *package;
1253 MSIFEATURE *feature;
1256 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1260 cl = msi_alloc( sizeof (*cl) );
1262 return ERROR_NOT_ENOUGH_MEMORY;
1263 cl->component = comp;
1264 list_add_tail( &feature->Components, &cl->entry );
1266 return ERROR_SUCCESS;
1269 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1273 fl = msi_alloc( sizeof(*fl) );
1275 return ERROR_NOT_ENOUGH_MEMORY;
1276 fl->feature = child;
1277 list_add_tail( &parent->Children, &fl->entry );
1279 return ERROR_SUCCESS;
1282 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1284 _ilfs* ilfs = param;
1288 component = MSI_RecordGetString(row,1);
1290 /* check to see if the component is already loaded */
1291 comp = get_loaded_component( ilfs->package, component );
1294 ERR("unknown component %s\n", debugstr_w(component));
1295 return ERROR_FUNCTION_FAILED;
1298 add_feature_component( ilfs->feature, comp );
1299 comp->Enabled = TRUE;
1301 return ERROR_SUCCESS;
1304 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1306 MSIFEATURE *feature;
1311 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1313 if ( !strcmpW( feature->Feature, name ) )
1320 static UINT load_feature(MSIRECORD * row, LPVOID param)
1322 MSIPACKAGE* package = param;
1323 MSIFEATURE* feature;
1324 static const WCHAR Query1[] =
1325 {'S','E','L','E','C','T',' ',
1326 '`','C','o','m','p','o','n','e','n','t','_','`',
1327 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1328 'C','o','m','p','o','n','e','n','t','s','`',' ',
1329 'W','H','E','R','E',' ',
1330 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1335 /* fill in the data */
1337 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1339 return ERROR_NOT_ENOUGH_MEMORY;
1341 list_init( &feature->Children );
1342 list_init( &feature->Components );
1344 feature->Feature = msi_dup_record_field( row, 1 );
1346 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1348 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1349 feature->Title = msi_dup_record_field( row, 3 );
1350 feature->Description = msi_dup_record_field( row, 4 );
1352 if (!MSI_RecordIsNull(row,5))
1353 feature->Display = MSI_RecordGetInteger(row,5);
1355 feature->Level= MSI_RecordGetInteger(row,6);
1356 feature->Directory = msi_dup_record_field( row, 7 );
1357 feature->Attributes = MSI_RecordGetInteger(row,8);
1359 feature->Installed = INSTALLSTATE_UNKNOWN;
1360 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1362 list_add_tail( &package->features, &feature->entry );
1364 /* load feature components */
1366 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1367 if (rc != ERROR_SUCCESS)
1368 return ERROR_SUCCESS;
1370 ilfs.package = package;
1371 ilfs.feature = feature;
1373 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1374 msiobj_release(&view->hdr);
1376 return ERROR_SUCCESS;
1379 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1381 MSIPACKAGE* package = param;
1382 MSIFEATURE *parent, *child;
1384 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1386 return ERROR_FUNCTION_FAILED;
1388 if (!child->Feature_Parent)
1389 return ERROR_SUCCESS;
1391 parent = find_feature_by_name( package, child->Feature_Parent );
1393 return ERROR_FUNCTION_FAILED;
1395 add_feature_child( parent, child );
1396 return ERROR_SUCCESS;
1399 static UINT load_all_features( MSIPACKAGE *package )
1401 static const WCHAR query[] = {
1402 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1403 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1404 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1408 if (!list_empty(&package->features))
1409 return ERROR_SUCCESS;
1411 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1412 if (r != ERROR_SUCCESS)
1415 r = MSI_IterateRecords( view, NULL, load_feature, package );
1416 if (r != ERROR_SUCCESS)
1419 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1420 msiobj_release( &view->hdr );
1425 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1436 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1438 static const WCHAR query[] = {
1439 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1440 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1441 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1442 MSIQUERY *view = NULL;
1443 MSIRECORD *row = NULL;
1446 TRACE("%s\n", debugstr_w(file->File));
1448 r = MSI_OpenQuery(package->db, &view, query, file->File);
1449 if (r != ERROR_SUCCESS)
1452 r = MSI_ViewExecute(view, NULL);
1453 if (r != ERROR_SUCCESS)
1456 r = MSI_ViewFetch(view, &row);
1457 if (r != ERROR_SUCCESS)
1460 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1461 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1462 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1463 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1464 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1467 if (view) msiobj_release(&view->hdr);
1468 if (row) msiobj_release(&row->hdr);
1472 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1475 static const WCHAR query[] = {
1476 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1477 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1478 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1480 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1483 WARN("query failed\n");
1484 return ERROR_FUNCTION_FAILED;
1487 file->disk_id = MSI_RecordGetInteger( row, 1 );
1488 msiobj_release( &row->hdr );
1489 return ERROR_SUCCESS;
1492 static UINT load_file(MSIRECORD *row, LPVOID param)
1494 MSIPACKAGE* package = param;
1498 /* fill in the data */
1500 file = msi_alloc_zero( sizeof (MSIFILE) );
1502 return ERROR_NOT_ENOUGH_MEMORY;
1504 file->File = msi_dup_record_field( row, 1 );
1506 component = MSI_RecordGetString( row, 2 );
1507 file->Component = get_loaded_component( package, component );
1509 if (!file->Component)
1511 WARN("Component not found: %s\n", debugstr_w(component));
1512 msi_free(file->File);
1514 return ERROR_SUCCESS;
1517 file->FileName = msi_dup_record_field( row, 3 );
1518 reduce_to_longfilename( file->FileName );
1520 file->ShortName = msi_dup_record_field( row, 3 );
1521 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1523 file->FileSize = MSI_RecordGetInteger( row, 4 );
1524 file->Version = msi_dup_record_field( row, 5 );
1525 file->Language = msi_dup_record_field( row, 6 );
1526 file->Attributes = MSI_RecordGetInteger( row, 7 );
1527 file->Sequence = MSI_RecordGetInteger( row, 8 );
1529 file->state = msifs_invalid;
1531 /* if the compressed bits are not set in the file attributes,
1532 * then read the information from the package word count property
1534 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1536 file->IsCompressed = FALSE;
1538 else if (file->Attributes &
1539 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1541 file->IsCompressed = TRUE;
1543 else if (file->Attributes & msidbFileAttributesNoncompressed)
1545 file->IsCompressed = FALSE;
1549 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1552 load_file_hash(package, file);
1553 load_file_disk_id(package, file);
1555 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1557 list_add_tail( &package->files, &file->entry );
1559 return ERROR_SUCCESS;
1562 static UINT load_all_files(MSIPACKAGE *package)
1566 static const WCHAR Query[] =
1567 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1568 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1569 '`','S','e','q','u','e','n','c','e','`', 0};
1571 if (!list_empty(&package->files))
1572 return ERROR_SUCCESS;
1574 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1575 if (rc != ERROR_SUCCESS)
1576 return ERROR_SUCCESS;
1578 rc = MSI_IterateRecords(view, NULL, load_file, package);
1579 msiobj_release(&view->hdr);
1581 return ERROR_SUCCESS;
1584 static UINT load_folder( MSIRECORD *row, LPVOID param )
1586 MSIPACKAGE *package = param;
1587 static WCHAR szEmpty[] = { 0 };
1588 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1591 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1593 return ERROR_NOT_ENOUGH_MEMORY;
1595 folder->Directory = msi_dup_record_field( row, 1 );
1597 TRACE("%s\n", debugstr_w(folder->Directory));
1599 p = msi_dup_record_field(row, 3);
1601 /* split src and target dir */
1603 src_short = folder_split_path( p, ':' );
1605 /* split the long and short paths */
1606 tgt_long = folder_split_path( tgt_short, '|' );
1607 src_long = folder_split_path( src_short, '|' );
1609 /* check for no-op dirs */
1610 if (tgt_short && !strcmpW( szDot, tgt_short ))
1611 tgt_short = szEmpty;
1612 if (src_short && !strcmpW( szDot, src_short ))
1613 src_short = szEmpty;
1616 tgt_long = tgt_short;
1619 src_short = tgt_short;
1620 src_long = tgt_long;
1624 src_long = src_short;
1626 /* FIXME: use the target short path too */
1627 folder->TargetDefault = strdupW(tgt_long);
1628 folder->SourceShortPath = strdupW(src_short);
1629 folder->SourceLongPath = strdupW(src_long);
1632 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1633 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1634 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1636 folder->Parent = msi_dup_record_field( row, 2 );
1638 folder->Property = msi_dup_property( package->db, folder->Directory );
1640 list_add_tail( &package->folders, &folder->entry );
1642 TRACE("returning %p\n", folder);
1644 return ERROR_SUCCESS;
1647 static UINT load_all_folders( MSIPACKAGE *package )
1649 static const WCHAR query[] = {
1650 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1651 '`','D','i','r','e','c','t','o','r','y','`',0 };
1655 if (!list_empty(&package->folders))
1656 return ERROR_SUCCESS;
1658 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1659 if (r != ERROR_SUCCESS)
1662 r = MSI_IterateRecords(view, NULL, load_folder, package);
1663 msiobj_release(&view->hdr);
1668 * I am not doing any of the costing functionality yet.
1669 * Mostly looking at doing the Component and Feature loading
1671 * The native MSI does A LOT of modification to tables here. Mostly adding
1672 * a lot of temporary columns to the Feature and Component tables.
1674 * note: Native msi also tracks the short filename. But I am only going to
1675 * track the long ones. Also looking at this directory table
1676 * it appears that the directory table does not get the parents
1677 * resolved base on property only based on their entries in the
1680 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1682 static const WCHAR szCosting[] =
1683 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1685 msi_set_property( package->db, szCosting, szZero );
1686 msi_set_property( package->db, cszRootDrive, c_colon );
1688 load_all_folders( package );
1689 load_all_components( package );
1690 load_all_features( package );
1691 load_all_files( package );
1693 return ERROR_SUCCESS;
1696 static UINT execute_script(MSIPACKAGE *package, UINT script )
1699 UINT rc = ERROR_SUCCESS;
1701 TRACE("Executing Script %i\n",script);
1703 if (!package->script)
1705 ERR("no script!\n");
1706 return ERROR_FUNCTION_FAILED;
1709 for (i = 0; i < package->script->ActionCount[script]; i++)
1712 action = package->script->Actions[script][i];
1713 ui_actionstart(package, action);
1714 TRACE("Executing Action (%s)\n",debugstr_w(action));
1715 rc = ACTION_PerformAction(package, action, script);
1716 if (rc != ERROR_SUCCESS)
1719 msi_free_action_script(package, script);
1723 static UINT ACTION_FileCost(MSIPACKAGE *package)
1725 return ERROR_SUCCESS;
1728 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1734 state = MsiQueryProductStateW(package->ProductCode);
1736 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1738 if (!comp->ComponentId)
1741 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1742 comp->Installed = INSTALLSTATE_ABSENT;
1745 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1746 package->Context, comp->ComponentId,
1748 if (r != ERROR_SUCCESS)
1749 comp->Installed = INSTALLSTATE_ABSENT;
1754 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1756 MSIFEATURE *feature;
1759 state = MsiQueryProductStateW(package->ProductCode);
1761 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1763 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1764 feature->Installed = INSTALLSTATE_ABSENT;
1767 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1773 static BOOL process_state_property(MSIPACKAGE* package, int level,
1774 LPCWSTR property, INSTALLSTATE state)
1777 MSIFEATURE *feature;
1779 override = msi_dup_property( package->db, property );
1783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1785 if (strcmpW( property, szRemove ) &&
1786 (feature->Level <= 0 || feature->Level > level))
1789 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1791 if (!strcmpiW( override, szAll ))
1792 msi_feature_set_state(package, feature, state);
1795 LPWSTR ptr = override;
1796 LPWSTR ptr2 = strchrW(override,',');
1800 int len = ptr2 - ptr;
1802 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1803 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1805 msi_feature_set_state(package, feature, state);
1811 ptr2 = strchrW(ptr,',');
1823 static BOOL process_overrides( MSIPACKAGE *package, int level )
1825 static const WCHAR szAddLocal[] =
1826 {'A','D','D','L','O','C','A','L',0};
1827 static const WCHAR szAddSource[] =
1828 {'A','D','D','S','O','U','R','C','E',0};
1829 static const WCHAR szAdvertise[] =
1830 {'A','D','V','E','R','T','I','S','E',0};
1833 /* all these activation/deactivation things happen in order and things
1834 * later on the list override things earlier on the list.
1836 * 0 INSTALLLEVEL processing
1849 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1850 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1851 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1852 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1853 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1856 msi_set_property( package->db, szPreselected, szOne );
1861 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1864 static const WCHAR szlevel[] =
1865 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1866 MSICOMPONENT* component;
1867 MSIFEATURE *feature;
1869 TRACE("Checking Install Level\n");
1871 level = msi_get_property_int(package->db, szlevel, 1);
1873 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1875 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1877 BOOL feature_state = ((feature->Level > 0) &&
1878 (feature->Level <= level));
1880 if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1882 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1883 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1884 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1885 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1887 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1891 /* disable child features of unselected parent features */
1892 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1896 if (feature->Level > 0 && feature->Level <= level)
1899 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1900 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1905 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1907 BOOL selected = feature->Level > 0 && feature->Level <= level;
1909 if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1911 msi_feature_set_state(package, feature, feature->Installed);
1917 * now we want to enable or disable components based on feature
1919 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1923 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1924 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1925 feature->ActionRequest, feature->Action);
1927 if (!feature->Level)
1930 /* features with components that have compressed files are made local */
1931 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1933 if (cl->component->ForceLocalState &&
1934 feature->ActionRequest == INSTALLSTATE_SOURCE)
1936 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1941 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1943 component = cl->component;
1945 switch (feature->ActionRequest)
1947 case INSTALLSTATE_ABSENT:
1948 component->anyAbsent = 1;
1950 case INSTALLSTATE_ADVERTISED:
1951 component->hasAdvertiseFeature = 1;
1953 case INSTALLSTATE_SOURCE:
1954 component->hasSourceFeature = 1;
1956 case INSTALLSTATE_LOCAL:
1957 component->hasLocalFeature = 1;
1959 case INSTALLSTATE_DEFAULT:
1960 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1961 component->hasAdvertiseFeature = 1;
1962 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1963 component->hasSourceFeature = 1;
1965 component->hasLocalFeature = 1;
1973 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1975 /* check if it's local or source */
1976 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1977 (component->hasLocalFeature || component->hasSourceFeature))
1979 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1980 !component->ForceLocalState)
1981 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1983 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1987 /* if any feature is local, the component must be local too */
1988 if (component->hasLocalFeature)
1990 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1994 if (component->hasSourceFeature)
1996 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2000 if (component->hasAdvertiseFeature)
2002 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2006 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2007 if (component->anyAbsent)
2008 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2011 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2013 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2015 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2016 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2019 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2020 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2023 return ERROR_SUCCESS;
2026 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2028 MSIPACKAGE *package = param;
2033 name = MSI_RecordGetString(row,1);
2035 f = get_loaded_folder(package, name);
2036 if (!f) return ERROR_SUCCESS;
2038 /* reset the ResolvedTarget */
2039 msi_free(f->ResolvedTarget);
2040 f->ResolvedTarget = NULL;
2042 /* This helper function now does ALL the work */
2043 TRACE("Dir %s ...\n",debugstr_w(name));
2044 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2045 TRACE("resolves to %s\n",debugstr_w(path));
2048 return ERROR_SUCCESS;
2051 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2053 MSIPACKAGE *package = param;
2055 MSIFEATURE *feature;
2057 name = MSI_RecordGetString( row, 1 );
2059 feature = get_loaded_feature( package, name );
2061 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2065 Condition = MSI_RecordGetString(row,3);
2067 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2069 int level = MSI_RecordGetInteger(row,2);
2070 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2071 feature->Level = level;
2074 return ERROR_SUCCESS;
2077 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2079 static const WCHAR name[] = {'\\',0};
2080 VS_FIXEDFILEINFO *ptr, *ret;
2082 DWORD versize, handle;
2085 TRACE("%s\n", debugstr_w(filename));
2087 versize = GetFileVersionInfoSizeW( filename, &handle );
2091 version = msi_alloc( versize );
2095 GetFileVersionInfoW( filename, 0, versize, version );
2097 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2099 msi_free( version );
2103 ret = msi_alloc( sz );
2104 memcpy( ret, ptr, sz );
2106 msi_free( version );
2110 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2114 msi_parse_version_string( version, &ms, &ls );
2116 if (fi->dwFileVersionMS > ms) return 1;
2117 else if (fi->dwFileVersionMS < ms) return -1;
2118 else if (fi->dwFileVersionLS > ls) return 1;
2119 else if (fi->dwFileVersionLS < ls) return -1;
2123 static DWORD get_disk_file_size( LPCWSTR filename )
2128 TRACE("%s\n", debugstr_w(filename));
2130 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2131 if (file == INVALID_HANDLE_VALUE)
2132 return INVALID_FILE_SIZE;
2134 size = GetFileSize( file, NULL );
2135 CloseHandle( file );
2139 static BOOL hash_matches( MSIFILE *file )
2142 MSIFILEHASHINFO hash;
2144 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2145 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2146 if (r != ERROR_SUCCESS)
2149 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2152 static WCHAR *get_temp_dir( void )
2155 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2157 GetTempPathW( MAX_PATH, tmp );
2160 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2161 if (CreateDirectoryW( dir, NULL )) break;
2163 return strdupW( dir );
2166 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2168 MSIASSEMBLY *assembly = file->Component->assembly;
2170 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2172 msi_free( file->TargetPath );
2173 if (assembly && !assembly->application)
2175 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2176 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2177 track_tempfile( package, file->TargetPath );
2181 WCHAR *dir = resolve_folder( package, file->Component->Directory, FALSE, FALSE, TRUE, NULL );
2182 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2186 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2189 static UINT set_file_install_states( MSIPACKAGE *package )
2191 VS_FIXEDFILEINFO *file_version;
2194 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2196 MSICOMPONENT *comp = file->Component;
2199 if (!comp->Enabled) continue;
2201 if (file->IsCompressed)
2202 comp->ForceLocalState = TRUE;
2204 set_target_path( package, file );
2206 if ((comp->assembly && !comp->assembly->installed) ||
2207 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2209 file->state = msifs_missing;
2210 comp->Cost += file->FileSize;
2213 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2215 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2216 HIWORD(file_version->dwFileVersionMS),
2217 LOWORD(file_version->dwFileVersionMS),
2218 HIWORD(file_version->dwFileVersionLS),
2219 LOWORD(file_version->dwFileVersionLS));
2221 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2223 file->state = msifs_overwrite;
2224 comp->Cost += file->FileSize;
2228 TRACE("Destination file version equal or greater, not overwriting\n");
2229 file->state = msifs_present;
2231 msi_free( file_version );
2234 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2236 file->state = msifs_overwrite;
2237 comp->Cost += file->FileSize - file_size;
2240 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2242 TRACE("File hashes match, not overwriting\n");
2243 file->state = msifs_present;
2246 file->state = msifs_overwrite;
2247 comp->Cost += file->FileSize - file_size;
2250 return ERROR_SUCCESS;
2254 * A lot is done in this function aside from just the costing.
2255 * The costing needs to be implemented at some point but for now I am going
2256 * to focus on the directory building
2259 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2261 static const WCHAR ExecSeqQuery[] =
2262 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2263 '`','D','i','r','e','c','t','o','r','y','`',0};
2264 static const WCHAR ConditionQuery[] =
2265 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2266 '`','C','o','n','d','i','t','i','o','n','`',0};
2267 static const WCHAR szCosting[] =
2268 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2269 static const WCHAR szlevel[] =
2270 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2271 static const WCHAR szOutOfDiskSpace[] =
2272 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2274 UINT rc = ERROR_SUCCESS;
2278 TRACE("Building Directory properties\n");
2280 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2281 if (rc == ERROR_SUCCESS)
2283 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2285 msiobj_release(&view->hdr);
2288 /* read components states from the registry */
2289 ACTION_GetComponentInstallStates(package);
2290 ACTION_GetFeatureInstallStates(package);
2292 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2294 TRACE("Evaluating feature conditions\n");
2296 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2297 if (rc == ERROR_SUCCESS)
2299 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2300 msiobj_release( &view->hdr );
2303 TRACE("Evaluating component conditions\n");
2305 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2307 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2309 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2310 comp->Enabled = FALSE;
2313 comp->Enabled = TRUE;
2316 TRACE("Calculating file install states\n");
2317 set_file_install_states( package );
2319 msi_set_property( package->db, szCosting, szOne );
2320 /* set default run level if not set */
2321 level = msi_dup_property( package->db, szlevel );
2323 msi_set_property( package->db, szlevel, szOne );
2326 /* FIXME: check volume disk space */
2327 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2329 return MSI_SetFeatureStates(package);
2332 /* OK this value is "interpreted" and then formatted based on the
2333 first few characters */
2334 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2339 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2345 LPWSTR deformated = NULL;
2348 deformat_string(package, &value[2], &deformated);
2350 /* binary value type */
2354 *size = (strlenW(ptr)/2)+1;
2356 *size = strlenW(ptr)/2;
2358 data = msi_alloc(*size);
2364 /* if uneven pad with a zero in front */
2370 data[count] = (BYTE)strtol(byte,NULL,0);
2372 TRACE("Uneven byte count\n");
2380 data[count] = (BYTE)strtol(byte,NULL,0);
2383 msi_free(deformated);
2385 TRACE("Data %i bytes(%i)\n",*size,count);
2392 deformat_string(package, &value[1], &deformated);
2395 *size = sizeof(DWORD);
2396 data = msi_alloc(*size);
2402 if ( (*p < '0') || (*p > '9') )
2408 if (deformated[0] == '-')
2411 TRACE("DWORD %i\n",*(LPDWORD)data);
2413 msi_free(deformated);
2418 static const WCHAR szMulti[] = {'[','~',']',0};
2427 *type=REG_EXPAND_SZ;
2435 if (strstrW(value, szMulti))
2436 *type = REG_MULTI_SZ;
2438 /* remove initial delimiter */
2439 if (!strncmpW(value, szMulti, 3))
2442 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2444 /* add double NULL terminator */
2445 if (*type == REG_MULTI_SZ)
2447 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2448 data = msi_realloc_zero(data, *size);
2454 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2461 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2463 *root_key = HKEY_LOCAL_MACHINE;
2468 *root_key = HKEY_CURRENT_USER;
2473 *root_key = HKEY_CLASSES_ROOT;
2477 *root_key = HKEY_CURRENT_USER;
2481 *root_key = HKEY_LOCAL_MACHINE;
2485 *root_key = HKEY_USERS;
2489 ERR("Unknown root %i\n", root);
2496 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2498 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2499 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2501 if (is_64bit && package->platform == PLATFORM_INTEL &&
2502 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2507 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2508 path_32node = msi_alloc( size );
2512 memcpy( path_32node, path, len * sizeof(WCHAR) );
2513 path_32node[len] = 0;
2514 strcatW( path_32node, szWow6432Node );
2515 strcatW( path_32node, szBackSlash );
2516 strcatW( path_32node, path + len );
2520 return strdupW( path );
2523 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2525 MSIPACKAGE *package = param;
2526 LPSTR value_data = NULL;
2527 HKEY root_key, hkey;
2529 LPWSTR deformated, uikey, keypath;
2530 LPCWSTR szRoot, component, name, key, value;
2534 BOOL check_first = FALSE;
2537 ui_progress(package,2,0,0,0);
2539 component = MSI_RecordGetString(row, 6);
2540 comp = get_loaded_component(package,component);
2542 return ERROR_SUCCESS;
2546 TRACE("component is disabled\n");
2547 return ERROR_SUCCESS;
2550 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2552 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2553 comp->Action = comp->Installed;
2554 return ERROR_SUCCESS;
2556 comp->Action = INSTALLSTATE_LOCAL;
2558 name = MSI_RecordGetString(row, 4);
2559 if( MSI_RecordIsNull(row,5) && name )
2561 /* null values can have special meanings */
2562 if (name[0]=='-' && name[1] == 0)
2563 return ERROR_SUCCESS;
2564 else if ((name[0]=='+' && name[1] == 0) ||
2565 (name[0] == '*' && name[1] == 0))
2570 root = MSI_RecordGetInteger(row,2);
2571 key = MSI_RecordGetString(row, 3);
2573 szRoot = get_root_key( package, root, &root_key );
2575 return ERROR_SUCCESS;
2577 deformat_string(package, key , &deformated);
2578 size = strlenW(deformated) + strlenW(szRoot) + 1;
2579 uikey = msi_alloc(size*sizeof(WCHAR));
2580 strcpyW(uikey,szRoot);
2581 strcatW(uikey,deformated);
2583 keypath = get_keypath( package, root_key, deformated );
2584 msi_free( deformated );
2585 if (RegCreateKeyW( root_key, keypath, &hkey ))
2587 ERR("Could not create key %s\n", debugstr_w(keypath));
2589 return ERROR_SUCCESS;
2592 value = MSI_RecordGetString(row,5);
2594 value_data = parse_value(package, value, &type, &size);
2597 value_data = (LPSTR)strdupW(szEmpty);
2598 size = sizeof(szEmpty);
2602 deformat_string(package, name, &deformated);
2606 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2608 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2613 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2614 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2616 TRACE("value %s of %s checked already exists\n",
2617 debugstr_w(deformated), debugstr_w(uikey));
2621 TRACE("Checked and setting value %s of %s\n",
2622 debugstr_w(deformated), debugstr_w(uikey));
2623 if (deformated || size)
2624 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2629 uirow = MSI_CreateRecord(3);
2630 MSI_RecordSetStringW(uirow,2,deformated);
2631 MSI_RecordSetStringW(uirow,1,uikey);
2632 if (type == REG_SZ || type == REG_EXPAND_SZ)
2633 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2634 ui_actiondata(package,szWriteRegistryValues,uirow);
2635 msiobj_release( &uirow->hdr );
2637 msi_free(value_data);
2638 msi_free(deformated);
2641 return ERROR_SUCCESS;
2644 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2648 static const WCHAR ExecSeqQuery[] =
2649 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2650 '`','R','e','g','i','s','t','r','y','`',0 };
2652 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2653 if (rc != ERROR_SUCCESS)
2654 return ERROR_SUCCESS;
2656 /* increment progress bar each time action data is sent */
2657 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2659 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2661 msiobj_release(&view->hdr);
2665 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2669 DWORD num_subkeys, num_values;
2673 if ((res = RegDeleteTreeW( hkey_root, key )))
2675 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2680 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2682 if ((res = RegDeleteValueW( hkey, value )))
2684 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2686 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2687 NULL, NULL, NULL, NULL );
2688 RegCloseKey( hkey );
2689 if (!res && !num_subkeys && !num_values)
2691 TRACE("Removing empty key %s\n", debugstr_w(key));
2692 RegDeleteKeyW( hkey_root, key );
2696 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2700 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2702 MSIPACKAGE *package = param;
2703 LPCWSTR component, name, key_str, root_key_str;
2704 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2707 BOOL delete_key = FALSE;
2712 ui_progress( package, 2, 0, 0, 0 );
2714 component = MSI_RecordGetString( row, 6 );
2715 comp = get_loaded_component( package, component );
2717 return ERROR_SUCCESS;
2721 TRACE("component is disabled\n");
2722 return ERROR_SUCCESS;
2725 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2727 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2728 comp->Action = comp->Installed;
2729 return ERROR_SUCCESS;
2731 comp->Action = INSTALLSTATE_ABSENT;
2733 name = MSI_RecordGetString( row, 4 );
2734 if (MSI_RecordIsNull( row, 5 ) && name )
2736 if (name[0] == '+' && !name[1])
2737 return ERROR_SUCCESS;
2738 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2745 root = MSI_RecordGetInteger( row, 2 );
2746 key_str = MSI_RecordGetString( row, 3 );
2748 root_key_str = get_root_key( package, root, &hkey_root );
2750 return ERROR_SUCCESS;
2752 deformat_string( package, key_str, &deformated_key );
2753 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2754 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2755 strcpyW( ui_key_str, root_key_str );
2756 strcatW( ui_key_str, deformated_key );
2758 deformat_string( package, name, &deformated_name );
2760 keypath = get_keypath( package, hkey_root, deformated_key );
2761 msi_free( deformated_key );
2762 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2763 msi_free( keypath );
2765 uirow = MSI_CreateRecord( 2 );
2766 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2767 MSI_RecordSetStringW( uirow, 2, deformated_name );
2769 ui_actiondata( package, szRemoveRegistryValues, uirow );
2770 msiobj_release( &uirow->hdr );
2772 msi_free( ui_key_str );
2773 msi_free( deformated_name );
2774 return ERROR_SUCCESS;
2777 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2779 MSIPACKAGE *package = param;
2780 LPCWSTR component, name, key_str, root_key_str;
2781 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2784 BOOL delete_key = FALSE;
2789 ui_progress( package, 2, 0, 0, 0 );
2791 component = MSI_RecordGetString( row, 5 );
2792 comp = get_loaded_component( package, component );
2794 return ERROR_SUCCESS;
2798 TRACE("component is disabled\n");
2799 return ERROR_SUCCESS;
2802 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2804 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2805 comp->Action = comp->Installed;
2806 return ERROR_SUCCESS;
2808 comp->Action = INSTALLSTATE_LOCAL;
2810 if ((name = MSI_RecordGetString( row, 4 )))
2812 if (name[0] == '-' && !name[1])
2819 root = MSI_RecordGetInteger( row, 2 );
2820 key_str = MSI_RecordGetString( row, 3 );
2822 root_key_str = get_root_key( package, root, &hkey_root );
2824 return ERROR_SUCCESS;
2826 deformat_string( package, key_str, &deformated_key );
2827 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2828 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2829 strcpyW( ui_key_str, root_key_str );
2830 strcatW( ui_key_str, deformated_key );
2832 deformat_string( package, name, &deformated_name );
2834 keypath = get_keypath( package, hkey_root, deformated_key );
2835 msi_free( deformated_key );
2836 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2837 msi_free( keypath );
2839 uirow = MSI_CreateRecord( 2 );
2840 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2841 MSI_RecordSetStringW( uirow, 2, deformated_name );
2843 ui_actiondata( package, szRemoveRegistryValues, uirow );
2844 msiobj_release( &uirow->hdr );
2846 msi_free( ui_key_str );
2847 msi_free( deformated_name );
2848 return ERROR_SUCCESS;
2851 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2855 static const WCHAR registry_query[] =
2856 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2857 '`','R','e','g','i','s','t','r','y','`',0 };
2858 static const WCHAR remove_registry_query[] =
2859 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2860 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2862 /* increment progress bar each time action data is sent */
2863 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2865 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2866 if (rc == ERROR_SUCCESS)
2868 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2869 msiobj_release( &view->hdr );
2870 if (rc != ERROR_SUCCESS)
2874 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2875 if (rc == ERROR_SUCCESS)
2877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2878 msiobj_release( &view->hdr );
2879 if (rc != ERROR_SUCCESS)
2883 return ERROR_SUCCESS;
2886 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2888 package->script->CurrentlyScripting = TRUE;
2890 return ERROR_SUCCESS;
2894 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2899 static const WCHAR q1[]=
2900 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2901 '`','R','e','g','i','s','t','r','y','`',0};
2904 MSIFEATURE *feature;
2907 TRACE("InstallValidate\n");
2909 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2910 if (rc == ERROR_SUCCESS)
2912 MSI_IterateRecords( view, &progress, NULL, package );
2913 msiobj_release( &view->hdr );
2914 total += progress * REG_PROGRESS_VALUE;
2917 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2918 total += COMPONENT_PROGRESS_VALUE;
2920 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2921 total += file->FileSize;
2923 ui_progress(package,0,total,0,0);
2925 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2927 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2928 debugstr_w(feature->Feature), feature->Installed,
2929 feature->ActionRequest, feature->Action);
2932 return ERROR_SUCCESS;
2935 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2937 MSIPACKAGE* package = param;
2938 LPCWSTR cond = NULL;
2939 LPCWSTR message = NULL;
2942 static const WCHAR title[]=
2943 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2945 cond = MSI_RecordGetString(row,1);
2947 r = MSI_EvaluateConditionW(package,cond);
2948 if (r == MSICONDITION_FALSE)
2950 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2953 message = MSI_RecordGetString(row,2);
2954 deformat_string(package,message,&deformated);
2955 MessageBoxW(NULL,deformated,title,MB_OK);
2956 msi_free(deformated);
2959 return ERROR_INSTALL_FAILURE;
2962 return ERROR_SUCCESS;
2965 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2968 MSIQUERY * view = NULL;
2969 static const WCHAR ExecSeqQuery[] =
2970 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2971 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2973 TRACE("Checking launch conditions\n");
2975 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2976 if (rc != ERROR_SUCCESS)
2977 return ERROR_SUCCESS;
2979 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2980 msiobj_release(&view->hdr);
2985 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2989 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2991 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2993 MSIRECORD * row = 0;
2995 LPWSTR deformated,buffer,deformated_name;
2997 static const WCHAR ExecSeqQuery[] =
2998 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2999 '`','R','e','g','i','s','t','r','y','`',' ',
3000 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3001 ' ','=',' ' ,'\'','%','s','\'',0 };
3002 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3003 static const WCHAR fmt2[]=
3004 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3006 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3010 root = MSI_RecordGetInteger(row,2);
3011 key = MSI_RecordGetString(row, 3);
3012 name = MSI_RecordGetString(row, 4);
3013 deformat_string(package, key , &deformated);
3014 deformat_string(package, name, &deformated_name);
3016 len = strlenW(deformated) + 6;
3017 if (deformated_name)
3018 len+=strlenW(deformated_name);
3020 buffer = msi_alloc( len *sizeof(WCHAR));
3022 if (deformated_name)
3023 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3025 sprintfW(buffer,fmt,root,deformated);
3027 msi_free(deformated);
3028 msi_free(deformated_name);
3029 msiobj_release(&row->hdr);
3033 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3035 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3040 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3043 return strdupW( file->TargetPath );
3048 static HKEY openSharedDLLsKey(void)
3051 static const WCHAR path[] =
3052 {'S','o','f','t','w','a','r','e','\\',
3053 'M','i','c','r','o','s','o','f','t','\\',
3054 'W','i','n','d','o','w','s','\\',
3055 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3056 'S','h','a','r','e','d','D','L','L','s',0};
3058 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3062 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3067 DWORD sz = sizeof(count);
3070 hkey = openSharedDLLsKey();
3071 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3072 if (rc != ERROR_SUCCESS)
3078 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3082 hkey = openSharedDLLsKey();
3084 msi_reg_set_val_dword( hkey, path, count );
3086 RegDeleteValueW(hkey,path);
3092 * Return TRUE if the count should be written out and FALSE if not
3094 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3096 MSIFEATURE *feature;
3100 /* only refcount DLLs */
3101 if (comp->KeyPath == NULL ||
3102 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3103 comp->Attributes & msidbComponentAttributesODBCDataSource)
3107 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3108 write = (count > 0);
3110 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3114 /* increment counts */
3115 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3119 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3122 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3124 if ( cl->component == comp )
3129 /* decrement counts */
3130 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3134 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3137 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3139 if ( cl->component == comp )
3144 /* ref count all the files in the component */
3149 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3151 if (file->Component == comp)
3152 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3156 /* add a count for permanent */
3157 if (comp->Attributes & msidbComponentAttributesPermanent)
3160 comp->RefCount = count;
3163 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3166 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3168 WCHAR squished_pc[GUID_SIZE];
3169 WCHAR squished_cc[GUID_SIZE];
3176 squash_guid(package->ProductCode,squished_pc);
3177 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3179 msi_set_sourcedir_props(package, FALSE);
3181 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3185 ui_progress(package,2,0,0,0);
3186 if (!comp->ComponentId)
3189 squash_guid(comp->ComponentId,squished_cc);
3191 msi_free(comp->FullKeypath);
3192 comp->FullKeypath = resolve_keypath( package, comp );
3194 ACTION_RefCountComponent( package, comp );
3196 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3197 debugstr_w(comp->Component),
3198 debugstr_w(squished_cc),
3199 debugstr_w(comp->FullKeypath),
3201 comp->ActionRequest);
3203 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3204 comp->ActionRequest == INSTALLSTATE_SOURCE)
3206 if (!comp->FullKeypath)
3209 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3210 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3213 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3216 if (rc != ERROR_SUCCESS)
3219 if (comp->Attributes & msidbComponentAttributesPermanent)
3221 static const WCHAR szPermKey[] =
3222 { '0','0','0','0','0','0','0','0','0','0','0','0',
3223 '0','0','0','0','0','0','0','0','0','0','0','0',
3224 '0','0','0','0','0','0','0','0',0 };
3226 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3229 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3230 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3236 WCHAR source[MAX_PATH];
3237 WCHAR base[MAX_PATH];
3240 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3241 static const WCHAR query[] = {
3242 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3243 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3244 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3245 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3246 '`','D','i','s','k','I','d','`',0};
3248 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3251 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3252 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3253 ptr2 = strrchrW(source, '\\') + 1;
3254 msiobj_release(&row->hdr);
3256 lstrcpyW(base, package->PackagePath);
3257 ptr = strrchrW(base, '\\');
3260 sourcepath = resolve_file_source(package, file);
3261 ptr = sourcepath + lstrlenW(base);
3262 lstrcpyW(ptr2, ptr);
3263 msi_free(sourcepath);
3265 msi_reg_set_val_str(hkey, squished_pc, source);
3269 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3271 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3272 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3274 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3276 comp->Action = comp->ActionRequest;
3279 uirow = MSI_CreateRecord(3);
3280 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3281 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3282 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3283 ui_actiondata(package,szProcessComponents,uirow);
3284 msiobj_release( &uirow->hdr );
3287 return ERROR_SUCCESS;
3298 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3299 LPWSTR lpszName, LONG_PTR lParam)
3302 typelib_struct *tl_struct = (typelib_struct*) lParam;
3303 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3307 if (!IS_INTRESOURCE(lpszName))
3309 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3313 sz = strlenW(tl_struct->source)+4;
3314 sz *= sizeof(WCHAR);
3316 if ((INT_PTR)lpszName == 1)
3317 tl_struct->path = strdupW(tl_struct->source);
3320 tl_struct->path = msi_alloc(sz);
3321 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3324 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3325 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3328 msi_free(tl_struct->path);
3329 tl_struct->path = NULL;
3334 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3335 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3337 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3341 msi_free(tl_struct->path);
3342 tl_struct->path = NULL;
3344 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3345 ITypeLib_Release(tl_struct->ptLib);
3350 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3352 MSIPACKAGE* package = param;
3356 typelib_struct tl_struct;
3361 component = MSI_RecordGetString(row,3);
3362 comp = get_loaded_component(package,component);
3364 return ERROR_SUCCESS;
3368 TRACE("component is disabled\n");
3369 return ERROR_SUCCESS;
3372 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3374 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3375 comp->Action = comp->Installed;
3376 return ERROR_SUCCESS;
3378 comp->Action = INSTALLSTATE_LOCAL;
3380 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3382 TRACE("component has no key path\n");
3383 return ERROR_SUCCESS;
3385 ui_actiondata( package, szRegisterTypeLibraries, row );
3387 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3391 guid = MSI_RecordGetString(row,1);
3392 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3393 tl_struct.source = strdupW( file->TargetPath );
3394 tl_struct.path = NULL;
3396 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3397 (LONG_PTR)&tl_struct);
3405 helpid = MSI_RecordGetString(row,6);
3408 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3409 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3413 ERR("Failed to register type library %s\n",
3414 debugstr_w(tl_struct.path));
3416 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3418 ITypeLib_Release(tl_struct.ptLib);
3419 msi_free(tl_struct.path);
3422 ERR("Failed to load type library %s\n",
3423 debugstr_w(tl_struct.source));
3425 FreeLibrary(module);
3426 msi_free(tl_struct.source);
3430 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3433 ERR("Failed to load type library: %08x\n", hr);
3434 return ERROR_INSTALL_FAILURE;
3437 ITypeLib_Release(tlib);
3440 return ERROR_SUCCESS;
3443 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3446 * OK this is a bit confusing.. I am given a _Component key and I believe
3447 * that the file that is being registered as a type library is the "key file
3448 * of that component" which I interpret to mean "The file in the KeyPath of
3453 static const WCHAR Query[] =
3454 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3455 '`','T','y','p','e','L','i','b','`',0};
3457 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3458 if (rc != ERROR_SUCCESS)
3459 return ERROR_SUCCESS;
3461 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3462 msiobj_release(&view->hdr);
3466 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3468 MSIPACKAGE *package = param;
3469 LPCWSTR component, guid;
3477 component = MSI_RecordGetString( row, 3 );
3478 comp = get_loaded_component( package, component );
3480 return ERROR_SUCCESS;
3484 TRACE("component is disabled\n");
3485 return ERROR_SUCCESS;
3488 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3490 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3491 comp->Action = comp->Installed;
3492 return ERROR_SUCCESS;
3494 comp->Action = INSTALLSTATE_ABSENT;
3496 ui_actiondata( package, szUnregisterTypeLibraries, row );
3498 guid = MSI_RecordGetString( row, 1 );
3499 CLSIDFromString( (LPCWSTR)guid, &libid );
3500 version = MSI_RecordGetInteger( row, 4 );
3501 language = MSI_RecordGetInteger( row, 2 );
3504 syskind = SYS_WIN64;
3506 syskind = SYS_WIN32;
3509 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3512 WARN("Failed to unregister typelib: %08x\n", hr);
3515 return ERROR_SUCCESS;
3518 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3522 static const WCHAR query[] =
3523 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3524 '`','T','y','p','e','L','i','b','`',0};
3526 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3527 if (rc != ERROR_SUCCESS)
3528 return ERROR_SUCCESS;
3530 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3531 msiobj_release( &view->hdr );
3535 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3537 static const WCHAR szlnk[] = {'.','l','n','k',0};
3538 LPCWSTR directory, extension;
3539 LPWSTR link_folder, link_file, filename;
3541 directory = MSI_RecordGetString( row, 2 );
3542 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3544 /* may be needed because of a bug somewhere else */
3545 create_full_pathW( link_folder );
3547 filename = msi_dup_record_field( row, 3 );
3548 reduce_to_longfilename( filename );
3550 extension = strchrW( filename, '.' );
3551 if (!extension || strcmpiW( extension, szlnk ))
3553 int len = strlenW( filename );
3554 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3555 memcpy( filename + len, szlnk, sizeof(szlnk) );
3557 link_file = build_directory_name( 2, link_folder, filename );
3558 msi_free( link_folder );
3559 msi_free( filename );
3564 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3566 MSIPACKAGE *package = param;
3567 LPWSTR link_file, deformated, path;
3568 LPCWSTR component, target;
3570 IShellLinkW *sl = NULL;
3571 IPersistFile *pf = NULL;
3574 component = MSI_RecordGetString(row, 4);
3575 comp = get_loaded_component(package, component);
3577 return ERROR_SUCCESS;
3581 TRACE("component is disabled\n");
3582 return ERROR_SUCCESS;
3585 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3587 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3588 comp->Action = comp->Installed;
3589 return ERROR_SUCCESS;
3591 comp->Action = INSTALLSTATE_LOCAL;
3593 ui_actiondata(package,szCreateShortcuts,row);
3595 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3596 &IID_IShellLinkW, (LPVOID *) &sl );
3600 ERR("CLSID_ShellLink not available\n");
3604 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3607 ERR("QueryInterface(IID_IPersistFile) failed\n");
3611 target = MSI_RecordGetString(row, 5);
3612 if (strchrW(target, '['))
3614 deformat_string(package, target, &deformated);
3615 IShellLinkW_SetPath(sl,deformated);
3616 msi_free(deformated);
3620 FIXME("poorly handled shortcut format, advertised shortcut\n");
3621 IShellLinkW_SetPath(sl,comp->FullKeypath);
3624 if (!MSI_RecordIsNull(row,6))
3626 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3627 deformat_string(package, arguments, &deformated);
3628 IShellLinkW_SetArguments(sl,deformated);
3629 msi_free(deformated);
3632 if (!MSI_RecordIsNull(row,7))
3634 LPCWSTR description = MSI_RecordGetString(row, 7);
3635 IShellLinkW_SetDescription(sl, description);
3638 if (!MSI_RecordIsNull(row,8))
3639 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3641 if (!MSI_RecordIsNull(row,9))
3644 LPCWSTR icon = MSI_RecordGetString(row, 9);
3646 path = build_icon_path(package, icon);
3647 index = MSI_RecordGetInteger(row,10);
3649 /* no value means 0 */
3650 if (index == MSI_NULL_INTEGER)
3653 IShellLinkW_SetIconLocation(sl, path, index);
3657 if (!MSI_RecordIsNull(row,11))
3658 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3660 if (!MSI_RecordIsNull(row,12))
3662 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3663 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3665 IShellLinkW_SetWorkingDirectory(sl, path);
3669 link_file = get_link_file(package, row);
3671 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3672 IPersistFile_Save(pf, link_file, FALSE);
3674 msi_free(link_file);
3678 IPersistFile_Release( pf );
3680 IShellLinkW_Release( sl );
3682 return ERROR_SUCCESS;
3685 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3690 static const WCHAR Query[] =
3691 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3692 '`','S','h','o','r','t','c','u','t','`',0};
3694 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3695 if (rc != ERROR_SUCCESS)
3696 return ERROR_SUCCESS;
3698 res = CoInitialize( NULL );
3700 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3701 msiobj_release(&view->hdr);
3709 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3711 MSIPACKAGE *package = param;
3716 component = MSI_RecordGetString( row, 4 );
3717 comp = get_loaded_component( package, component );
3719 return ERROR_SUCCESS;
3723 TRACE("component is disabled\n");
3724 return ERROR_SUCCESS;
3727 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3729 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3730 comp->Action = comp->Installed;
3731 return ERROR_SUCCESS;
3733 comp->Action = INSTALLSTATE_ABSENT;
3735 ui_actiondata( package, szRemoveShortcuts, row );
3737 link_file = get_link_file( package, row );
3739 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3740 if (!DeleteFileW( link_file ))
3742 WARN("Failed to remove shortcut file %u\n", GetLastError());
3744 msi_free( link_file );
3746 return ERROR_SUCCESS;
3749 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3753 static const WCHAR query[] =
3754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3755 '`','S','h','o','r','t','c','u','t','`',0};
3757 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3758 if (rc != ERROR_SUCCESS)
3759 return ERROR_SUCCESS;
3761 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3762 msiobj_release( &view->hdr );
3767 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3769 MSIPACKAGE* package = param;
3777 FileName = MSI_RecordGetString(row,1);
3780 ERR("Unable to get FileName\n");
3781 return ERROR_SUCCESS;
3784 FilePath = build_icon_path(package,FileName);
3786 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3788 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3789 FILE_ATTRIBUTE_NORMAL, NULL);
3791 if (the_file == INVALID_HANDLE_VALUE)
3793 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3795 return ERROR_SUCCESS;
3802 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3803 if (rc != ERROR_SUCCESS)
3805 ERR("Failed to get stream\n");
3806 CloseHandle(the_file);
3807 DeleteFileW(FilePath);
3810 WriteFile(the_file,buffer,sz,&write,NULL);
3811 } while (sz == 1024);
3814 CloseHandle(the_file);
3816 return ERROR_SUCCESS;
3819 static UINT msi_publish_icons(MSIPACKAGE *package)
3824 static const WCHAR query[]= {
3825 'S','E','L','E','C','T',' ','*',' ',
3826 'F','R','O','M',' ','`','I','c','o','n','`',0};
3828 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3829 if (r == ERROR_SUCCESS)
3831 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3832 msiobj_release(&view->hdr);
3835 return ERROR_SUCCESS;
3838 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3844 MSISOURCELISTINFO *info;
3846 r = RegCreateKeyW(hkey, szSourceList, &source);
3847 if (r != ERROR_SUCCESS)
3850 RegCloseKey(source);
3852 buffer = strrchrW(package->PackagePath, '\\') + 1;
3853 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3854 package->Context, MSICODE_PRODUCT,
3855 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3856 if (r != ERROR_SUCCESS)
3859 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3860 package->Context, MSICODE_PRODUCT,
3861 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3862 if (r != ERROR_SUCCESS)
3865 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3866 package->Context, MSICODE_PRODUCT,
3867 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3868 if (r != ERROR_SUCCESS)
3871 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3873 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3874 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3875 info->options, info->value);
3877 MsiSourceListSetInfoW(package->ProductCode, NULL,
3878 info->context, info->options,
3879 info->property, info->value);
3882 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3884 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3885 disk->context, disk->options,
3886 disk->disk_id, disk->volume_label, disk->disk_prompt);
3889 return ERROR_SUCCESS;
3892 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3894 MSIHANDLE hdb, suminfo;
3895 WCHAR guids[MAX_PATH];
3896 WCHAR packcode[SQUISH_GUID_SIZE];
3903 static const WCHAR szProductLanguage[] =
3904 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3905 static const WCHAR szARPProductIcon[] =
3906 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3907 static const WCHAR szProductVersion[] =
3908 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3909 static const WCHAR szAssignment[] =
3910 {'A','s','s','i','g','n','m','e','n','t',0};
3911 static const WCHAR szAdvertiseFlags[] =
3912 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3913 static const WCHAR szClients[] =
3914 {'C','l','i','e','n','t','s',0};
3915 static const WCHAR szColon[] = {':',0};
3917 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3918 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3921 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3922 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3925 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3927 buffer = msi_dup_property(package->db, szARPProductIcon);
3930 LPWSTR path = build_icon_path(package,buffer);
3931 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3936 buffer = msi_dup_property(package->db, szProductVersion);
3939 DWORD verdword = msi_version_str_to_dword(buffer);
3940 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3944 msi_reg_set_val_dword(hkey, szAssignment, 0);
3945 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3946 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3947 msi_reg_set_val_str(hkey, szClients, szColon);
3949 hdb = alloc_msihandle(&package->db->hdr);
3951 return ERROR_NOT_ENOUGH_MEMORY;
3953 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3954 MsiCloseHandle(hdb);
3955 if (r != ERROR_SUCCESS)
3959 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3960 NULL, guids, &size);
3961 if (r != ERROR_SUCCESS)
3964 ptr = strchrW(guids, ';');
3966 squash_guid(guids, packcode);
3967 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3970 MsiCloseHandle(suminfo);
3971 return ERROR_SUCCESS;
3974 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3979 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3981 upgrade = msi_dup_property(package->db, szUpgradeCode);
3983 return ERROR_SUCCESS;
3985 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3987 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3988 if (r != ERROR_SUCCESS)
3993 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3994 if (r != ERROR_SUCCESS)
3998 squash_guid(package->ProductCode, squashed_pc);
3999 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4008 static BOOL msi_check_publish(MSIPACKAGE *package)
4010 MSIFEATURE *feature;
4012 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4014 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4021 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4023 MSIFEATURE *feature;
4025 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4027 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4034 static UINT msi_publish_patches( MSIPACKAGE *package )
4036 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4037 WCHAR patch_squashed[GUID_SIZE];
4038 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4040 MSIPATCHINFO *patch;
4042 WCHAR *p, *all_patches = NULL;
4045 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4046 if (r != ERROR_SUCCESS)
4047 return ERROR_FUNCTION_FAILED;
4049 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4050 if (res != ERROR_SUCCESS)
4052 r = ERROR_FUNCTION_FAILED;
4056 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4057 if (r != ERROR_SUCCESS)
4060 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4062 squash_guid( patch->patchcode, patch_squashed );
4063 len += strlenW( patch_squashed ) + 1;
4066 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4070 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4074 squash_guid( patch->patchcode, p );
4075 p += strlenW( p ) + 1;
4077 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4078 (const BYTE *)patch->transforms,
4079 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4080 if (res != ERROR_SUCCESS)
4083 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4084 if (r != ERROR_SUCCESS)
4087 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4088 (const BYTE *)patch->localfile,
4089 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4090 RegCloseKey( patch_key );
4091 if (res != ERROR_SUCCESS)
4094 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4095 if (res != ERROR_SUCCESS)
4098 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4099 RegCloseKey( patch_key );
4100 if (res != ERROR_SUCCESS)
4104 all_patches[len] = 0;
4105 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4106 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4107 if (res != ERROR_SUCCESS)
4110 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4111 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4112 if (res != ERROR_SUCCESS)
4113 r = ERROR_FUNCTION_FAILED;
4116 RegCloseKey( product_patches_key );
4117 RegCloseKey( patches_key );
4118 RegCloseKey( product_key );
4119 msi_free( all_patches );
4124 * 99% of the work done here is only done for
4125 * advertised installs. However this is where the
4126 * Icon table is processed and written out
4127 * so that is what I am going to do here.
4129 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4132 HKEY hukey = NULL, hudkey = NULL;
4135 if (!list_empty(&package->patches))
4137 rc = msi_publish_patches(package);
4138 if (rc != ERROR_SUCCESS)
4142 /* FIXME: also need to publish if the product is in advertise mode */
4143 if (!msi_check_publish(package))
4144 return ERROR_SUCCESS;
4146 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4148 if (rc != ERROR_SUCCESS)
4151 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4152 NULL, &hudkey, TRUE);
4153 if (rc != ERROR_SUCCESS)
4156 rc = msi_publish_upgrade_code(package);
4157 if (rc != ERROR_SUCCESS)
4160 rc = msi_publish_product_properties(package, hukey);
4161 if (rc != ERROR_SUCCESS)
4164 rc = msi_publish_sourcelist(package, hukey);
4165 if (rc != ERROR_SUCCESS)
4168 rc = msi_publish_icons(package);
4171 uirow = MSI_CreateRecord( 1 );
4172 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4173 ui_actiondata( package, szPublishProduct, uirow );
4174 msiobj_release( &uirow->hdr );
4177 RegCloseKey(hudkey);
4182 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4184 WCHAR *filename, *ptr, *folder, *ret;
4185 const WCHAR *dirprop;
4187 filename = msi_dup_record_field( row, 2 );
4188 if (filename && (ptr = strchrW( filename, '|' )))
4193 dirprop = MSI_RecordGetString( row, 3 );
4196 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4198 folder = msi_dup_property( package->db, dirprop );
4201 folder = msi_dup_property( package->db, szWindowsFolder );
4205 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4206 msi_free( filename );
4210 ret = build_directory_name( 2, folder, ptr );
4212 msi_free( filename );
4217 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4219 MSIPACKAGE *package = param;
4220 LPCWSTR component, section, key, value, identifier;
4221 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4226 component = MSI_RecordGetString(row, 8);
4227 comp = get_loaded_component(package,component);
4229 return ERROR_SUCCESS;
4233 TRACE("component is disabled\n");
4234 return ERROR_SUCCESS;
4237 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4239 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4240 comp->Action = comp->Installed;
4241 return ERROR_SUCCESS;
4243 comp->Action = INSTALLSTATE_LOCAL;
4245 identifier = MSI_RecordGetString(row,1);
4246 section = MSI_RecordGetString(row,4);
4247 key = MSI_RecordGetString(row,5);
4248 value = MSI_RecordGetString(row,6);
4249 action = MSI_RecordGetInteger(row,7);
4251 deformat_string(package,section,&deformated_section);
4252 deformat_string(package,key,&deformated_key);
4253 deformat_string(package,value,&deformated_value);
4255 fullname = get_ini_file_name(package, row);
4259 TRACE("Adding value %s to section %s in %s\n",
4260 debugstr_w(deformated_key), debugstr_w(deformated_section),
4261 debugstr_w(fullname));
4262 WritePrivateProfileStringW(deformated_section, deformated_key,
4263 deformated_value, fullname);
4265 else if (action == 1)
4268 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4269 returned, 10, fullname);
4270 if (returned[0] == 0)
4272 TRACE("Adding value %s to section %s in %s\n",
4273 debugstr_w(deformated_key), debugstr_w(deformated_section),
4274 debugstr_w(fullname));
4276 WritePrivateProfileStringW(deformated_section, deformated_key,
4277 deformated_value, fullname);
4280 else if (action == 3)
4281 FIXME("Append to existing section not yet implemented\n");
4283 uirow = MSI_CreateRecord(4);
4284 MSI_RecordSetStringW(uirow,1,identifier);
4285 MSI_RecordSetStringW(uirow,2,deformated_section);
4286 MSI_RecordSetStringW(uirow,3,deformated_key);
4287 MSI_RecordSetStringW(uirow,4,deformated_value);
4288 ui_actiondata(package,szWriteIniValues,uirow);
4289 msiobj_release( &uirow->hdr );
4292 msi_free(deformated_key);
4293 msi_free(deformated_value);
4294 msi_free(deformated_section);
4295 return ERROR_SUCCESS;
4298 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4302 static const WCHAR ExecSeqQuery[] =
4303 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4304 '`','I','n','i','F','i','l','e','`',0};
4306 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4307 if (rc != ERROR_SUCCESS)
4309 TRACE("no IniFile table\n");
4310 return ERROR_SUCCESS;
4313 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4314 msiobj_release(&view->hdr);
4318 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4320 MSIPACKAGE *package = param;
4321 LPCWSTR component, section, key, value, identifier;
4322 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4327 component = MSI_RecordGetString( row, 8 );
4328 comp = get_loaded_component( package, component );
4330 return ERROR_SUCCESS;
4334 TRACE("component is disabled\n");
4335 return ERROR_SUCCESS;
4338 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4340 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4341 comp->Action = comp->Installed;
4342 return ERROR_SUCCESS;
4344 comp->Action = INSTALLSTATE_ABSENT;
4346 identifier = MSI_RecordGetString( row, 1 );
4347 section = MSI_RecordGetString( row, 4 );
4348 key = MSI_RecordGetString( row, 5 );
4349 value = MSI_RecordGetString( row, 6 );
4350 action = MSI_RecordGetInteger( row, 7 );
4352 deformat_string( package, section, &deformated_section );
4353 deformat_string( package, key, &deformated_key );
4354 deformat_string( package, value, &deformated_value );
4356 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4358 filename = get_ini_file_name( package, row );
4360 TRACE("Removing key %s from section %s in %s\n",
4361 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4363 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4365 WARN("Unable to remove key %u\n", GetLastError());
4367 msi_free( filename );
4370 FIXME("Unsupported action %d\n", action);
4373 uirow = MSI_CreateRecord( 4 );
4374 MSI_RecordSetStringW( uirow, 1, identifier );
4375 MSI_RecordSetStringW( uirow, 2, deformated_section );
4376 MSI_RecordSetStringW( uirow, 3, deformated_key );
4377 MSI_RecordSetStringW( uirow, 4, deformated_value );
4378 ui_actiondata( package, szRemoveIniValues, uirow );
4379 msiobj_release( &uirow->hdr );
4381 msi_free( deformated_key );
4382 msi_free( deformated_value );
4383 msi_free( deformated_section );
4384 return ERROR_SUCCESS;
4387 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4389 MSIPACKAGE *package = param;
4390 LPCWSTR component, section, key, value, identifier;
4391 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4396 component = MSI_RecordGetString( row, 8 );
4397 comp = get_loaded_component( package, component );
4399 return ERROR_SUCCESS;
4403 TRACE("component is disabled\n");
4404 return ERROR_SUCCESS;
4407 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4409 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4410 comp->Action = comp->Installed;
4411 return ERROR_SUCCESS;
4413 comp->Action = INSTALLSTATE_LOCAL;
4415 identifier = MSI_RecordGetString( row, 1 );
4416 section = MSI_RecordGetString( row, 4 );
4417 key = MSI_RecordGetString( row, 5 );
4418 value = MSI_RecordGetString( row, 6 );
4419 action = MSI_RecordGetInteger( row, 7 );
4421 deformat_string( package, section, &deformated_section );
4422 deformat_string( package, key, &deformated_key );
4423 deformat_string( package, value, &deformated_value );
4425 if (action == msidbIniFileActionRemoveLine)
4427 filename = get_ini_file_name( package, row );
4429 TRACE("Removing key %s from section %s in %s\n",
4430 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4432 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4434 WARN("Unable to remove key %u\n", GetLastError());
4436 msi_free( filename );
4439 FIXME("Unsupported action %d\n", action);
4441 uirow = MSI_CreateRecord( 4 );
4442 MSI_RecordSetStringW( uirow, 1, identifier );
4443 MSI_RecordSetStringW( uirow, 2, deformated_section );
4444 MSI_RecordSetStringW( uirow, 3, deformated_key );
4445 MSI_RecordSetStringW( uirow, 4, deformated_value );
4446 ui_actiondata( package, szRemoveIniValues, uirow );
4447 msiobj_release( &uirow->hdr );
4449 msi_free( deformated_key );
4450 msi_free( deformated_value );
4451 msi_free( deformated_section );
4452 return ERROR_SUCCESS;
4455 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4459 static const WCHAR query[] =
4460 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4461 '`','I','n','i','F','i','l','e','`',0};
4462 static const WCHAR remove_query[] =
4463 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4464 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4466 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4467 if (rc == ERROR_SUCCESS)
4469 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4470 msiobj_release( &view->hdr );
4471 if (rc != ERROR_SUCCESS)
4475 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4476 if (rc == ERROR_SUCCESS)
4478 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4479 msiobj_release( &view->hdr );
4480 if (rc != ERROR_SUCCESS)
4484 return ERROR_SUCCESS;
4487 static void register_dll( const WCHAR *dll, BOOL unregister )
4491 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4494 HRESULT (WINAPI *func_ptr)( void );
4495 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4497 func_ptr = (void *)GetProcAddress( hmod, func );
4500 HRESULT hr = func_ptr();
4502 WARN("failed to register dll 0x%08x\n", hr);
4505 WARN("entry point %s not found\n", func);
4506 FreeLibrary( hmod );
4509 WARN("failed to load library %u\n", GetLastError());
4512 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4514 MSIPACKAGE *package = param;
4519 filename = MSI_RecordGetString(row,1);
4520 file = get_loaded_file( package, filename );
4524 ERR("Unable to find file id %s\n",debugstr_w(filename));
4525 return ERROR_SUCCESS;
4528 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4530 register_dll( file->TargetPath, FALSE );
4532 uirow = MSI_CreateRecord( 2 );
4533 MSI_RecordSetStringW( uirow, 1, filename );
4534 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4535 ui_actiondata( package, szSelfRegModules, uirow );
4536 msiobj_release( &uirow->hdr );
4538 return ERROR_SUCCESS;
4541 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4545 static const WCHAR ExecSeqQuery[] =
4546 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4547 '`','S','e','l','f','R','e','g','`',0};
4549 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4550 if (rc != ERROR_SUCCESS)
4552 TRACE("no SelfReg table\n");
4553 return ERROR_SUCCESS;
4556 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4557 msiobj_release(&view->hdr);
4559 return ERROR_SUCCESS;
4562 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4564 MSIPACKAGE *package = param;
4569 filename = MSI_RecordGetString( row, 1 );
4570 file = get_loaded_file( package, filename );
4574 ERR("Unable to find file id %s\n", debugstr_w(filename));
4575 return ERROR_SUCCESS;
4578 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4580 register_dll( file->TargetPath, TRUE );
4582 uirow = MSI_CreateRecord( 2 );
4583 MSI_RecordSetStringW( uirow, 1, filename );
4584 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4585 ui_actiondata( package, szSelfUnregModules, uirow );
4586 msiobj_release( &uirow->hdr );
4588 return ERROR_SUCCESS;
4591 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4595 static const WCHAR query[] =
4596 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4597 '`','S','e','l','f','R','e','g','`',0};
4599 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4600 if (rc != ERROR_SUCCESS)
4602 TRACE("no SelfReg table\n");
4603 return ERROR_SUCCESS;
4606 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4607 msiobj_release( &view->hdr );
4609 return ERROR_SUCCESS;
4612 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4614 MSIFEATURE *feature;
4616 HKEY hkey = NULL, userdata = NULL;
4618 if (!msi_check_publish(package))
4619 return ERROR_SUCCESS;
4621 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4623 if (rc != ERROR_SUCCESS)
4626 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4628 if (rc != ERROR_SUCCESS)
4631 /* here the guids are base 85 encoded */
4632 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4638 BOOL absent = FALSE;
4641 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4642 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4643 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4646 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4650 if (feature->Feature_Parent)
4651 size += strlenW( feature->Feature_Parent )+2;
4653 data = msi_alloc(size * sizeof(WCHAR));
4656 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4658 MSICOMPONENT* component = cl->component;
4662 if (component->ComponentId)
4664 TRACE("From %s\n",debugstr_w(component->ComponentId));
4665 CLSIDFromString(component->ComponentId, &clsid);
4666 encode_base85_guid(&clsid,buf);
4667 TRACE("to %s\n",debugstr_w(buf));
4672 if (feature->Feature_Parent)
4674 static const WCHAR sep[] = {'\2',0};
4676 strcatW(data,feature->Feature_Parent);
4679 msi_reg_set_val_str( userdata, feature->Feature, data );
4683 if (feature->Feature_Parent)
4684 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4687 size += sizeof(WCHAR);
4688 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4689 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4693 size += 2*sizeof(WCHAR);
4694 data = msi_alloc(size);
4697 if (feature->Feature_Parent)
4698 strcpyW( &data[1], feature->Feature_Parent );
4699 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4705 uirow = MSI_CreateRecord( 1 );
4706 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4707 ui_actiondata( package, szPublishFeatures, uirow);
4708 msiobj_release( &uirow->hdr );
4709 /* FIXME: call ui_progress? */
4714 RegCloseKey(userdata);
4718 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4724 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4726 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4728 if (r == ERROR_SUCCESS)
4730 RegDeleteValueW(hkey, feature->Feature);
4734 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4736 if (r == ERROR_SUCCESS)
4738 RegDeleteValueW(hkey, feature->Feature);
4742 uirow = MSI_CreateRecord( 1 );
4743 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4744 ui_actiondata( package, szUnpublishFeatures, uirow );
4745 msiobj_release( &uirow->hdr );
4747 return ERROR_SUCCESS;
4750 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4752 MSIFEATURE *feature;
4754 if (!msi_check_unpublish(package))
4755 return ERROR_SUCCESS;
4757 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4759 msi_unpublish_feature(package, feature);
4762 return ERROR_SUCCESS;
4765 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4769 WCHAR date[9], *val, *buffer;
4770 const WCHAR *prop, *key;
4772 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4773 static const WCHAR szWindowsInstaller[] =
4774 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4775 static const WCHAR modpath_fmt[] =
4776 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4777 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4778 static const WCHAR szModifyPath[] =
4779 {'M','o','d','i','f','y','P','a','t','h',0};
4780 static const WCHAR szUninstallString[] =
4781 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4782 static const WCHAR szEstimatedSize[] =
4783 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4784 static const WCHAR szProductLanguage[] =
4785 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4786 static const WCHAR szProductVersion[] =
4787 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4788 static const WCHAR szDisplayVersion[] =
4789 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4790 static const WCHAR szInstallSource[] =
4791 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4792 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4793 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4794 static const WCHAR szAuthorizedCDFPrefix[] =
4795 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4796 static const WCHAR szARPCONTACT[] =
4797 {'A','R','P','C','O','N','T','A','C','T',0};
4798 static const WCHAR szContact[] =
4799 {'C','o','n','t','a','c','t',0};
4800 static const WCHAR szARPCOMMENTS[] =
4801 {'A','R','P','C','O','M','M','E','N','T','S',0};
4802 static const WCHAR szComments[] =
4803 {'C','o','m','m','e','n','t','s',0};
4804 static const WCHAR szProductName[] =
4805 {'P','r','o','d','u','c','t','N','a','m','e',0};
4806 static const WCHAR szDisplayName[] =
4807 {'D','i','s','p','l','a','y','N','a','m','e',0};
4808 static const WCHAR szARPHELPLINK[] =
4809 {'A','R','P','H','E','L','P','L','I','N','K',0};
4810 static const WCHAR szHelpLink[] =
4811 {'H','e','l','p','L','i','n','k',0};
4812 static const WCHAR szARPHELPTELEPHONE[] =
4813 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4814 static const WCHAR szHelpTelephone[] =
4815 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4816 static const WCHAR szARPINSTALLLOCATION[] =
4817 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4818 static const WCHAR szInstallLocation[] =
4819 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4820 static const WCHAR szManufacturer[] =
4821 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4822 static const WCHAR szPublisher[] =
4823 {'P','u','b','l','i','s','h','e','r',0};
4824 static const WCHAR szARPREADME[] =
4825 {'A','R','P','R','E','A','D','M','E',0};
4826 static const WCHAR szReadme[] =
4827 {'R','e','a','d','M','e',0};
4828 static const WCHAR szARPSIZE[] =
4829 {'A','R','P','S','I','Z','E',0};
4830 static const WCHAR szSize[] =
4831 {'S','i','z','e',0};
4832 static const WCHAR szARPURLINFOABOUT[] =
4833 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4834 static const WCHAR szURLInfoAbout[] =
4835 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4836 static const WCHAR szARPURLUPDATEINFO[] =
4837 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4838 static const WCHAR szURLUpdateInfo[] =
4839 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4841 static const WCHAR *propval[] = {
4842 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4843 szARPCONTACT, szContact,
4844 szARPCOMMENTS, szComments,
4845 szProductName, szDisplayName,
4846 szARPHELPLINK, szHelpLink,
4847 szARPHELPTELEPHONE, szHelpTelephone,
4848 szARPINSTALLLOCATION, szInstallLocation,
4849 cszSourceDir, szInstallSource,
4850 szManufacturer, szPublisher,
4851 szARPREADME, szReadme,
4853 szARPURLINFOABOUT, szURLInfoAbout,
4854 szARPURLUPDATEINFO, szURLUpdateInfo,
4857 const WCHAR **p = propval;
4863 val = msi_dup_property(package->db, prop);
4864 msi_reg_set_val_str(hkey, key, val);
4868 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4870 size = deformat_string(package, modpath_fmt, &buffer);
4871 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4872 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4875 /* FIXME: Write real Estimated Size when we have it */
4876 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4878 GetLocalTime(&systime);
4879 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4880 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4882 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4883 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4885 buffer = msi_dup_property(package->db, szProductVersion);
4886 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4889 DWORD verdword = msi_version_str_to_dword(buffer);
4891 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4892 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4893 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4897 return ERROR_SUCCESS;
4900 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4902 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4904 LPWSTR upgrade_code;
4909 /* FIXME: also need to publish if the product is in advertise mode */
4910 if (!msi_check_publish(package))
4911 return ERROR_SUCCESS;
4913 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4914 if (rc != ERROR_SUCCESS)
4917 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4918 NULL, &props, TRUE);
4919 if (rc != ERROR_SUCCESS)
4922 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4923 msi_free( package->db->localfile );
4924 package->db->localfile = NULL;
4926 rc = msi_publish_install_properties(package, hkey);
4927 if (rc != ERROR_SUCCESS)
4930 rc = msi_publish_install_properties(package, props);
4931 if (rc != ERROR_SUCCESS)
4934 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4937 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4938 squash_guid(package->ProductCode, squashed_pc);
4939 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4940 RegCloseKey(upgrade);
4941 msi_free(upgrade_code);
4945 uirow = MSI_CreateRecord( 1 );
4946 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4947 ui_actiondata( package, szRegisterProduct, uirow );
4948 msiobj_release( &uirow->hdr );
4951 return ERROR_SUCCESS;
4954 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4956 return execute_script(package,INSTALL_SCRIPT);
4959 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4961 WCHAR *upgrade, **features;
4962 BOOL full_uninstall = TRUE;
4963 MSIFEATURE *feature;
4964 MSIPATCHINFO *patch;
4966 static const WCHAR szUpgradeCode[] =
4967 {'U','p','g','r','a','d','e','C','o','d','e',0};
4969 features = msi_split_string(remove, ',');
4972 ERR("REMOVE feature list is empty!\n");
4973 return ERROR_FUNCTION_FAILED;
4976 if (!strcmpW( features[0], szAll ))
4977 full_uninstall = TRUE;
4980 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4982 if (feature->Action != INSTALLSTATE_ABSENT)
4983 full_uninstall = FALSE;
4988 if (!full_uninstall)
4989 return ERROR_SUCCESS;
4991 MSIREG_DeleteProductKey(package->ProductCode);
4992 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4993 MSIREG_DeleteUninstallKey(package);
4995 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4997 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4998 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5002 MSIREG_DeleteUserProductKey(package->ProductCode);
5003 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5006 upgrade = msi_dup_property(package->db, szUpgradeCode);
5009 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5013 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5015 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5018 return ERROR_SUCCESS;
5021 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5026 /* turn off scheduling */
5027 package->script->CurrentlyScripting= FALSE;
5029 /* first do the same as an InstallExecute */
5030 rc = ACTION_InstallExecute(package);
5031 if (rc != ERROR_SUCCESS)
5034 /* then handle Commit Actions */
5035 rc = execute_script(package,COMMIT_SCRIPT);
5036 if (rc != ERROR_SUCCESS)
5039 remove = msi_dup_property(package->db, szRemove);
5041 rc = msi_unpublish_product(package, remove);
5047 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5049 static const WCHAR RunOnce[] = {
5050 'S','o','f','t','w','a','r','e','\\',
5051 'M','i','c','r','o','s','o','f','t','\\',
5052 'W','i','n','d','o','w','s','\\',
5053 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5054 'R','u','n','O','n','c','e',0};
5055 static const WCHAR InstallRunOnce[] = {
5056 'S','o','f','t','w','a','r','e','\\',
5057 'M','i','c','r','o','s','o','f','t','\\',
5058 'W','i','n','d','o','w','s','\\',
5059 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5060 'I','n','s','t','a','l','l','e','r','\\',
5061 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5063 static const WCHAR msiexec_fmt[] = {
5065 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5066 '\"','%','s','\"',0};
5067 static const WCHAR install_fmt[] = {
5068 '/','I',' ','\"','%','s','\"',' ',
5069 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5070 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5071 WCHAR buffer[256], sysdir[MAX_PATH];
5073 WCHAR squished_pc[100];
5075 squash_guid(package->ProductCode,squished_pc);
5077 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5078 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5079 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5082 msi_reg_set_val_str( hkey, squished_pc, buffer );
5085 TRACE("Reboot command %s\n",debugstr_w(buffer));
5087 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5088 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5090 msi_reg_set_val_str( hkey, squished_pc, buffer );
5093 return ERROR_INSTALL_SUSPEND;
5096 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5102 * We are currently doing what should be done here in the top level Install
5103 * however for Administrative and uninstalls this step will be needed
5105 if (!package->PackagePath)
5106 return ERROR_SUCCESS;
5108 msi_set_sourcedir_props(package, TRUE);
5110 attrib = GetFileAttributesW(package->db->path);
5111 if (attrib == INVALID_FILE_ATTRIBUTES)
5117 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5118 package->Context, MSICODE_PRODUCT,
5119 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5120 if (rc == ERROR_MORE_DATA)
5122 prompt = msi_alloc(size * sizeof(WCHAR));
5123 MsiSourceListGetInfoW(package->ProductCode, NULL,
5124 package->Context, MSICODE_PRODUCT,
5125 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5128 prompt = strdupW(package->db->path);
5130 msg = generate_error_string(package,1302,1,prompt);
5131 while(attrib == INVALID_FILE_ATTRIBUTES)
5133 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5136 rc = ERROR_INSTALL_USEREXIT;
5139 attrib = GetFileAttributesW(package->db->path);
5145 return ERROR_SUCCESS;
5150 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5153 LPWSTR buffer, productid = NULL;
5154 UINT i, rc = ERROR_SUCCESS;
5157 static const WCHAR szPropKeys[][80] =
5159 {'P','r','o','d','u','c','t','I','D',0},
5160 {'U','S','E','R','N','A','M','E',0},
5161 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5165 static const WCHAR szRegKeys[][80] =
5167 {'P','r','o','d','u','c','t','I','D',0},
5168 {'R','e','g','O','w','n','e','r',0},
5169 {'R','e','g','C','o','m','p','a','n','y',0},
5173 if (msi_check_unpublish(package))
5175 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5179 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5183 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5185 if (rc != ERROR_SUCCESS)
5188 for( i = 0; szPropKeys[i][0]; i++ )
5190 buffer = msi_dup_property( package->db, szPropKeys[i] );
5191 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5196 uirow = MSI_CreateRecord( 1 );
5197 MSI_RecordSetStringW( uirow, 1, productid );
5198 ui_actiondata( package, szRegisterUser, uirow );
5199 msiobj_release( &uirow->hdr );
5201 msi_free(productid);
5207 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5211 package->script->InWhatSequence |= SEQUENCE_EXEC;
5212 rc = ACTION_ProcessExecSequence(package,FALSE);
5217 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5219 MSIPACKAGE *package = param;
5220 LPCWSTR compgroupid, component, feature, qualifier, text;
5221 LPWSTR advertise = NULL, output = NULL;
5229 feature = MSI_RecordGetString(rec, 5);
5230 feat = get_loaded_feature(package, feature);
5232 return ERROR_SUCCESS;
5234 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5235 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5236 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5238 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5239 feat->Action = feat->Installed;
5240 return ERROR_SUCCESS;
5243 component = MSI_RecordGetString(rec, 3);
5244 comp = get_loaded_component(package, component);
5246 return ERROR_SUCCESS;
5248 compgroupid = MSI_RecordGetString(rec,1);
5249 qualifier = MSI_RecordGetString(rec,2);
5251 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5252 if (rc != ERROR_SUCCESS)
5255 text = MSI_RecordGetString(rec,4);
5256 advertise = create_component_advertise_string(package, comp, feature);
5258 sz = strlenW(advertise);
5261 sz += lstrlenW(text);
5264 sz *= sizeof(WCHAR);
5266 output = msi_alloc_zero(sz);
5267 strcpyW(output,advertise);
5268 msi_free(advertise);
5271 strcatW(output,text);
5273 msi_reg_set_val_multi_str( hkey, qualifier, output );
5280 uirow = MSI_CreateRecord( 2 );
5281 MSI_RecordSetStringW( uirow, 1, compgroupid );
5282 MSI_RecordSetStringW( uirow, 2, qualifier);
5283 ui_actiondata( package, szPublishComponents, uirow);
5284 msiobj_release( &uirow->hdr );
5285 /* FIXME: call ui_progress? */
5291 * At present I am ignorning the advertised components part of this and only
5292 * focusing on the qualified component sets
5294 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5298 static const WCHAR ExecSeqQuery[] =
5299 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5300 '`','P','u','b','l','i','s','h',
5301 'C','o','m','p','o','n','e','n','t','`',0};
5303 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5304 if (rc != ERROR_SUCCESS)
5305 return ERROR_SUCCESS;
5307 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5308 msiobj_release(&view->hdr);
5313 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5315 static const WCHAR szInstallerComponents[] = {
5316 'S','o','f','t','w','a','r','e','\\',
5317 'M','i','c','r','o','s','o','f','t','\\',
5318 'I','n','s','t','a','l','l','e','r','\\',
5319 'C','o','m','p','o','n','e','n','t','s','\\',0};
5321 MSIPACKAGE *package = param;
5322 LPCWSTR compgroupid, component, feature, qualifier;
5326 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5329 feature = MSI_RecordGetString( rec, 5 );
5330 feat = get_loaded_feature( package, feature );
5332 return ERROR_SUCCESS;
5334 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5336 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5337 feat->Action = feat->Installed;
5338 return ERROR_SUCCESS;
5341 component = MSI_RecordGetString( rec, 3 );
5342 comp = get_loaded_component( package, component );
5344 return ERROR_SUCCESS;
5346 compgroupid = MSI_RecordGetString( rec, 1 );
5347 qualifier = MSI_RecordGetString( rec, 2 );
5349 squash_guid( compgroupid, squashed );
5350 strcpyW( keypath, szInstallerComponents );
5351 strcatW( keypath, squashed );
5353 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5354 if (res != ERROR_SUCCESS)
5356 WARN("Unable to delete component key %d\n", res);
5359 uirow = MSI_CreateRecord( 2 );
5360 MSI_RecordSetStringW( uirow, 1, compgroupid );
5361 MSI_RecordSetStringW( uirow, 2, qualifier );
5362 ui_actiondata( package, szUnpublishComponents, uirow );
5363 msiobj_release( &uirow->hdr );
5365 return ERROR_SUCCESS;
5368 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5372 static const WCHAR query[] =
5373 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5374 '`','P','u','b','l','i','s','h',
5375 'C','o','m','p','o','n','e','n','t','`',0};
5377 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5378 if (rc != ERROR_SUCCESS)
5379 return ERROR_SUCCESS;
5381 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5382 msiobj_release( &view->hdr );
5387 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5389 MSIPACKAGE *package = param;
5392 SC_HANDLE hscm, service = NULL;
5394 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5395 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5396 DWORD serv_type, start_type, err_control;
5397 SERVICE_DESCRIPTIONW sd = {NULL};
5399 static const WCHAR query[] =
5400 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5401 '`','C','o','m','p','o','n','e','n','t','`',' ',
5402 'W','H','E','R','E',' ',
5403 '`','C','o','m','p','o','n','e','n','t','`',' ',
5404 '=','\'','%','s','\'',0};
5406 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5409 ERR("Failed to open the SC Manager!\n");
5413 start_type = MSI_RecordGetInteger(rec, 5);
5414 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5417 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5418 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5419 serv_type = MSI_RecordGetInteger(rec, 4);
5420 err_control = MSI_RecordGetInteger(rec, 6);
5421 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5422 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5423 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5424 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5425 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5426 comp = MSI_RecordGetString(rec, 12);
5427 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5429 /* fetch the service path */
5430 row = MSI_QueryGetRecord(package->db, query, comp);
5433 ERR("Control query failed!\n");
5436 key = MSI_RecordGetString(row, 6);
5438 file = get_loaded_file(package, key);
5439 msiobj_release(&row->hdr);
5442 ERR("Failed to load the service file\n");
5446 if (!args || !args[0]) image_path = file->TargetPath;
5449 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5450 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5451 return ERROR_OUTOFMEMORY;
5453 strcpyW(image_path, file->TargetPath);
5454 strcatW(image_path, szSpace);
5455 strcatW(image_path, args);
5457 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5458 start_type, err_control, image_path, load_order,
5459 NULL, depends, serv_name, pass);
5463 if (GetLastError() != ERROR_SERVICE_EXISTS)
5464 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5466 else if (sd.lpDescription)
5468 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5469 WARN("failed to set service description %u\n", GetLastError());
5472 if (image_path != file->TargetPath) msi_free(image_path);
5474 CloseServiceHandle(service);
5475 CloseServiceHandle(hscm);
5478 msi_free(sd.lpDescription);
5479 msi_free(load_order);
5480 msi_free(serv_name);
5485 return ERROR_SUCCESS;
5488 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5492 static const WCHAR ExecSeqQuery[] =
5493 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5494 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5496 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5497 if (rc != ERROR_SUCCESS)
5498 return ERROR_SUCCESS;
5500 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5501 msiobj_release(&view->hdr);
5506 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5507 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5509 LPCWSTR *vector, *temp_vector;
5513 static const WCHAR separator[] = {'[','~',']',0};
5516 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5521 vector = msi_alloc(sizeof(LPWSTR));
5529 vector[*numargs - 1] = p;
5531 if ((q = strstrW(p, separator)))
5535 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5541 vector = temp_vector;
5550 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5552 MSIPACKAGE *package = param;
5555 SC_HANDLE scm = NULL, service = NULL;
5556 LPCWSTR component, *vector = NULL;
5557 LPWSTR name, args, display_name = NULL;
5558 DWORD event, numargs, len;
5559 UINT r = ERROR_FUNCTION_FAILED;
5561 component = MSI_RecordGetString(rec, 6);
5562 comp = get_loaded_component(package, component);
5564 return ERROR_SUCCESS;
5568 TRACE("component is disabled\n");
5569 return ERROR_SUCCESS;
5572 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5574 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5575 comp->Action = comp->Installed;
5576 return ERROR_SUCCESS;
5578 comp->Action = INSTALLSTATE_LOCAL;
5580 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5581 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5582 event = MSI_RecordGetInteger(rec, 3);
5584 if (!(event & msidbServiceControlEventStart))
5590 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5593 ERR("Failed to open the service control manager\n");
5598 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5599 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5601 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5602 GetServiceDisplayNameW( scm, name, display_name, &len );
5605 service = OpenServiceW(scm, name, SERVICE_START);
5608 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5612 vector = msi_service_args_to_vector(args, &numargs);
5614 if (!StartServiceW(service, numargs, vector) &&
5615 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5617 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5624 uirow = MSI_CreateRecord( 2 );
5625 MSI_RecordSetStringW( uirow, 1, display_name );
5626 MSI_RecordSetStringW( uirow, 2, name );
5627 ui_actiondata( package, szStartServices, uirow );
5628 msiobj_release( &uirow->hdr );
5630 CloseServiceHandle(service);
5631 CloseServiceHandle(scm);
5636 msi_free(display_name);
5640 static UINT ACTION_StartServices( MSIPACKAGE *package )
5645 static const WCHAR query[] = {
5646 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5647 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5649 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5650 if (rc != ERROR_SUCCESS)
5651 return ERROR_SUCCESS;
5653 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5654 msiobj_release(&view->hdr);
5659 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5661 DWORD i, needed, count;
5662 ENUM_SERVICE_STATUSW *dependencies;
5666 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5667 0, &needed, &count))
5670 if (GetLastError() != ERROR_MORE_DATA)
5673 dependencies = msi_alloc(needed);
5677 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5678 needed, &needed, &count))
5681 for (i = 0; i < count; i++)
5683 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5684 SERVICE_STOP | SERVICE_QUERY_STATUS);
5688 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5695 msi_free(dependencies);
5699 static UINT stop_service( LPCWSTR name )
5701 SC_HANDLE scm = NULL, service = NULL;
5702 SERVICE_STATUS status;
5703 SERVICE_STATUS_PROCESS ssp;
5706 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5709 WARN("Failed to open the SCM: %d\n", GetLastError());
5713 service = OpenServiceW(scm, name,
5715 SERVICE_QUERY_STATUS |
5716 SERVICE_ENUMERATE_DEPENDENTS);
5719 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5723 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5724 sizeof(SERVICE_STATUS_PROCESS), &needed))
5726 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5730 if (ssp.dwCurrentState == SERVICE_STOPPED)
5733 stop_service_dependents(scm, service);
5735 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5736 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5739 CloseServiceHandle(service);
5740 CloseServiceHandle(scm);
5742 return ERROR_SUCCESS;
5745 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5747 MSIPACKAGE *package = param;
5751 LPWSTR name = NULL, display_name = NULL;
5755 event = MSI_RecordGetInteger( rec, 3 );
5756 if (!(event & msidbServiceControlEventStop))
5757 return ERROR_SUCCESS;
5759 component = MSI_RecordGetString( rec, 6 );
5760 comp = get_loaded_component( package, component );
5762 return ERROR_SUCCESS;
5766 TRACE("component is disabled\n");
5767 return ERROR_SUCCESS;
5770 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5772 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5773 comp->Action = comp->Installed;
5774 return ERROR_SUCCESS;
5776 comp->Action = INSTALLSTATE_ABSENT;
5778 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5781 ERR("Failed to open the service control manager\n");
5786 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5787 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5789 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5790 GetServiceDisplayNameW( scm, name, display_name, &len );
5792 CloseServiceHandle( scm );
5794 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5795 stop_service( name );
5798 uirow = MSI_CreateRecord( 2 );
5799 MSI_RecordSetStringW( uirow, 1, display_name );
5800 MSI_RecordSetStringW( uirow, 2, name );
5801 ui_actiondata( package, szStopServices, uirow );
5802 msiobj_release( &uirow->hdr );
5805 msi_free( display_name );
5806 return ERROR_SUCCESS;
5809 static UINT ACTION_StopServices( MSIPACKAGE *package )
5814 static const WCHAR query[] = {
5815 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5816 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5818 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5819 if (rc != ERROR_SUCCESS)
5820 return ERROR_SUCCESS;
5822 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5823 msiobj_release(&view->hdr);
5828 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5830 MSIPACKAGE *package = param;
5834 LPWSTR name = NULL, display_name = NULL;
5836 SC_HANDLE scm = NULL, service = NULL;
5838 event = MSI_RecordGetInteger( rec, 3 );
5839 if (!(event & msidbServiceControlEventDelete))
5840 return ERROR_SUCCESS;
5842 component = MSI_RecordGetString(rec, 6);
5843 comp = get_loaded_component(package, component);
5845 return ERROR_SUCCESS;
5849 TRACE("component is disabled\n");
5850 return ERROR_SUCCESS;
5853 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5855 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5856 comp->Action = comp->Installed;
5857 return ERROR_SUCCESS;
5859 comp->Action = INSTALLSTATE_ABSENT;
5861 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5862 stop_service( name );
5864 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5867 WARN("Failed to open the SCM: %d\n", GetLastError());
5872 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5873 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5875 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5876 GetServiceDisplayNameW( scm, name, display_name, &len );
5879 service = OpenServiceW( scm, name, DELETE );
5882 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5886 if (!DeleteService( service ))
5887 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5890 uirow = MSI_CreateRecord( 2 );
5891 MSI_RecordSetStringW( uirow, 1, display_name );
5892 MSI_RecordSetStringW( uirow, 2, name );
5893 ui_actiondata( package, szDeleteServices, uirow );
5894 msiobj_release( &uirow->hdr );
5896 CloseServiceHandle( service );
5897 CloseServiceHandle( scm );
5899 msi_free( display_name );
5901 return ERROR_SUCCESS;
5904 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5909 static const WCHAR query[] = {
5910 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5911 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5913 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5914 if (rc != ERROR_SUCCESS)
5915 return ERROR_SUCCESS;
5917 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5918 msiobj_release( &view->hdr );
5923 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5925 MSIPACKAGE *package = param;
5926 LPWSTR driver, driver_path, ptr;
5927 WCHAR outpath[MAX_PATH];
5928 MSIFILE *driver_file = NULL, *setup_file = NULL;
5930 LPCWSTR desc, file_key;
5932 UINT r = ERROR_SUCCESS;
5934 static const WCHAR driver_fmt[] = {
5935 'D','r','i','v','e','r','=','%','s',0};
5936 static const WCHAR setup_fmt[] = {
5937 'S','e','t','u','p','=','%','s',0};
5938 static const WCHAR usage_fmt[] = {
5939 'F','i','l','e','U','s','a','g','e','=','1',0};
5941 desc = MSI_RecordGetString(rec, 3);
5943 file_key = MSI_RecordGetString( rec, 4 );
5944 if (file_key) driver_file = get_loaded_file( package, file_key );
5946 file_key = MSI_RecordGetString( rec, 5 );
5947 if (file_key) setup_file = get_loaded_file( package, file_key );
5951 ERR("ODBC Driver entry not found!\n");
5952 return ERROR_FUNCTION_FAILED;
5955 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5957 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5958 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5960 driver = msi_alloc(len * sizeof(WCHAR));
5962 return ERROR_OUTOFMEMORY;
5965 lstrcpyW(ptr, desc);
5966 ptr += lstrlenW(ptr) + 1;
5968 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5973 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5977 lstrcpyW(ptr, usage_fmt);
5978 ptr += lstrlenW(ptr) + 1;
5981 driver_path = strdupW(driver_file->TargetPath);
5982 ptr = strrchrW(driver_path, '\\');
5983 if (ptr) *ptr = '\0';
5985 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5986 NULL, ODBC_INSTALL_COMPLETE, &usage))
5988 ERR("Failed to install SQL driver!\n");
5989 r = ERROR_FUNCTION_FAILED;
5992 uirow = MSI_CreateRecord( 5 );
5993 MSI_RecordSetStringW( uirow, 1, desc );
5994 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5995 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5996 ui_actiondata( package, szInstallODBC, uirow );
5997 msiobj_release( &uirow->hdr );
6000 msi_free(driver_path);
6005 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6007 MSIPACKAGE *package = param;
6008 LPWSTR translator, translator_path, ptr;
6009 WCHAR outpath[MAX_PATH];
6010 MSIFILE *translator_file = NULL, *setup_file = NULL;
6012 LPCWSTR desc, file_key;
6014 UINT r = ERROR_SUCCESS;
6016 static const WCHAR translator_fmt[] = {
6017 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6018 static const WCHAR setup_fmt[] = {
6019 'S','e','t','u','p','=','%','s',0};
6021 desc = MSI_RecordGetString(rec, 3);
6023 file_key = MSI_RecordGetString( rec, 4 );
6024 if (file_key) translator_file = get_loaded_file( package, file_key );
6026 file_key = MSI_RecordGetString( rec, 5 );
6027 if (file_key) setup_file = get_loaded_file( package, file_key );
6029 if (!translator_file)
6031 ERR("ODBC Translator entry not found!\n");
6032 return ERROR_FUNCTION_FAILED;
6035 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6037 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6039 translator = msi_alloc(len * sizeof(WCHAR));
6041 return ERROR_OUTOFMEMORY;
6044 lstrcpyW(ptr, desc);
6045 ptr += lstrlenW(ptr) + 1;
6047 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6052 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6057 translator_path = strdupW(translator_file->TargetPath);
6058 ptr = strrchrW(translator_path, '\\');
6059 if (ptr) *ptr = '\0';
6061 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6062 NULL, ODBC_INSTALL_COMPLETE, &usage))
6064 ERR("Failed to install SQL translator!\n");
6065 r = ERROR_FUNCTION_FAILED;
6068 uirow = MSI_CreateRecord( 5 );
6069 MSI_RecordSetStringW( uirow, 1, desc );
6070 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6071 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6072 ui_actiondata( package, szInstallODBC, uirow );
6073 msiobj_release( &uirow->hdr );
6075 msi_free(translator);
6076 msi_free(translator_path);
6081 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6083 MSIPACKAGE *package = param;
6085 LPCWSTR desc, driver;
6086 WORD request = ODBC_ADD_SYS_DSN;
6089 UINT r = ERROR_SUCCESS;
6092 static const WCHAR attrs_fmt[] = {
6093 'D','S','N','=','%','s',0 };
6095 desc = MSI_RecordGetString(rec, 3);
6096 driver = MSI_RecordGetString(rec, 4);
6097 registration = MSI_RecordGetInteger(rec, 5);
6099 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6100 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6102 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6103 attrs = msi_alloc(len * sizeof(WCHAR));
6105 return ERROR_OUTOFMEMORY;
6107 len = sprintfW(attrs, attrs_fmt, desc);
6110 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6112 ERR("Failed to install SQL data source!\n");
6113 r = ERROR_FUNCTION_FAILED;
6116 uirow = MSI_CreateRecord( 5 );
6117 MSI_RecordSetStringW( uirow, 1, desc );
6118 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6119 MSI_RecordSetInteger( uirow, 3, request );
6120 ui_actiondata( package, szInstallODBC, uirow );
6121 msiobj_release( &uirow->hdr );
6128 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6133 static const WCHAR driver_query[] = {
6134 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6135 'O','D','B','C','D','r','i','v','e','r',0 };
6137 static const WCHAR translator_query[] = {
6138 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6139 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6141 static const WCHAR source_query[] = {
6142 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6143 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6145 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6146 if (rc != ERROR_SUCCESS)
6147 return ERROR_SUCCESS;
6149 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6150 msiobj_release(&view->hdr);
6152 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6153 if (rc != ERROR_SUCCESS)
6154 return ERROR_SUCCESS;
6156 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6157 msiobj_release(&view->hdr);
6159 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6160 if (rc != ERROR_SUCCESS)
6161 return ERROR_SUCCESS;
6163 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6164 msiobj_release(&view->hdr);
6169 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6171 MSIPACKAGE *package = param;
6176 desc = MSI_RecordGetString( rec, 3 );
6177 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6179 WARN("Failed to remove ODBC driver\n");
6183 FIXME("Usage count reached 0\n");
6186 uirow = MSI_CreateRecord( 2 );
6187 MSI_RecordSetStringW( uirow, 1, desc );
6188 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6189 ui_actiondata( package, szRemoveODBC, uirow );
6190 msiobj_release( &uirow->hdr );
6192 return ERROR_SUCCESS;
6195 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6197 MSIPACKAGE *package = param;
6202 desc = MSI_RecordGetString( rec, 3 );
6203 if (!SQLRemoveTranslatorW( desc, &usage ))
6205 WARN("Failed to remove ODBC translator\n");
6209 FIXME("Usage count reached 0\n");
6212 uirow = MSI_CreateRecord( 2 );
6213 MSI_RecordSetStringW( uirow, 1, desc );
6214 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6215 ui_actiondata( package, szRemoveODBC, uirow );
6216 msiobj_release( &uirow->hdr );
6218 return ERROR_SUCCESS;
6221 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6223 MSIPACKAGE *package = param;
6226 LPCWSTR desc, driver;
6227 WORD request = ODBC_REMOVE_SYS_DSN;
6231 static const WCHAR attrs_fmt[] = {
6232 'D','S','N','=','%','s',0 };
6234 desc = MSI_RecordGetString( rec, 3 );
6235 driver = MSI_RecordGetString( rec, 4 );
6236 registration = MSI_RecordGetInteger( rec, 5 );
6238 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6239 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6241 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6242 attrs = msi_alloc( len * sizeof(WCHAR) );
6244 return ERROR_OUTOFMEMORY;
6246 FIXME("Use ODBCSourceAttribute table\n");
6248 len = sprintfW( attrs, attrs_fmt, desc );
6251 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6253 WARN("Failed to remove ODBC data source\n");
6257 uirow = MSI_CreateRecord( 3 );
6258 MSI_RecordSetStringW( uirow, 1, desc );
6259 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6260 MSI_RecordSetInteger( uirow, 3, request );
6261 ui_actiondata( package, szRemoveODBC, uirow );
6262 msiobj_release( &uirow->hdr );
6264 return ERROR_SUCCESS;
6267 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6272 static const WCHAR driver_query[] = {
6273 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6274 'O','D','B','C','D','r','i','v','e','r',0 };
6276 static const WCHAR translator_query[] = {
6277 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6278 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6280 static const WCHAR source_query[] = {
6281 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6282 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6284 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6285 if (rc != ERROR_SUCCESS)
6286 return ERROR_SUCCESS;
6288 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6289 msiobj_release( &view->hdr );
6291 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6292 if (rc != ERROR_SUCCESS)
6293 return ERROR_SUCCESS;
6295 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6296 msiobj_release( &view->hdr );
6298 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6299 if (rc != ERROR_SUCCESS)
6300 return ERROR_SUCCESS;
6302 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6303 msiobj_release( &view->hdr );
6308 #define ENV_ACT_SETALWAYS 0x1
6309 #define ENV_ACT_SETABSENT 0x2
6310 #define ENV_ACT_REMOVE 0x4
6311 #define ENV_ACT_REMOVEMATCH 0x8
6313 #define ENV_MOD_MACHINE 0x20000000
6314 #define ENV_MOD_APPEND 0x40000000
6315 #define ENV_MOD_PREFIX 0x80000000
6316 #define ENV_MOD_MASK 0xC0000000
6318 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6320 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6322 LPCWSTR cptr = *name;
6324 static const WCHAR prefix[] = {'[','~',']',0};
6325 static const int prefix_len = 3;
6331 *flags |= ENV_ACT_SETALWAYS;
6332 else if (*cptr == '+')
6333 *flags |= ENV_ACT_SETABSENT;
6334 else if (*cptr == '-')
6335 *flags |= ENV_ACT_REMOVE;
6336 else if (*cptr == '!')
6337 *flags |= ENV_ACT_REMOVEMATCH;
6338 else if (*cptr == '*')
6339 *flags |= ENV_MOD_MACHINE;
6349 ERR("Missing environment variable\n");
6350 return ERROR_FUNCTION_FAILED;
6355 LPCWSTR ptr = *value;
6356 if (!strncmpW(ptr, prefix, prefix_len))
6358 if (ptr[prefix_len] == szSemiColon[0])
6360 *flags |= ENV_MOD_APPEND;
6361 *value += lstrlenW(prefix);
6368 else if (lstrlenW(*value) >= prefix_len)
6370 ptr += lstrlenW(ptr) - prefix_len;
6371 if (!strcmpW( ptr, prefix ))
6373 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6375 *flags |= ENV_MOD_PREFIX;
6376 /* the "[~]" will be removed by deformat_string */;
6386 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6387 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6388 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6389 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6391 ERR("Invalid flags: %08x\n", *flags);
6392 return ERROR_FUNCTION_FAILED;
6396 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6398 return ERROR_SUCCESS;
6401 static UINT open_env_key( DWORD flags, HKEY *key )
6403 static const WCHAR user_env[] =
6404 {'E','n','v','i','r','o','n','m','e','n','t',0};
6405 static const WCHAR machine_env[] =
6406 {'S','y','s','t','e','m','\\',
6407 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6408 'C','o','n','t','r','o','l','\\',
6409 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6410 'E','n','v','i','r','o','n','m','e','n','t',0};
6415 if (flags & ENV_MOD_MACHINE)
6418 root = HKEY_LOCAL_MACHINE;
6423 root = HKEY_CURRENT_USER;
6426 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6427 if (res != ERROR_SUCCESS)
6429 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6430 return ERROR_FUNCTION_FAILED;
6433 return ERROR_SUCCESS;
6436 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6438 MSIPACKAGE *package = param;
6439 LPCWSTR name, value, component;
6440 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6441 DWORD flags, type, size;
6448 component = MSI_RecordGetString(rec, 4);
6449 comp = get_loaded_component(package, component);
6451 return ERROR_SUCCESS;
6455 TRACE("component is disabled\n");
6456 return ERROR_SUCCESS;
6459 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6461 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6462 comp->Action = comp->Installed;
6463 return ERROR_SUCCESS;
6465 comp->Action = INSTALLSTATE_LOCAL;
6467 name = MSI_RecordGetString(rec, 2);
6468 value = MSI_RecordGetString(rec, 3);
6470 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6472 res = env_parse_flags(&name, &value, &flags);
6473 if (res != ERROR_SUCCESS || !value)
6476 if (value && !deformat_string(package, value, &deformatted))
6478 res = ERROR_OUTOFMEMORY;
6482 value = deformatted;
6484 res = open_env_key( flags, &env );
6485 if (res != ERROR_SUCCESS)
6488 if (flags & ENV_MOD_MACHINE)
6489 action |= 0x20000000;
6493 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6494 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6495 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6498 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6502 /* Nothing to do. */
6505 res = ERROR_SUCCESS;
6509 /* If we are appending but the string was empty, strip ; */
6510 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6512 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6513 newval = strdupW(value);
6516 res = ERROR_OUTOFMEMORY;
6524 /* Contrary to MSDN, +-variable to [~];path works */
6525 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6527 res = ERROR_SUCCESS;
6531 data = msi_alloc(size);
6535 return ERROR_OUTOFMEMORY;
6538 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6539 if (res != ERROR_SUCCESS)
6542 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6545 res = RegDeleteValueW(env, name);
6546 if (res != ERROR_SUCCESS)
6547 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6551 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6552 if (flags & ENV_MOD_MASK)
6556 if (flags & ENV_MOD_APPEND) multiplier++;
6557 if (flags & ENV_MOD_PREFIX) multiplier++;
6558 mod_size = lstrlenW(value) * multiplier;
6559 size += mod_size * sizeof(WCHAR);
6562 newval = msi_alloc(size);
6566 res = ERROR_OUTOFMEMORY;
6570 if (flags & ENV_MOD_PREFIX)
6572 lstrcpyW(newval, value);
6573 ptr = newval + lstrlenW(value);
6574 action |= 0x80000000;
6577 lstrcpyW(ptr, data);
6579 if (flags & ENV_MOD_APPEND)
6581 lstrcatW(newval, value);
6582 action |= 0x40000000;
6585 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6586 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6589 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6593 uirow = MSI_CreateRecord( 3 );
6594 MSI_RecordSetStringW( uirow, 1, name );
6595 MSI_RecordSetStringW( uirow, 2, newval );
6596 MSI_RecordSetInteger( uirow, 3, action );
6597 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6598 msiobj_release( &uirow->hdr );
6600 if (env) RegCloseKey(env);
6601 msi_free(deformatted);
6607 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6611 static const WCHAR ExecSeqQuery[] =
6612 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6613 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6614 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6615 if (rc != ERROR_SUCCESS)
6616 return ERROR_SUCCESS;
6618 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6619 msiobj_release(&view->hdr);
6624 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6626 MSIPACKAGE *package = param;
6627 LPCWSTR name, value, component;
6628 LPWSTR deformatted = NULL;
6637 component = MSI_RecordGetString( rec, 4 );
6638 comp = get_loaded_component( package, component );
6640 return ERROR_SUCCESS;
6644 TRACE("component is disabled\n");
6645 return ERROR_SUCCESS;
6648 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6650 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6651 comp->Action = comp->Installed;
6652 return ERROR_SUCCESS;
6654 comp->Action = INSTALLSTATE_ABSENT;
6656 name = MSI_RecordGetString( rec, 2 );
6657 value = MSI_RecordGetString( rec, 3 );
6659 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6661 r = env_parse_flags( &name, &value, &flags );
6662 if (r != ERROR_SUCCESS)
6665 if (!(flags & ENV_ACT_REMOVE))
6667 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6668 return ERROR_SUCCESS;
6671 if (value && !deformat_string( package, value, &deformatted ))
6672 return ERROR_OUTOFMEMORY;
6674 value = deformatted;
6676 r = open_env_key( flags, &env );
6677 if (r != ERROR_SUCCESS)
6683 if (flags & ENV_MOD_MACHINE)
6684 action |= 0x20000000;
6686 TRACE("Removing %s\n", debugstr_w(name));
6688 res = RegDeleteValueW( env, name );
6689 if (res != ERROR_SUCCESS)
6691 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6696 uirow = MSI_CreateRecord( 3 );
6697 MSI_RecordSetStringW( uirow, 1, name );
6698 MSI_RecordSetStringW( uirow, 2, value );
6699 MSI_RecordSetInteger( uirow, 3, action );
6700 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6701 msiobj_release( &uirow->hdr );
6703 if (env) RegCloseKey( env );
6704 msi_free( deformatted );
6708 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6712 static const WCHAR query[] =
6713 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6714 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6716 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6717 if (rc != ERROR_SUCCESS)
6718 return ERROR_SUCCESS;
6720 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6721 msiobj_release( &view->hdr );
6726 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6728 LPWSTR key, template, id;
6729 UINT r = ERROR_SUCCESS;
6731 id = msi_dup_property( package->db, szProductID );
6735 return ERROR_SUCCESS;
6737 template = msi_dup_property( package->db, szPIDTemplate );
6738 key = msi_dup_property( package->db, szPIDKEY );
6740 if (key && template)
6742 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6743 r = msi_set_property( package->db, szProductID, key );
6745 msi_free( template );
6750 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6753 package->need_reboot = 1;
6754 return ERROR_SUCCESS;
6757 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6759 static const WCHAR szAvailableFreeReg[] =
6760 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6762 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6764 TRACE("%p %d kilobytes\n", package, space);
6766 uirow = MSI_CreateRecord( 1 );
6767 MSI_RecordSetInteger( uirow, 1, space );
6768 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6769 msiobj_release( &uirow->hdr );
6771 return ERROR_SUCCESS;
6774 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6776 FIXME("%p\n", package);
6777 return ERROR_SUCCESS;
6780 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6782 FIXME("%p\n", package);
6783 return ERROR_SUCCESS;
6786 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6791 static const WCHAR driver_query[] = {
6792 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6793 'O','D','B','C','D','r','i','v','e','r',0 };
6795 static const WCHAR translator_query[] = {
6796 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6797 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6799 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6800 if (r == ERROR_SUCCESS)
6803 r = MSI_IterateRecords( view, &count, NULL, package );
6804 msiobj_release( &view->hdr );
6805 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6808 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6809 if (r == ERROR_SUCCESS)
6812 r = MSI_IterateRecords( view, &count, NULL, package );
6813 msiobj_release( &view->hdr );
6814 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6817 return ERROR_SUCCESS;
6820 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6821 LPCSTR action, LPCWSTR table )
6823 static const WCHAR query[] = {
6824 'S','E','L','E','C','T',' ','*',' ',
6825 'F','R','O','M',' ','`','%','s','`',0 };
6826 MSIQUERY *view = NULL;
6830 r = MSI_OpenQuery( package->db, &view, query, table );
6831 if (r == ERROR_SUCCESS)
6833 r = MSI_IterateRecords(view, &count, NULL, package);
6834 msiobj_release(&view->hdr);
6838 FIXME("%s -> %u ignored %s table values\n",
6839 action, count, debugstr_w(table));
6841 return ERROR_SUCCESS;
6844 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6846 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6847 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6850 static UINT ACTION_BindImage( MSIPACKAGE *package )
6852 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6853 return msi_unimplemented_action_stub( package, "BindImage", table );
6856 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6858 static const WCHAR table[] = {
6859 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6860 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6863 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6865 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6866 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6869 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6871 static const WCHAR table[] = {
6872 'M','s','i','A','s','s','e','m','b','l','y',0 };
6873 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6876 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6878 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6879 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6882 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6884 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6885 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6888 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6890 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6891 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6894 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6896 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6897 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6900 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6902 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6903 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6906 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6910 const WCHAR *action;
6911 UINT (*handler)(MSIPACKAGE *);
6915 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6916 { szAppSearch, ACTION_AppSearch },
6917 { szBindImage, ACTION_BindImage },
6918 { szCCPSearch, ACTION_CCPSearch },
6919 { szCostFinalize, ACTION_CostFinalize },
6920 { szCostInitialize, ACTION_CostInitialize },
6921 { szCreateFolders, ACTION_CreateFolders },
6922 { szCreateShortcuts, ACTION_CreateShortcuts },
6923 { szDeleteServices, ACTION_DeleteServices },
6924 { szDisableRollback, ACTION_DisableRollback },
6925 { szDuplicateFiles, ACTION_DuplicateFiles },
6926 { szExecuteAction, ACTION_ExecuteAction },
6927 { szFileCost, ACTION_FileCost },
6928 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6929 { szForceReboot, ACTION_ForceReboot },
6930 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6931 { szInstallExecute, ACTION_InstallExecute },
6932 { szInstallExecuteAgain, ACTION_InstallExecute },
6933 { szInstallFiles, ACTION_InstallFiles},
6934 { szInstallFinalize, ACTION_InstallFinalize },
6935 { szInstallInitialize, ACTION_InstallInitialize },
6936 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6937 { szInstallValidate, ACTION_InstallValidate },
6938 { szIsolateComponents, ACTION_IsolateComponents },
6939 { szLaunchConditions, ACTION_LaunchConditions },
6940 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6941 { szMoveFiles, ACTION_MoveFiles },
6942 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6943 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6944 { szInstallODBC, ACTION_InstallODBC },
6945 { szInstallServices, ACTION_InstallServices },
6946 { szPatchFiles, ACTION_PatchFiles },
6947 { szProcessComponents, ACTION_ProcessComponents },
6948 { szPublishComponents, ACTION_PublishComponents },
6949 { szPublishFeatures, ACTION_PublishFeatures },
6950 { szPublishProduct, ACTION_PublishProduct },
6951 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6952 { szRegisterComPlus, ACTION_RegisterComPlus},
6953 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6954 { szRegisterFonts, ACTION_RegisterFonts },
6955 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6956 { szRegisterProduct, ACTION_RegisterProduct },
6957 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6958 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6959 { szRegisterUser, ACTION_RegisterUser },
6960 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6961 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6962 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6963 { szRemoveFiles, ACTION_RemoveFiles },
6964 { szRemoveFolders, ACTION_RemoveFolders },
6965 { szRemoveIniValues, ACTION_RemoveIniValues },
6966 { szRemoveODBC, ACTION_RemoveODBC },
6967 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6968 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6969 { szResolveSource, ACTION_ResolveSource },
6970 { szRMCCPSearch, ACTION_RMCCPSearch },
6971 { szScheduleReboot, ACTION_ScheduleReboot },
6972 { szSelfRegModules, ACTION_SelfRegModules },
6973 { szSelfUnregModules, ACTION_SelfUnregModules },
6974 { szSetODBCFolders, ACTION_SetODBCFolders },
6975 { szStartServices, ACTION_StartServices },
6976 { szStopServices, ACTION_StopServices },
6977 { szUnpublishComponents, ACTION_UnpublishComponents },
6978 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6979 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6980 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6981 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6982 { szUnregisterFonts, ACTION_UnregisterFonts },
6983 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6984 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6985 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6986 { szValidateProductID, ACTION_ValidateProductID },
6987 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6988 { szWriteIniValues, ACTION_WriteIniValues },
6989 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6993 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
6999 while (StandardActions[i].action != NULL)
7001 if (!strcmpW( StandardActions[i].action, action ))
7003 ui_actionstart( package, action );
7004 if (StandardActions[i].handler)
7006 ui_actioninfo( package, action, TRUE, 0 );
7007 *rc = StandardActions[i].handler( package );
7008 ui_actioninfo( package, action, FALSE, *rc );
7012 FIXME("unhandled standard action %s\n", debugstr_w(action));
7013 *rc = ERROR_SUCCESS;
7023 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7025 UINT rc = ERROR_SUCCESS;
7028 TRACE("Performing action (%s)\n", debugstr_w(action));
7030 handled = ACTION_HandleStandardAction(package, action, &rc);
7033 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7037 WARN("unhandled msi action %s\n", debugstr_w(action));
7038 rc = ERROR_FUNCTION_NOT_CALLED;
7044 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7046 UINT rc = ERROR_SUCCESS;
7047 BOOL handled = FALSE;
7049 TRACE("Performing action (%s)\n", debugstr_w(action));
7051 handled = ACTION_HandleStandardAction(package, action, &rc);
7054 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7056 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7061 WARN("unhandled msi action %s\n", debugstr_w(action));
7062 rc = ERROR_FUNCTION_NOT_CALLED;
7068 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7070 UINT rc = ERROR_SUCCESS;
7073 static const WCHAR ExecSeqQuery[] =
7074 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7075 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7076 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7077 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7078 static const WCHAR UISeqQuery[] =
7079 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7080 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7081 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7082 ' ', '=',' ','%','i',0};
7084 if (needs_ui_sequence(package))
7085 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7087 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7091 LPCWSTR action, cond;
7093 TRACE("Running the actions\n");
7095 /* check conditions */
7096 cond = MSI_RecordGetString(row, 2);
7098 /* this is a hack to skip errors in the condition code */
7099 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7101 msiobj_release(&row->hdr);
7102 return ERROR_SUCCESS;
7105 action = MSI_RecordGetString(row, 1);
7108 ERR("failed to fetch action\n");
7109 msiobj_release(&row->hdr);
7110 return ERROR_FUNCTION_FAILED;
7113 if (needs_ui_sequence(package))
7114 rc = ACTION_PerformUIAction(package, action, -1);
7116 rc = ACTION_PerformAction(package, action, -1);
7118 msiobj_release(&row->hdr);
7124 /****************************************************
7125 * TOP level entry points
7126 *****************************************************/
7128 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7129 LPCWSTR szCommandLine )
7134 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7135 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7137 msi_set_property( package->db, szAction, szInstall );
7139 package->script->InWhatSequence = SEQUENCE_INSTALL;
7146 dir = strdupW(szPackagePath);
7147 p = strrchrW(dir, '\\');
7151 file = szPackagePath + (p - dir);
7156 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7157 GetCurrentDirectoryW(MAX_PATH, dir);
7158 lstrcatW(dir, szBackSlash);
7159 file = szPackagePath;
7162 msi_free( package->PackagePath );
7163 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7164 if (!package->PackagePath)
7167 return ERROR_OUTOFMEMORY;
7170 lstrcpyW(package->PackagePath, dir);
7171 lstrcatW(package->PackagePath, file);
7174 msi_set_sourcedir_props(package, FALSE);
7177 msi_parse_command_line( package, szCommandLine, FALSE );
7179 msi_apply_transforms( package );
7180 msi_apply_patches( package );
7182 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7184 TRACE("setting reinstall property\n");
7185 msi_set_property( package->db, szReinstall, szAll );
7188 /* properties may have been added by a transform */
7189 msi_clone_properties( package );
7191 msi_parse_command_line( package, szCommandLine, FALSE );
7192 msi_adjust_privilege_properties( package );
7193 msi_set_context( package );
7195 if (needs_ui_sequence( package))
7197 package->script->InWhatSequence |= SEQUENCE_UI;
7198 rc = ACTION_ProcessUISequence(package);
7199 ui_exists = ui_sequence_exists(package);
7200 if (rc == ERROR_SUCCESS || !ui_exists)
7202 package->script->InWhatSequence |= SEQUENCE_EXEC;
7203 rc = ACTION_ProcessExecSequence(package, ui_exists);
7207 rc = ACTION_ProcessExecSequence(package, FALSE);
7209 package->script->CurrentlyScripting = FALSE;
7211 /* process the ending type action */
7212 if (rc == ERROR_SUCCESS)
7213 ACTION_PerformActionSequence(package, -1);
7214 else if (rc == ERROR_INSTALL_USEREXIT)
7215 ACTION_PerformActionSequence(package, -2);
7216 else if (rc == ERROR_INSTALL_SUSPEND)
7217 ACTION_PerformActionSequence(package, -4);
7219 ACTION_PerformActionSequence(package, -3);
7221 /* finish up running custom actions */
7222 ACTION_FinishCustomActions(package);
7224 if (rc == ERROR_SUCCESS && package->need_reboot)
7225 return ERROR_SUCCESS_REBOOT_REQUIRED;