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 file = get_loaded_file(package, comp->KeyPath);
3252 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3253 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3254 ptr2 = strrchrW(source, '\\') + 1;
3255 msiobj_release(&row->hdr);
3257 lstrcpyW(base, package->PackagePath);
3258 ptr = strrchrW(base, '\\');
3261 sourcepath = resolve_file_source(package, file);
3262 ptr = sourcepath + lstrlenW(base);
3263 lstrcpyW(ptr2, ptr);
3264 msi_free(sourcepath);
3266 msi_reg_set_val_str(hkey, squished_pc, source);
3270 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3272 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3273 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3275 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3277 comp->Action = comp->ActionRequest;
3280 uirow = MSI_CreateRecord(3);
3281 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3282 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3283 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3284 ui_actiondata(package,szProcessComponents,uirow);
3285 msiobj_release( &uirow->hdr );
3288 return ERROR_SUCCESS;
3299 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3300 LPWSTR lpszName, LONG_PTR lParam)
3303 typelib_struct *tl_struct = (typelib_struct*) lParam;
3304 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3308 if (!IS_INTRESOURCE(lpszName))
3310 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3314 sz = strlenW(tl_struct->source)+4;
3315 sz *= sizeof(WCHAR);
3317 if ((INT_PTR)lpszName == 1)
3318 tl_struct->path = strdupW(tl_struct->source);
3321 tl_struct->path = msi_alloc(sz);
3322 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3325 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3326 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3329 msi_free(tl_struct->path);
3330 tl_struct->path = NULL;
3335 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3336 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3338 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3342 msi_free(tl_struct->path);
3343 tl_struct->path = NULL;
3345 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3346 ITypeLib_Release(tl_struct->ptLib);
3351 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3353 MSIPACKAGE* package = param;
3357 typelib_struct tl_struct;
3362 component = MSI_RecordGetString(row,3);
3363 comp = get_loaded_component(package,component);
3365 return ERROR_SUCCESS;
3369 TRACE("component is disabled\n");
3370 return ERROR_SUCCESS;
3373 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3375 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3376 comp->Action = comp->Installed;
3377 return ERROR_SUCCESS;
3379 comp->Action = INSTALLSTATE_LOCAL;
3381 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3383 TRACE("component has no key path\n");
3384 return ERROR_SUCCESS;
3386 ui_actiondata( package, szRegisterTypeLibraries, row );
3388 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3392 guid = MSI_RecordGetString(row,1);
3393 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3394 tl_struct.source = strdupW( file->TargetPath );
3395 tl_struct.path = NULL;
3397 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3398 (LONG_PTR)&tl_struct);
3406 helpid = MSI_RecordGetString(row,6);
3409 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3410 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3414 ERR("Failed to register type library %s\n",
3415 debugstr_w(tl_struct.path));
3417 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3419 ITypeLib_Release(tl_struct.ptLib);
3420 msi_free(tl_struct.path);
3423 ERR("Failed to load type library %s\n",
3424 debugstr_w(tl_struct.source));
3426 FreeLibrary(module);
3427 msi_free(tl_struct.source);
3431 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3434 ERR("Failed to load type library: %08x\n", hr);
3435 return ERROR_INSTALL_FAILURE;
3438 ITypeLib_Release(tlib);
3441 return ERROR_SUCCESS;
3444 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3447 * OK this is a bit confusing.. I am given a _Component key and I believe
3448 * that the file that is being registered as a type library is the "key file
3449 * of that component" which I interpret to mean "The file in the KeyPath of
3454 static const WCHAR Query[] =
3455 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3456 '`','T','y','p','e','L','i','b','`',0};
3458 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3459 if (rc != ERROR_SUCCESS)
3460 return ERROR_SUCCESS;
3462 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3463 msiobj_release(&view->hdr);
3467 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3469 MSIPACKAGE *package = param;
3470 LPCWSTR component, guid;
3478 component = MSI_RecordGetString( row, 3 );
3479 comp = get_loaded_component( package, component );
3481 return ERROR_SUCCESS;
3485 TRACE("component is disabled\n");
3486 return ERROR_SUCCESS;
3489 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3491 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3492 comp->Action = comp->Installed;
3493 return ERROR_SUCCESS;
3495 comp->Action = INSTALLSTATE_ABSENT;
3497 ui_actiondata( package, szUnregisterTypeLibraries, row );
3499 guid = MSI_RecordGetString( row, 1 );
3500 CLSIDFromString( (LPCWSTR)guid, &libid );
3501 version = MSI_RecordGetInteger( row, 4 );
3502 language = MSI_RecordGetInteger( row, 2 );
3505 syskind = SYS_WIN64;
3507 syskind = SYS_WIN32;
3510 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3513 WARN("Failed to unregister typelib: %08x\n", hr);
3516 return ERROR_SUCCESS;
3519 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3523 static const WCHAR query[] =
3524 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3525 '`','T','y','p','e','L','i','b','`',0};
3527 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3528 if (rc != ERROR_SUCCESS)
3529 return ERROR_SUCCESS;
3531 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3532 msiobj_release( &view->hdr );
3536 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3538 static const WCHAR szlnk[] = {'.','l','n','k',0};
3539 LPCWSTR directory, extension;
3540 LPWSTR link_folder, link_file, filename;
3542 directory = MSI_RecordGetString( row, 2 );
3543 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3545 /* may be needed because of a bug somewhere else */
3546 create_full_pathW( link_folder );
3548 filename = msi_dup_record_field( row, 3 );
3549 reduce_to_longfilename( filename );
3551 extension = strchrW( filename, '.' );
3552 if (!extension || strcmpiW( extension, szlnk ))
3554 int len = strlenW( filename );
3555 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3556 memcpy( filename + len, szlnk, sizeof(szlnk) );
3558 link_file = build_directory_name( 2, link_folder, filename );
3559 msi_free( link_folder );
3560 msi_free( filename );
3565 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3567 MSIPACKAGE *package = param;
3568 LPWSTR link_file, deformated, path;
3569 LPCWSTR component, target;
3571 IShellLinkW *sl = NULL;
3572 IPersistFile *pf = NULL;
3575 component = MSI_RecordGetString(row, 4);
3576 comp = get_loaded_component(package, component);
3578 return ERROR_SUCCESS;
3582 TRACE("component is disabled\n");
3583 return ERROR_SUCCESS;
3586 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3588 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3589 comp->Action = comp->Installed;
3590 return ERROR_SUCCESS;
3592 comp->Action = INSTALLSTATE_LOCAL;
3594 ui_actiondata(package,szCreateShortcuts,row);
3596 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3597 &IID_IShellLinkW, (LPVOID *) &sl );
3601 ERR("CLSID_ShellLink not available\n");
3605 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3608 ERR("QueryInterface(IID_IPersistFile) failed\n");
3612 target = MSI_RecordGetString(row, 5);
3613 if (strchrW(target, '['))
3615 deformat_string(package, target, &deformated);
3616 IShellLinkW_SetPath(sl,deformated);
3617 msi_free(deformated);
3621 FIXME("poorly handled shortcut format, advertised shortcut\n");
3622 IShellLinkW_SetPath(sl,comp->FullKeypath);
3625 if (!MSI_RecordIsNull(row,6))
3627 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3628 deformat_string(package, arguments, &deformated);
3629 IShellLinkW_SetArguments(sl,deformated);
3630 msi_free(deformated);
3633 if (!MSI_RecordIsNull(row,7))
3635 LPCWSTR description = MSI_RecordGetString(row, 7);
3636 IShellLinkW_SetDescription(sl, description);
3639 if (!MSI_RecordIsNull(row,8))
3640 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3642 if (!MSI_RecordIsNull(row,9))
3645 LPCWSTR icon = MSI_RecordGetString(row, 9);
3647 path = build_icon_path(package, icon);
3648 index = MSI_RecordGetInteger(row,10);
3650 /* no value means 0 */
3651 if (index == MSI_NULL_INTEGER)
3654 IShellLinkW_SetIconLocation(sl, path, index);
3658 if (!MSI_RecordIsNull(row,11))
3659 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3661 if (!MSI_RecordIsNull(row,12))
3663 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3664 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3666 IShellLinkW_SetWorkingDirectory(sl, path);
3670 link_file = get_link_file(package, row);
3672 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3673 IPersistFile_Save(pf, link_file, FALSE);
3675 msi_free(link_file);
3679 IPersistFile_Release( pf );
3681 IShellLinkW_Release( sl );
3683 return ERROR_SUCCESS;
3686 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3691 static const WCHAR Query[] =
3692 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3693 '`','S','h','o','r','t','c','u','t','`',0};
3695 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3696 if (rc != ERROR_SUCCESS)
3697 return ERROR_SUCCESS;
3699 res = CoInitialize( NULL );
3701 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3702 msiobj_release(&view->hdr);
3710 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3712 MSIPACKAGE *package = param;
3717 component = MSI_RecordGetString( row, 4 );
3718 comp = get_loaded_component( package, component );
3720 return ERROR_SUCCESS;
3724 TRACE("component is disabled\n");
3725 return ERROR_SUCCESS;
3728 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3730 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3731 comp->Action = comp->Installed;
3732 return ERROR_SUCCESS;
3734 comp->Action = INSTALLSTATE_ABSENT;
3736 ui_actiondata( package, szRemoveShortcuts, row );
3738 link_file = get_link_file( package, row );
3740 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3741 if (!DeleteFileW( link_file ))
3743 WARN("Failed to remove shortcut file %u\n", GetLastError());
3745 msi_free( link_file );
3747 return ERROR_SUCCESS;
3750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3754 static const WCHAR query[] =
3755 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3756 '`','S','h','o','r','t','c','u','t','`',0};
3758 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3759 if (rc != ERROR_SUCCESS)
3760 return ERROR_SUCCESS;
3762 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3763 msiobj_release( &view->hdr );
3768 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3770 MSIPACKAGE* package = param;
3778 FileName = MSI_RecordGetString(row,1);
3781 ERR("Unable to get FileName\n");
3782 return ERROR_SUCCESS;
3785 FilePath = build_icon_path(package,FileName);
3787 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3789 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3790 FILE_ATTRIBUTE_NORMAL, NULL);
3792 if (the_file == INVALID_HANDLE_VALUE)
3794 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3796 return ERROR_SUCCESS;
3803 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3804 if (rc != ERROR_SUCCESS)
3806 ERR("Failed to get stream\n");
3807 CloseHandle(the_file);
3808 DeleteFileW(FilePath);
3811 WriteFile(the_file,buffer,sz,&write,NULL);
3812 } while (sz == 1024);
3815 CloseHandle(the_file);
3817 return ERROR_SUCCESS;
3820 static UINT msi_publish_icons(MSIPACKAGE *package)
3825 static const WCHAR query[]= {
3826 'S','E','L','E','C','T',' ','*',' ',
3827 'F','R','O','M',' ','`','I','c','o','n','`',0};
3829 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3830 if (r == ERROR_SUCCESS)
3832 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3833 msiobj_release(&view->hdr);
3836 return ERROR_SUCCESS;
3839 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3845 MSISOURCELISTINFO *info;
3847 r = RegCreateKeyW(hkey, szSourceList, &source);
3848 if (r != ERROR_SUCCESS)
3851 RegCloseKey(source);
3853 buffer = strrchrW(package->PackagePath, '\\') + 1;
3854 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3855 package->Context, MSICODE_PRODUCT,
3856 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3857 if (r != ERROR_SUCCESS)
3860 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3861 package->Context, MSICODE_PRODUCT,
3862 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3863 if (r != ERROR_SUCCESS)
3866 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3867 package->Context, MSICODE_PRODUCT,
3868 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3869 if (r != ERROR_SUCCESS)
3872 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3874 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3875 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3876 info->options, info->value);
3878 MsiSourceListSetInfoW(package->ProductCode, NULL,
3879 info->context, info->options,
3880 info->property, info->value);
3883 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3885 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3886 disk->context, disk->options,
3887 disk->disk_id, disk->volume_label, disk->disk_prompt);
3890 return ERROR_SUCCESS;
3893 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3895 MSIHANDLE hdb, suminfo;
3896 WCHAR guids[MAX_PATH];
3897 WCHAR packcode[SQUISH_GUID_SIZE];
3904 static const WCHAR szProductLanguage[] =
3905 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3906 static const WCHAR szARPProductIcon[] =
3907 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3908 static const WCHAR szProductVersion[] =
3909 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3910 static const WCHAR szAssignment[] =
3911 {'A','s','s','i','g','n','m','e','n','t',0};
3912 static const WCHAR szAdvertiseFlags[] =
3913 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3914 static const WCHAR szClients[] =
3915 {'C','l','i','e','n','t','s',0};
3916 static const WCHAR szColon[] = {':',0};
3918 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3919 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3922 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3923 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3926 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3928 buffer = msi_dup_property(package->db, szARPProductIcon);
3931 LPWSTR path = build_icon_path(package,buffer);
3932 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3937 buffer = msi_dup_property(package->db, szProductVersion);
3940 DWORD verdword = msi_version_str_to_dword(buffer);
3941 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3945 msi_reg_set_val_dword(hkey, szAssignment, 0);
3946 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3947 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3948 msi_reg_set_val_str(hkey, szClients, szColon);
3950 hdb = alloc_msihandle(&package->db->hdr);
3952 return ERROR_NOT_ENOUGH_MEMORY;
3954 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3955 MsiCloseHandle(hdb);
3956 if (r != ERROR_SUCCESS)
3960 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3961 NULL, guids, &size);
3962 if (r != ERROR_SUCCESS)
3965 ptr = strchrW(guids, ';');
3967 squash_guid(guids, packcode);
3968 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3971 MsiCloseHandle(suminfo);
3972 return ERROR_SUCCESS;
3975 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3980 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3982 upgrade = msi_dup_property(package->db, szUpgradeCode);
3984 return ERROR_SUCCESS;
3986 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3988 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3989 if (r != ERROR_SUCCESS)
3994 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3995 if (r != ERROR_SUCCESS)
3999 squash_guid(package->ProductCode, squashed_pc);
4000 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4009 static BOOL msi_check_publish(MSIPACKAGE *package)
4011 MSIFEATURE *feature;
4013 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4015 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4022 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4024 MSIFEATURE *feature;
4026 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4028 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4035 static UINT msi_publish_patches( MSIPACKAGE *package )
4037 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4038 WCHAR patch_squashed[GUID_SIZE];
4039 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4041 MSIPATCHINFO *patch;
4043 WCHAR *p, *all_patches = NULL;
4046 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4047 if (r != ERROR_SUCCESS)
4048 return ERROR_FUNCTION_FAILED;
4050 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4051 if (res != ERROR_SUCCESS)
4053 r = ERROR_FUNCTION_FAILED;
4057 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4058 if (r != ERROR_SUCCESS)
4061 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4063 squash_guid( patch->patchcode, patch_squashed );
4064 len += strlenW( patch_squashed ) + 1;
4067 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4071 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4075 squash_guid( patch->patchcode, p );
4076 p += strlenW( p ) + 1;
4078 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4079 (const BYTE *)patch->transforms,
4080 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4081 if (res != ERROR_SUCCESS)
4084 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4085 if (r != ERROR_SUCCESS)
4088 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4089 (const BYTE *)patch->localfile,
4090 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4091 RegCloseKey( patch_key );
4092 if (res != ERROR_SUCCESS)
4095 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4096 if (res != ERROR_SUCCESS)
4099 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4100 RegCloseKey( patch_key );
4101 if (res != ERROR_SUCCESS)
4105 all_patches[len] = 0;
4106 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4107 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4108 if (res != ERROR_SUCCESS)
4111 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4112 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4113 if (res != ERROR_SUCCESS)
4114 r = ERROR_FUNCTION_FAILED;
4117 RegCloseKey( product_patches_key );
4118 RegCloseKey( patches_key );
4119 RegCloseKey( product_key );
4120 msi_free( all_patches );
4125 * 99% of the work done here is only done for
4126 * advertised installs. However this is where the
4127 * Icon table is processed and written out
4128 * so that is what I am going to do here.
4130 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4133 HKEY hukey = NULL, hudkey = NULL;
4136 if (!list_empty(&package->patches))
4138 rc = msi_publish_patches(package);
4139 if (rc != ERROR_SUCCESS)
4143 /* FIXME: also need to publish if the product is in advertise mode */
4144 if (!msi_check_publish(package))
4145 return ERROR_SUCCESS;
4147 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4149 if (rc != ERROR_SUCCESS)
4152 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4153 NULL, &hudkey, TRUE);
4154 if (rc != ERROR_SUCCESS)
4157 rc = msi_publish_upgrade_code(package);
4158 if (rc != ERROR_SUCCESS)
4161 rc = msi_publish_product_properties(package, hukey);
4162 if (rc != ERROR_SUCCESS)
4165 rc = msi_publish_sourcelist(package, hukey);
4166 if (rc != ERROR_SUCCESS)
4169 rc = msi_publish_icons(package);
4172 uirow = MSI_CreateRecord( 1 );
4173 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4174 ui_actiondata( package, szPublishProduct, uirow );
4175 msiobj_release( &uirow->hdr );
4178 RegCloseKey(hudkey);
4183 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4185 WCHAR *filename, *ptr, *folder, *ret;
4186 const WCHAR *dirprop;
4188 filename = msi_dup_record_field( row, 2 );
4189 if (filename && (ptr = strchrW( filename, '|' )))
4194 dirprop = MSI_RecordGetString( row, 3 );
4197 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4199 folder = msi_dup_property( package->db, dirprop );
4202 folder = msi_dup_property( package->db, szWindowsFolder );
4206 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4207 msi_free( filename );
4211 ret = build_directory_name( 2, folder, ptr );
4213 msi_free( filename );
4218 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4220 MSIPACKAGE *package = param;
4221 LPCWSTR component, section, key, value, identifier;
4222 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4227 component = MSI_RecordGetString(row, 8);
4228 comp = get_loaded_component(package,component);
4230 return ERROR_SUCCESS;
4234 TRACE("component is disabled\n");
4235 return ERROR_SUCCESS;
4238 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4240 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4241 comp->Action = comp->Installed;
4242 return ERROR_SUCCESS;
4244 comp->Action = INSTALLSTATE_LOCAL;
4246 identifier = MSI_RecordGetString(row,1);
4247 section = MSI_RecordGetString(row,4);
4248 key = MSI_RecordGetString(row,5);
4249 value = MSI_RecordGetString(row,6);
4250 action = MSI_RecordGetInteger(row,7);
4252 deformat_string(package,section,&deformated_section);
4253 deformat_string(package,key,&deformated_key);
4254 deformat_string(package,value,&deformated_value);
4256 fullname = get_ini_file_name(package, row);
4260 TRACE("Adding value %s to section %s in %s\n",
4261 debugstr_w(deformated_key), debugstr_w(deformated_section),
4262 debugstr_w(fullname));
4263 WritePrivateProfileStringW(deformated_section, deformated_key,
4264 deformated_value, fullname);
4266 else if (action == 1)
4269 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4270 returned, 10, fullname);
4271 if (returned[0] == 0)
4273 TRACE("Adding value %s to section %s in %s\n",
4274 debugstr_w(deformated_key), debugstr_w(deformated_section),
4275 debugstr_w(fullname));
4277 WritePrivateProfileStringW(deformated_section, deformated_key,
4278 deformated_value, fullname);
4281 else if (action == 3)
4282 FIXME("Append to existing section not yet implemented\n");
4284 uirow = MSI_CreateRecord(4);
4285 MSI_RecordSetStringW(uirow,1,identifier);
4286 MSI_RecordSetStringW(uirow,2,deformated_section);
4287 MSI_RecordSetStringW(uirow,3,deformated_key);
4288 MSI_RecordSetStringW(uirow,4,deformated_value);
4289 ui_actiondata(package,szWriteIniValues,uirow);
4290 msiobj_release( &uirow->hdr );
4293 msi_free(deformated_key);
4294 msi_free(deformated_value);
4295 msi_free(deformated_section);
4296 return ERROR_SUCCESS;
4299 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4303 static const WCHAR ExecSeqQuery[] =
4304 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4305 '`','I','n','i','F','i','l','e','`',0};
4307 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4308 if (rc != ERROR_SUCCESS)
4310 TRACE("no IniFile table\n");
4311 return ERROR_SUCCESS;
4314 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4315 msiobj_release(&view->hdr);
4319 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4321 MSIPACKAGE *package = param;
4322 LPCWSTR component, section, key, value, identifier;
4323 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4328 component = MSI_RecordGetString( row, 8 );
4329 comp = get_loaded_component( package, component );
4331 return ERROR_SUCCESS;
4335 TRACE("component is disabled\n");
4336 return ERROR_SUCCESS;
4339 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4341 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4342 comp->Action = comp->Installed;
4343 return ERROR_SUCCESS;
4345 comp->Action = INSTALLSTATE_ABSENT;
4347 identifier = MSI_RecordGetString( row, 1 );
4348 section = MSI_RecordGetString( row, 4 );
4349 key = MSI_RecordGetString( row, 5 );
4350 value = MSI_RecordGetString( row, 6 );
4351 action = MSI_RecordGetInteger( row, 7 );
4353 deformat_string( package, section, &deformated_section );
4354 deformat_string( package, key, &deformated_key );
4355 deformat_string( package, value, &deformated_value );
4357 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4359 filename = get_ini_file_name( package, row );
4361 TRACE("Removing key %s from section %s in %s\n",
4362 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4364 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4366 WARN("Unable to remove key %u\n", GetLastError());
4368 msi_free( filename );
4371 FIXME("Unsupported action %d\n", action);
4374 uirow = MSI_CreateRecord( 4 );
4375 MSI_RecordSetStringW( uirow, 1, identifier );
4376 MSI_RecordSetStringW( uirow, 2, deformated_section );
4377 MSI_RecordSetStringW( uirow, 3, deformated_key );
4378 MSI_RecordSetStringW( uirow, 4, deformated_value );
4379 ui_actiondata( package, szRemoveIniValues, uirow );
4380 msiobj_release( &uirow->hdr );
4382 msi_free( deformated_key );
4383 msi_free( deformated_value );
4384 msi_free( deformated_section );
4385 return ERROR_SUCCESS;
4388 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4390 MSIPACKAGE *package = param;
4391 LPCWSTR component, section, key, value, identifier;
4392 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4397 component = MSI_RecordGetString( row, 8 );
4398 comp = get_loaded_component( package, component );
4400 return ERROR_SUCCESS;
4404 TRACE("component is disabled\n");
4405 return ERROR_SUCCESS;
4408 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4410 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4411 comp->Action = comp->Installed;
4412 return ERROR_SUCCESS;
4414 comp->Action = INSTALLSTATE_LOCAL;
4416 identifier = MSI_RecordGetString( row, 1 );
4417 section = MSI_RecordGetString( row, 4 );
4418 key = MSI_RecordGetString( row, 5 );
4419 value = MSI_RecordGetString( row, 6 );
4420 action = MSI_RecordGetInteger( row, 7 );
4422 deformat_string( package, section, &deformated_section );
4423 deformat_string( package, key, &deformated_key );
4424 deformat_string( package, value, &deformated_value );
4426 if (action == msidbIniFileActionRemoveLine)
4428 filename = get_ini_file_name( package, row );
4430 TRACE("Removing key %s from section %s in %s\n",
4431 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4433 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4435 WARN("Unable to remove key %u\n", GetLastError());
4437 msi_free( filename );
4440 FIXME("Unsupported action %d\n", action);
4442 uirow = MSI_CreateRecord( 4 );
4443 MSI_RecordSetStringW( uirow, 1, identifier );
4444 MSI_RecordSetStringW( uirow, 2, deformated_section );
4445 MSI_RecordSetStringW( uirow, 3, deformated_key );
4446 MSI_RecordSetStringW( uirow, 4, deformated_value );
4447 ui_actiondata( package, szRemoveIniValues, uirow );
4448 msiobj_release( &uirow->hdr );
4450 msi_free( deformated_key );
4451 msi_free( deformated_value );
4452 msi_free( deformated_section );
4453 return ERROR_SUCCESS;
4456 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4460 static const WCHAR query[] =
4461 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4462 '`','I','n','i','F','i','l','e','`',0};
4463 static const WCHAR remove_query[] =
4464 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4465 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4467 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4468 if (rc == ERROR_SUCCESS)
4470 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4471 msiobj_release( &view->hdr );
4472 if (rc != ERROR_SUCCESS)
4476 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4477 if (rc == ERROR_SUCCESS)
4479 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4480 msiobj_release( &view->hdr );
4481 if (rc != ERROR_SUCCESS)
4485 return ERROR_SUCCESS;
4488 static void register_dll( const WCHAR *dll, BOOL unregister )
4492 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4495 HRESULT (WINAPI *func_ptr)( void );
4496 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4498 func_ptr = (void *)GetProcAddress( hmod, func );
4501 HRESULT hr = func_ptr();
4503 WARN("failed to register dll 0x%08x\n", hr);
4506 WARN("entry point %s not found\n", func);
4507 FreeLibrary( hmod );
4510 WARN("failed to load library %u\n", GetLastError());
4513 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4515 MSIPACKAGE *package = param;
4520 filename = MSI_RecordGetString(row,1);
4521 file = get_loaded_file( package, filename );
4525 ERR("Unable to find file id %s\n",debugstr_w(filename));
4526 return ERROR_SUCCESS;
4529 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4531 register_dll( file->TargetPath, FALSE );
4533 uirow = MSI_CreateRecord( 2 );
4534 MSI_RecordSetStringW( uirow, 1, filename );
4535 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4536 ui_actiondata( package, szSelfRegModules, uirow );
4537 msiobj_release( &uirow->hdr );
4539 return ERROR_SUCCESS;
4542 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4546 static const WCHAR ExecSeqQuery[] =
4547 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4548 '`','S','e','l','f','R','e','g','`',0};
4550 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4551 if (rc != ERROR_SUCCESS)
4553 TRACE("no SelfReg table\n");
4554 return ERROR_SUCCESS;
4557 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4558 msiobj_release(&view->hdr);
4560 return ERROR_SUCCESS;
4563 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4565 MSIPACKAGE *package = param;
4570 filename = MSI_RecordGetString( row, 1 );
4571 file = get_loaded_file( package, filename );
4575 ERR("Unable to find file id %s\n", debugstr_w(filename));
4576 return ERROR_SUCCESS;
4579 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4581 register_dll( file->TargetPath, TRUE );
4583 uirow = MSI_CreateRecord( 2 );
4584 MSI_RecordSetStringW( uirow, 1, filename );
4585 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4586 ui_actiondata( package, szSelfUnregModules, uirow );
4587 msiobj_release( &uirow->hdr );
4589 return ERROR_SUCCESS;
4592 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4596 static const WCHAR query[] =
4597 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4598 '`','S','e','l','f','R','e','g','`',0};
4600 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4601 if (rc != ERROR_SUCCESS)
4603 TRACE("no SelfReg table\n");
4604 return ERROR_SUCCESS;
4607 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4608 msiobj_release( &view->hdr );
4610 return ERROR_SUCCESS;
4613 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4615 MSIFEATURE *feature;
4617 HKEY hkey = NULL, userdata = NULL;
4619 if (!msi_check_publish(package))
4620 return ERROR_SUCCESS;
4622 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4624 if (rc != ERROR_SUCCESS)
4627 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4629 if (rc != ERROR_SUCCESS)
4632 /* here the guids are base 85 encoded */
4633 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4639 BOOL absent = FALSE;
4642 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4643 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4644 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4647 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4651 if (feature->Feature_Parent)
4652 size += strlenW( feature->Feature_Parent )+2;
4654 data = msi_alloc(size * sizeof(WCHAR));
4657 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4659 MSICOMPONENT* component = cl->component;
4663 if (component->ComponentId)
4665 TRACE("From %s\n",debugstr_w(component->ComponentId));
4666 CLSIDFromString(component->ComponentId, &clsid);
4667 encode_base85_guid(&clsid,buf);
4668 TRACE("to %s\n",debugstr_w(buf));
4673 if (feature->Feature_Parent)
4675 static const WCHAR sep[] = {'\2',0};
4677 strcatW(data,feature->Feature_Parent);
4680 msi_reg_set_val_str( userdata, feature->Feature, data );
4684 if (feature->Feature_Parent)
4685 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4688 size += sizeof(WCHAR);
4689 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4690 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4694 size += 2*sizeof(WCHAR);
4695 data = msi_alloc(size);
4698 if (feature->Feature_Parent)
4699 strcpyW( &data[1], feature->Feature_Parent );
4700 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4706 uirow = MSI_CreateRecord( 1 );
4707 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4708 ui_actiondata( package, szPublishFeatures, uirow);
4709 msiobj_release( &uirow->hdr );
4710 /* FIXME: call ui_progress? */
4715 RegCloseKey(userdata);
4719 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4725 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4727 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4729 if (r == ERROR_SUCCESS)
4731 RegDeleteValueW(hkey, feature->Feature);
4735 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4737 if (r == ERROR_SUCCESS)
4739 RegDeleteValueW(hkey, feature->Feature);
4743 uirow = MSI_CreateRecord( 1 );
4744 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4745 ui_actiondata( package, szUnpublishFeatures, uirow );
4746 msiobj_release( &uirow->hdr );
4748 return ERROR_SUCCESS;
4751 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4753 MSIFEATURE *feature;
4755 if (!msi_check_unpublish(package))
4756 return ERROR_SUCCESS;
4758 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4760 msi_unpublish_feature(package, feature);
4763 return ERROR_SUCCESS;
4766 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4770 WCHAR date[9], *val, *buffer;
4771 const WCHAR *prop, *key;
4773 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4774 static const WCHAR szWindowsInstaller[] =
4775 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4776 static const WCHAR modpath_fmt[] =
4777 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4778 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4779 static const WCHAR szModifyPath[] =
4780 {'M','o','d','i','f','y','P','a','t','h',0};
4781 static const WCHAR szUninstallString[] =
4782 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4783 static const WCHAR szEstimatedSize[] =
4784 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4785 static const WCHAR szProductLanguage[] =
4786 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4787 static const WCHAR szProductVersion[] =
4788 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4789 static const WCHAR szDisplayVersion[] =
4790 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4791 static const WCHAR szInstallSource[] =
4792 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4793 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4794 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4795 static const WCHAR szAuthorizedCDFPrefix[] =
4796 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4797 static const WCHAR szARPCONTACT[] =
4798 {'A','R','P','C','O','N','T','A','C','T',0};
4799 static const WCHAR szContact[] =
4800 {'C','o','n','t','a','c','t',0};
4801 static const WCHAR szARPCOMMENTS[] =
4802 {'A','R','P','C','O','M','M','E','N','T','S',0};
4803 static const WCHAR szComments[] =
4804 {'C','o','m','m','e','n','t','s',0};
4805 static const WCHAR szProductName[] =
4806 {'P','r','o','d','u','c','t','N','a','m','e',0};
4807 static const WCHAR szDisplayName[] =
4808 {'D','i','s','p','l','a','y','N','a','m','e',0};
4809 static const WCHAR szARPHELPLINK[] =
4810 {'A','R','P','H','E','L','P','L','I','N','K',0};
4811 static const WCHAR szHelpLink[] =
4812 {'H','e','l','p','L','i','n','k',0};
4813 static const WCHAR szARPHELPTELEPHONE[] =
4814 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4815 static const WCHAR szHelpTelephone[] =
4816 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4817 static const WCHAR szARPINSTALLLOCATION[] =
4818 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4819 static const WCHAR szInstallLocation[] =
4820 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4821 static const WCHAR szManufacturer[] =
4822 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4823 static const WCHAR szPublisher[] =
4824 {'P','u','b','l','i','s','h','e','r',0};
4825 static const WCHAR szARPREADME[] =
4826 {'A','R','P','R','E','A','D','M','E',0};
4827 static const WCHAR szReadme[] =
4828 {'R','e','a','d','M','e',0};
4829 static const WCHAR szARPSIZE[] =
4830 {'A','R','P','S','I','Z','E',0};
4831 static const WCHAR szSize[] =
4832 {'S','i','z','e',0};
4833 static const WCHAR szARPURLINFOABOUT[] =
4834 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4835 static const WCHAR szURLInfoAbout[] =
4836 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4837 static const WCHAR szARPURLUPDATEINFO[] =
4838 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4839 static const WCHAR szURLUpdateInfo[] =
4840 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4842 static const WCHAR *propval[] = {
4843 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4844 szARPCONTACT, szContact,
4845 szARPCOMMENTS, szComments,
4846 szProductName, szDisplayName,
4847 szARPHELPLINK, szHelpLink,
4848 szARPHELPTELEPHONE, szHelpTelephone,
4849 szARPINSTALLLOCATION, szInstallLocation,
4850 cszSourceDir, szInstallSource,
4851 szManufacturer, szPublisher,
4852 szARPREADME, szReadme,
4854 szARPURLINFOABOUT, szURLInfoAbout,
4855 szARPURLUPDATEINFO, szURLUpdateInfo,
4858 const WCHAR **p = propval;
4864 val = msi_dup_property(package->db, prop);
4865 msi_reg_set_val_str(hkey, key, val);
4869 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4871 size = deformat_string(package, modpath_fmt, &buffer);
4872 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4873 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4876 /* FIXME: Write real Estimated Size when we have it */
4877 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4879 GetLocalTime(&systime);
4880 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4881 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4883 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4884 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4886 buffer = msi_dup_property(package->db, szProductVersion);
4887 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4890 DWORD verdword = msi_version_str_to_dword(buffer);
4892 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4893 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4894 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4898 return ERROR_SUCCESS;
4901 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4903 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4905 LPWSTR upgrade_code;
4910 /* FIXME: also need to publish if the product is in advertise mode */
4911 if (!msi_check_publish(package))
4912 return ERROR_SUCCESS;
4914 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4915 if (rc != ERROR_SUCCESS)
4918 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4919 NULL, &props, TRUE);
4920 if (rc != ERROR_SUCCESS)
4923 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4924 msi_free( package->db->localfile );
4925 package->db->localfile = NULL;
4927 rc = msi_publish_install_properties(package, hkey);
4928 if (rc != ERROR_SUCCESS)
4931 rc = msi_publish_install_properties(package, props);
4932 if (rc != ERROR_SUCCESS)
4935 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4938 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4939 squash_guid(package->ProductCode, squashed_pc);
4940 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4941 RegCloseKey(upgrade);
4942 msi_free(upgrade_code);
4946 uirow = MSI_CreateRecord( 1 );
4947 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4948 ui_actiondata( package, szRegisterProduct, uirow );
4949 msiobj_release( &uirow->hdr );
4952 return ERROR_SUCCESS;
4955 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4957 return execute_script(package,INSTALL_SCRIPT);
4960 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4962 WCHAR *upgrade, **features;
4963 BOOL full_uninstall = TRUE;
4964 MSIFEATURE *feature;
4965 MSIPATCHINFO *patch;
4967 static const WCHAR szUpgradeCode[] =
4968 {'U','p','g','r','a','d','e','C','o','d','e',0};
4970 features = msi_split_string(remove, ',');
4973 ERR("REMOVE feature list is empty!\n");
4974 return ERROR_FUNCTION_FAILED;
4977 if (!strcmpW( features[0], szAll ))
4978 full_uninstall = TRUE;
4981 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4983 if (feature->Action != INSTALLSTATE_ABSENT)
4984 full_uninstall = FALSE;
4989 if (!full_uninstall)
4990 return ERROR_SUCCESS;
4992 MSIREG_DeleteProductKey(package->ProductCode);
4993 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4994 MSIREG_DeleteUninstallKey(package);
4996 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4998 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4999 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5003 MSIREG_DeleteUserProductKey(package->ProductCode);
5004 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5007 upgrade = msi_dup_property(package->db, szUpgradeCode);
5010 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5014 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5016 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5019 return ERROR_SUCCESS;
5022 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5027 /* turn off scheduling */
5028 package->script->CurrentlyScripting= FALSE;
5030 /* first do the same as an InstallExecute */
5031 rc = ACTION_InstallExecute(package);
5032 if (rc != ERROR_SUCCESS)
5035 /* then handle Commit Actions */
5036 rc = execute_script(package,COMMIT_SCRIPT);
5037 if (rc != ERROR_SUCCESS)
5040 remove = msi_dup_property(package->db, szRemove);
5042 rc = msi_unpublish_product(package, remove);
5048 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5050 static const WCHAR RunOnce[] = {
5051 'S','o','f','t','w','a','r','e','\\',
5052 'M','i','c','r','o','s','o','f','t','\\',
5053 'W','i','n','d','o','w','s','\\',
5054 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5055 'R','u','n','O','n','c','e',0};
5056 static const WCHAR InstallRunOnce[] = {
5057 'S','o','f','t','w','a','r','e','\\',
5058 'M','i','c','r','o','s','o','f','t','\\',
5059 'W','i','n','d','o','w','s','\\',
5060 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5061 'I','n','s','t','a','l','l','e','r','\\',
5062 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5064 static const WCHAR msiexec_fmt[] = {
5066 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5067 '\"','%','s','\"',0};
5068 static const WCHAR install_fmt[] = {
5069 '/','I',' ','\"','%','s','\"',' ',
5070 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5071 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5072 WCHAR buffer[256], sysdir[MAX_PATH];
5074 WCHAR squished_pc[100];
5076 squash_guid(package->ProductCode,squished_pc);
5078 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5079 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5080 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5083 msi_reg_set_val_str( hkey, squished_pc, buffer );
5086 TRACE("Reboot command %s\n",debugstr_w(buffer));
5088 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5089 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5091 msi_reg_set_val_str( hkey, squished_pc, buffer );
5094 return ERROR_INSTALL_SUSPEND;
5097 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5103 * We are currently doing what should be done here in the top level Install
5104 * however for Administrative and uninstalls this step will be needed
5106 if (!package->PackagePath)
5107 return ERROR_SUCCESS;
5109 msi_set_sourcedir_props(package, TRUE);
5111 attrib = GetFileAttributesW(package->db->path);
5112 if (attrib == INVALID_FILE_ATTRIBUTES)
5118 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5119 package->Context, MSICODE_PRODUCT,
5120 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5121 if (rc == ERROR_MORE_DATA)
5123 prompt = msi_alloc(size * sizeof(WCHAR));
5124 MsiSourceListGetInfoW(package->ProductCode, NULL,
5125 package->Context, MSICODE_PRODUCT,
5126 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5129 prompt = strdupW(package->db->path);
5131 msg = generate_error_string(package,1302,1,prompt);
5132 while(attrib == INVALID_FILE_ATTRIBUTES)
5134 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5137 rc = ERROR_INSTALL_USEREXIT;
5140 attrib = GetFileAttributesW(package->db->path);
5146 return ERROR_SUCCESS;
5151 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5154 LPWSTR buffer, productid = NULL;
5155 UINT i, rc = ERROR_SUCCESS;
5158 static const WCHAR szPropKeys[][80] =
5160 {'P','r','o','d','u','c','t','I','D',0},
5161 {'U','S','E','R','N','A','M','E',0},
5162 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5166 static const WCHAR szRegKeys[][80] =
5168 {'P','r','o','d','u','c','t','I','D',0},
5169 {'R','e','g','O','w','n','e','r',0},
5170 {'R','e','g','C','o','m','p','a','n','y',0},
5174 if (msi_check_unpublish(package))
5176 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5180 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5184 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5186 if (rc != ERROR_SUCCESS)
5189 for( i = 0; szPropKeys[i][0]; i++ )
5191 buffer = msi_dup_property( package->db, szPropKeys[i] );
5192 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5197 uirow = MSI_CreateRecord( 1 );
5198 MSI_RecordSetStringW( uirow, 1, productid );
5199 ui_actiondata( package, szRegisterUser, uirow );
5200 msiobj_release( &uirow->hdr );
5202 msi_free(productid);
5208 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5212 package->script->InWhatSequence |= SEQUENCE_EXEC;
5213 rc = ACTION_ProcessExecSequence(package,FALSE);
5218 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5220 MSIPACKAGE *package = param;
5221 LPCWSTR compgroupid, component, feature, qualifier, text;
5222 LPWSTR advertise = NULL, output = NULL;
5230 feature = MSI_RecordGetString(rec, 5);
5231 feat = get_loaded_feature(package, feature);
5233 return ERROR_SUCCESS;
5235 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5236 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5237 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5239 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5240 feat->Action = feat->Installed;
5241 return ERROR_SUCCESS;
5244 component = MSI_RecordGetString(rec, 3);
5245 comp = get_loaded_component(package, component);
5247 return ERROR_SUCCESS;
5249 compgroupid = MSI_RecordGetString(rec,1);
5250 qualifier = MSI_RecordGetString(rec,2);
5252 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5253 if (rc != ERROR_SUCCESS)
5256 text = MSI_RecordGetString(rec,4);
5257 advertise = create_component_advertise_string(package, comp, feature);
5259 sz = strlenW(advertise);
5262 sz += lstrlenW(text);
5265 sz *= sizeof(WCHAR);
5267 output = msi_alloc_zero(sz);
5268 strcpyW(output,advertise);
5269 msi_free(advertise);
5272 strcatW(output,text);
5274 msi_reg_set_val_multi_str( hkey, qualifier, output );
5281 uirow = MSI_CreateRecord( 2 );
5282 MSI_RecordSetStringW( uirow, 1, compgroupid );
5283 MSI_RecordSetStringW( uirow, 2, qualifier);
5284 ui_actiondata( package, szPublishComponents, uirow);
5285 msiobj_release( &uirow->hdr );
5286 /* FIXME: call ui_progress? */
5292 * At present I am ignorning the advertised components part of this and only
5293 * focusing on the qualified component sets
5295 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5299 static const WCHAR ExecSeqQuery[] =
5300 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5301 '`','P','u','b','l','i','s','h',
5302 'C','o','m','p','o','n','e','n','t','`',0};
5304 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5305 if (rc != ERROR_SUCCESS)
5306 return ERROR_SUCCESS;
5308 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5309 msiobj_release(&view->hdr);
5314 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5316 static const WCHAR szInstallerComponents[] = {
5317 'S','o','f','t','w','a','r','e','\\',
5318 'M','i','c','r','o','s','o','f','t','\\',
5319 'I','n','s','t','a','l','l','e','r','\\',
5320 'C','o','m','p','o','n','e','n','t','s','\\',0};
5322 MSIPACKAGE *package = param;
5323 LPCWSTR compgroupid, component, feature, qualifier;
5327 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5330 feature = MSI_RecordGetString( rec, 5 );
5331 feat = get_loaded_feature( package, feature );
5333 return ERROR_SUCCESS;
5335 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5337 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5338 feat->Action = feat->Installed;
5339 return ERROR_SUCCESS;
5342 component = MSI_RecordGetString( rec, 3 );
5343 comp = get_loaded_component( package, component );
5345 return ERROR_SUCCESS;
5347 compgroupid = MSI_RecordGetString( rec, 1 );
5348 qualifier = MSI_RecordGetString( rec, 2 );
5350 squash_guid( compgroupid, squashed );
5351 strcpyW( keypath, szInstallerComponents );
5352 strcatW( keypath, squashed );
5354 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5355 if (res != ERROR_SUCCESS)
5357 WARN("Unable to delete component key %d\n", res);
5360 uirow = MSI_CreateRecord( 2 );
5361 MSI_RecordSetStringW( uirow, 1, compgroupid );
5362 MSI_RecordSetStringW( uirow, 2, qualifier );
5363 ui_actiondata( package, szUnpublishComponents, uirow );
5364 msiobj_release( &uirow->hdr );
5366 return ERROR_SUCCESS;
5369 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5373 static const WCHAR query[] =
5374 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5375 '`','P','u','b','l','i','s','h',
5376 'C','o','m','p','o','n','e','n','t','`',0};
5378 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5379 if (rc != ERROR_SUCCESS)
5380 return ERROR_SUCCESS;
5382 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5383 msiobj_release( &view->hdr );
5388 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5390 MSIPACKAGE *package = param;
5393 SC_HANDLE hscm, service = NULL;
5395 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5396 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5397 DWORD serv_type, start_type, err_control;
5398 SERVICE_DESCRIPTIONW sd = {NULL};
5400 static const WCHAR query[] =
5401 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5402 '`','C','o','m','p','o','n','e','n','t','`',' ',
5403 'W','H','E','R','E',' ',
5404 '`','C','o','m','p','o','n','e','n','t','`',' ',
5405 '=','\'','%','s','\'',0};
5407 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5410 ERR("Failed to open the SC Manager!\n");
5414 start_type = MSI_RecordGetInteger(rec, 5);
5415 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5418 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5419 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5420 serv_type = MSI_RecordGetInteger(rec, 4);
5421 err_control = MSI_RecordGetInteger(rec, 6);
5422 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5423 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5424 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5425 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5426 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5427 comp = MSI_RecordGetString(rec, 12);
5428 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5430 /* fetch the service path */
5431 row = MSI_QueryGetRecord(package->db, query, comp);
5434 ERR("Control query failed!\n");
5437 key = MSI_RecordGetString(row, 6);
5439 file = get_loaded_file(package, key);
5440 msiobj_release(&row->hdr);
5443 ERR("Failed to load the service file\n");
5447 if (!args || !args[0]) image_path = file->TargetPath;
5450 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5451 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5452 return ERROR_OUTOFMEMORY;
5454 strcpyW(image_path, file->TargetPath);
5455 strcatW(image_path, szSpace);
5456 strcatW(image_path, args);
5458 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5459 start_type, err_control, image_path, load_order,
5460 NULL, depends, serv_name, pass);
5464 if (GetLastError() != ERROR_SERVICE_EXISTS)
5465 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5467 else if (sd.lpDescription)
5469 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5470 WARN("failed to set service description %u\n", GetLastError());
5473 if (image_path != file->TargetPath) msi_free(image_path);
5475 CloseServiceHandle(service);
5476 CloseServiceHandle(hscm);
5479 msi_free(sd.lpDescription);
5480 msi_free(load_order);
5481 msi_free(serv_name);
5486 return ERROR_SUCCESS;
5489 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5493 static const WCHAR ExecSeqQuery[] =
5494 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5495 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5497 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5498 if (rc != ERROR_SUCCESS)
5499 return ERROR_SUCCESS;
5501 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5502 msiobj_release(&view->hdr);
5507 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5508 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5510 LPCWSTR *vector, *temp_vector;
5514 static const WCHAR separator[] = {'[','~',']',0};
5517 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5522 vector = msi_alloc(sizeof(LPWSTR));
5530 vector[*numargs - 1] = p;
5532 if ((q = strstrW(p, separator)))
5536 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5542 vector = temp_vector;
5551 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5553 MSIPACKAGE *package = param;
5556 SC_HANDLE scm = NULL, service = NULL;
5557 LPCWSTR component, *vector = NULL;
5558 LPWSTR name, args, display_name = NULL;
5559 DWORD event, numargs, len;
5560 UINT r = ERROR_FUNCTION_FAILED;
5562 component = MSI_RecordGetString(rec, 6);
5563 comp = get_loaded_component(package, component);
5565 return ERROR_SUCCESS;
5569 TRACE("component is disabled\n");
5570 return ERROR_SUCCESS;
5573 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5575 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5576 comp->Action = comp->Installed;
5577 return ERROR_SUCCESS;
5579 comp->Action = INSTALLSTATE_LOCAL;
5581 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5582 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5583 event = MSI_RecordGetInteger(rec, 3);
5585 if (!(event & msidbServiceControlEventStart))
5591 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5594 ERR("Failed to open the service control manager\n");
5599 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5600 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5602 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5603 GetServiceDisplayNameW( scm, name, display_name, &len );
5606 service = OpenServiceW(scm, name, SERVICE_START);
5609 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5613 vector = msi_service_args_to_vector(args, &numargs);
5615 if (!StartServiceW(service, numargs, vector) &&
5616 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5618 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5625 uirow = MSI_CreateRecord( 2 );
5626 MSI_RecordSetStringW( uirow, 1, display_name );
5627 MSI_RecordSetStringW( uirow, 2, name );
5628 ui_actiondata( package, szStartServices, uirow );
5629 msiobj_release( &uirow->hdr );
5631 CloseServiceHandle(service);
5632 CloseServiceHandle(scm);
5637 msi_free(display_name);
5641 static UINT ACTION_StartServices( MSIPACKAGE *package )
5646 static const WCHAR query[] = {
5647 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5648 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5650 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5651 if (rc != ERROR_SUCCESS)
5652 return ERROR_SUCCESS;
5654 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5655 msiobj_release(&view->hdr);
5660 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5662 DWORD i, needed, count;
5663 ENUM_SERVICE_STATUSW *dependencies;
5667 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5668 0, &needed, &count))
5671 if (GetLastError() != ERROR_MORE_DATA)
5674 dependencies = msi_alloc(needed);
5678 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5679 needed, &needed, &count))
5682 for (i = 0; i < count; i++)
5684 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5685 SERVICE_STOP | SERVICE_QUERY_STATUS);
5689 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5696 msi_free(dependencies);
5700 static UINT stop_service( LPCWSTR name )
5702 SC_HANDLE scm = NULL, service = NULL;
5703 SERVICE_STATUS status;
5704 SERVICE_STATUS_PROCESS ssp;
5707 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5710 WARN("Failed to open the SCM: %d\n", GetLastError());
5714 service = OpenServiceW(scm, name,
5716 SERVICE_QUERY_STATUS |
5717 SERVICE_ENUMERATE_DEPENDENTS);
5720 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5724 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5725 sizeof(SERVICE_STATUS_PROCESS), &needed))
5727 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5731 if (ssp.dwCurrentState == SERVICE_STOPPED)
5734 stop_service_dependents(scm, service);
5736 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5737 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5740 CloseServiceHandle(service);
5741 CloseServiceHandle(scm);
5743 return ERROR_SUCCESS;
5746 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5748 MSIPACKAGE *package = param;
5752 LPWSTR name = NULL, display_name = NULL;
5756 event = MSI_RecordGetInteger( rec, 3 );
5757 if (!(event & msidbServiceControlEventStop))
5758 return ERROR_SUCCESS;
5760 component = MSI_RecordGetString( rec, 6 );
5761 comp = get_loaded_component( package, component );
5763 return ERROR_SUCCESS;
5767 TRACE("component is disabled\n");
5768 return ERROR_SUCCESS;
5771 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5773 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5774 comp->Action = comp->Installed;
5775 return ERROR_SUCCESS;
5777 comp->Action = INSTALLSTATE_ABSENT;
5779 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5782 ERR("Failed to open the service control manager\n");
5787 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5788 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5790 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5791 GetServiceDisplayNameW( scm, name, display_name, &len );
5793 CloseServiceHandle( scm );
5795 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5796 stop_service( name );
5799 uirow = MSI_CreateRecord( 2 );
5800 MSI_RecordSetStringW( uirow, 1, display_name );
5801 MSI_RecordSetStringW( uirow, 2, name );
5802 ui_actiondata( package, szStopServices, uirow );
5803 msiobj_release( &uirow->hdr );
5806 msi_free( display_name );
5807 return ERROR_SUCCESS;
5810 static UINT ACTION_StopServices( MSIPACKAGE *package )
5815 static const WCHAR query[] = {
5816 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5817 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5819 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5820 if (rc != ERROR_SUCCESS)
5821 return ERROR_SUCCESS;
5823 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5824 msiobj_release(&view->hdr);
5829 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5831 MSIPACKAGE *package = param;
5835 LPWSTR name = NULL, display_name = NULL;
5837 SC_HANDLE scm = NULL, service = NULL;
5839 event = MSI_RecordGetInteger( rec, 3 );
5840 if (!(event & msidbServiceControlEventDelete))
5841 return ERROR_SUCCESS;
5843 component = MSI_RecordGetString(rec, 6);
5844 comp = get_loaded_component(package, component);
5846 return ERROR_SUCCESS;
5850 TRACE("component is disabled\n");
5851 return ERROR_SUCCESS;
5854 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5856 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5857 comp->Action = comp->Installed;
5858 return ERROR_SUCCESS;
5860 comp->Action = INSTALLSTATE_ABSENT;
5862 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5863 stop_service( name );
5865 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5868 WARN("Failed to open the SCM: %d\n", GetLastError());
5873 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5874 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5876 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5877 GetServiceDisplayNameW( scm, name, display_name, &len );
5880 service = OpenServiceW( scm, name, DELETE );
5883 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5887 if (!DeleteService( service ))
5888 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5891 uirow = MSI_CreateRecord( 2 );
5892 MSI_RecordSetStringW( uirow, 1, display_name );
5893 MSI_RecordSetStringW( uirow, 2, name );
5894 ui_actiondata( package, szDeleteServices, uirow );
5895 msiobj_release( &uirow->hdr );
5897 CloseServiceHandle( service );
5898 CloseServiceHandle( scm );
5900 msi_free( display_name );
5902 return ERROR_SUCCESS;
5905 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5910 static const WCHAR query[] = {
5911 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5912 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5914 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5915 if (rc != ERROR_SUCCESS)
5916 return ERROR_SUCCESS;
5918 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5919 msiobj_release( &view->hdr );
5924 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5926 MSIPACKAGE *package = param;
5927 LPWSTR driver, driver_path, ptr;
5928 WCHAR outpath[MAX_PATH];
5929 MSIFILE *driver_file = NULL, *setup_file = NULL;
5931 LPCWSTR desc, file_key;
5933 UINT r = ERROR_SUCCESS;
5935 static const WCHAR driver_fmt[] = {
5936 'D','r','i','v','e','r','=','%','s',0};
5937 static const WCHAR setup_fmt[] = {
5938 'S','e','t','u','p','=','%','s',0};
5939 static const WCHAR usage_fmt[] = {
5940 'F','i','l','e','U','s','a','g','e','=','1',0};
5942 desc = MSI_RecordGetString(rec, 3);
5944 file_key = MSI_RecordGetString( rec, 4 );
5945 if (file_key) driver_file = get_loaded_file( package, file_key );
5947 file_key = MSI_RecordGetString( rec, 5 );
5948 if (file_key) setup_file = get_loaded_file( package, file_key );
5952 ERR("ODBC Driver entry not found!\n");
5953 return ERROR_FUNCTION_FAILED;
5956 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5958 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5959 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5961 driver = msi_alloc(len * sizeof(WCHAR));
5963 return ERROR_OUTOFMEMORY;
5966 lstrcpyW(ptr, desc);
5967 ptr += lstrlenW(ptr) + 1;
5969 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5974 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5978 lstrcpyW(ptr, usage_fmt);
5979 ptr += lstrlenW(ptr) + 1;
5982 driver_path = strdupW(driver_file->TargetPath);
5983 ptr = strrchrW(driver_path, '\\');
5984 if (ptr) *ptr = '\0';
5986 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5987 NULL, ODBC_INSTALL_COMPLETE, &usage))
5989 ERR("Failed to install SQL driver!\n");
5990 r = ERROR_FUNCTION_FAILED;
5993 uirow = MSI_CreateRecord( 5 );
5994 MSI_RecordSetStringW( uirow, 1, desc );
5995 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5996 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5997 ui_actiondata( package, szInstallODBC, uirow );
5998 msiobj_release( &uirow->hdr );
6001 msi_free(driver_path);
6006 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6008 MSIPACKAGE *package = param;
6009 LPWSTR translator, translator_path, ptr;
6010 WCHAR outpath[MAX_PATH];
6011 MSIFILE *translator_file = NULL, *setup_file = NULL;
6013 LPCWSTR desc, file_key;
6015 UINT r = ERROR_SUCCESS;
6017 static const WCHAR translator_fmt[] = {
6018 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6019 static const WCHAR setup_fmt[] = {
6020 'S','e','t','u','p','=','%','s',0};
6022 desc = MSI_RecordGetString(rec, 3);
6024 file_key = MSI_RecordGetString( rec, 4 );
6025 if (file_key) translator_file = get_loaded_file( package, file_key );
6027 file_key = MSI_RecordGetString( rec, 5 );
6028 if (file_key) setup_file = get_loaded_file( package, file_key );
6030 if (!translator_file)
6032 ERR("ODBC Translator entry not found!\n");
6033 return ERROR_FUNCTION_FAILED;
6036 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6038 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6040 translator = msi_alloc(len * sizeof(WCHAR));
6042 return ERROR_OUTOFMEMORY;
6045 lstrcpyW(ptr, desc);
6046 ptr += lstrlenW(ptr) + 1;
6048 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6053 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6058 translator_path = strdupW(translator_file->TargetPath);
6059 ptr = strrchrW(translator_path, '\\');
6060 if (ptr) *ptr = '\0';
6062 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6063 NULL, ODBC_INSTALL_COMPLETE, &usage))
6065 ERR("Failed to install SQL translator!\n");
6066 r = ERROR_FUNCTION_FAILED;
6069 uirow = MSI_CreateRecord( 5 );
6070 MSI_RecordSetStringW( uirow, 1, desc );
6071 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6072 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6073 ui_actiondata( package, szInstallODBC, uirow );
6074 msiobj_release( &uirow->hdr );
6076 msi_free(translator);
6077 msi_free(translator_path);
6082 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6084 MSIPACKAGE *package = param;
6086 LPCWSTR desc, driver;
6087 WORD request = ODBC_ADD_SYS_DSN;
6090 UINT r = ERROR_SUCCESS;
6093 static const WCHAR attrs_fmt[] = {
6094 'D','S','N','=','%','s',0 };
6096 desc = MSI_RecordGetString(rec, 3);
6097 driver = MSI_RecordGetString(rec, 4);
6098 registration = MSI_RecordGetInteger(rec, 5);
6100 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6101 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6103 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6104 attrs = msi_alloc(len * sizeof(WCHAR));
6106 return ERROR_OUTOFMEMORY;
6108 len = sprintfW(attrs, attrs_fmt, desc);
6111 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6113 ERR("Failed to install SQL data source!\n");
6114 r = ERROR_FUNCTION_FAILED;
6117 uirow = MSI_CreateRecord( 5 );
6118 MSI_RecordSetStringW( uirow, 1, desc );
6119 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6120 MSI_RecordSetInteger( uirow, 3, request );
6121 ui_actiondata( package, szInstallODBC, uirow );
6122 msiobj_release( &uirow->hdr );
6129 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6134 static const WCHAR driver_query[] = {
6135 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6136 'O','D','B','C','D','r','i','v','e','r',0 };
6138 static const WCHAR translator_query[] = {
6139 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6140 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6142 static const WCHAR source_query[] = {
6143 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6144 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6146 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6147 if (rc != ERROR_SUCCESS)
6148 return ERROR_SUCCESS;
6150 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6151 msiobj_release(&view->hdr);
6153 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6154 if (rc != ERROR_SUCCESS)
6155 return ERROR_SUCCESS;
6157 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6158 msiobj_release(&view->hdr);
6160 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6161 if (rc != ERROR_SUCCESS)
6162 return ERROR_SUCCESS;
6164 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6165 msiobj_release(&view->hdr);
6170 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6172 MSIPACKAGE *package = param;
6177 desc = MSI_RecordGetString( rec, 3 );
6178 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6180 WARN("Failed to remove ODBC driver\n");
6184 FIXME("Usage count reached 0\n");
6187 uirow = MSI_CreateRecord( 2 );
6188 MSI_RecordSetStringW( uirow, 1, desc );
6189 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6190 ui_actiondata( package, szRemoveODBC, uirow );
6191 msiobj_release( &uirow->hdr );
6193 return ERROR_SUCCESS;
6196 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6198 MSIPACKAGE *package = param;
6203 desc = MSI_RecordGetString( rec, 3 );
6204 if (!SQLRemoveTranslatorW( desc, &usage ))
6206 WARN("Failed to remove ODBC translator\n");
6210 FIXME("Usage count reached 0\n");
6213 uirow = MSI_CreateRecord( 2 );
6214 MSI_RecordSetStringW( uirow, 1, desc );
6215 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6216 ui_actiondata( package, szRemoveODBC, uirow );
6217 msiobj_release( &uirow->hdr );
6219 return ERROR_SUCCESS;
6222 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6224 MSIPACKAGE *package = param;
6227 LPCWSTR desc, driver;
6228 WORD request = ODBC_REMOVE_SYS_DSN;
6232 static const WCHAR attrs_fmt[] = {
6233 'D','S','N','=','%','s',0 };
6235 desc = MSI_RecordGetString( rec, 3 );
6236 driver = MSI_RecordGetString( rec, 4 );
6237 registration = MSI_RecordGetInteger( rec, 5 );
6239 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6240 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6242 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6243 attrs = msi_alloc( len * sizeof(WCHAR) );
6245 return ERROR_OUTOFMEMORY;
6247 FIXME("Use ODBCSourceAttribute table\n");
6249 len = sprintfW( attrs, attrs_fmt, desc );
6252 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6254 WARN("Failed to remove ODBC data source\n");
6258 uirow = MSI_CreateRecord( 3 );
6259 MSI_RecordSetStringW( uirow, 1, desc );
6260 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6261 MSI_RecordSetInteger( uirow, 3, request );
6262 ui_actiondata( package, szRemoveODBC, uirow );
6263 msiobj_release( &uirow->hdr );
6265 return ERROR_SUCCESS;
6268 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6273 static const WCHAR driver_query[] = {
6274 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6275 'O','D','B','C','D','r','i','v','e','r',0 };
6277 static const WCHAR translator_query[] = {
6278 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6279 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6281 static const WCHAR source_query[] = {
6282 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6283 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6285 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6286 if (rc != ERROR_SUCCESS)
6287 return ERROR_SUCCESS;
6289 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6290 msiobj_release( &view->hdr );
6292 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6293 if (rc != ERROR_SUCCESS)
6294 return ERROR_SUCCESS;
6296 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6297 msiobj_release( &view->hdr );
6299 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6300 if (rc != ERROR_SUCCESS)
6301 return ERROR_SUCCESS;
6303 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6304 msiobj_release( &view->hdr );
6309 #define ENV_ACT_SETALWAYS 0x1
6310 #define ENV_ACT_SETABSENT 0x2
6311 #define ENV_ACT_REMOVE 0x4
6312 #define ENV_ACT_REMOVEMATCH 0x8
6314 #define ENV_MOD_MACHINE 0x20000000
6315 #define ENV_MOD_APPEND 0x40000000
6316 #define ENV_MOD_PREFIX 0x80000000
6317 #define ENV_MOD_MASK 0xC0000000
6319 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6321 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6323 LPCWSTR cptr = *name;
6325 static const WCHAR prefix[] = {'[','~',']',0};
6326 static const int prefix_len = 3;
6332 *flags |= ENV_ACT_SETALWAYS;
6333 else if (*cptr == '+')
6334 *flags |= ENV_ACT_SETABSENT;
6335 else if (*cptr == '-')
6336 *flags |= ENV_ACT_REMOVE;
6337 else if (*cptr == '!')
6338 *flags |= ENV_ACT_REMOVEMATCH;
6339 else if (*cptr == '*')
6340 *flags |= ENV_MOD_MACHINE;
6350 ERR("Missing environment variable\n");
6351 return ERROR_FUNCTION_FAILED;
6356 LPCWSTR ptr = *value;
6357 if (!strncmpW(ptr, prefix, prefix_len))
6359 if (ptr[prefix_len] == szSemiColon[0])
6361 *flags |= ENV_MOD_APPEND;
6362 *value += lstrlenW(prefix);
6369 else if (lstrlenW(*value) >= prefix_len)
6371 ptr += lstrlenW(ptr) - prefix_len;
6372 if (!strcmpW( ptr, prefix ))
6374 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6376 *flags |= ENV_MOD_PREFIX;
6377 /* the "[~]" will be removed by deformat_string */;
6387 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6388 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6389 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6390 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6392 ERR("Invalid flags: %08x\n", *flags);
6393 return ERROR_FUNCTION_FAILED;
6397 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6399 return ERROR_SUCCESS;
6402 static UINT open_env_key( DWORD flags, HKEY *key )
6404 static const WCHAR user_env[] =
6405 {'E','n','v','i','r','o','n','m','e','n','t',0};
6406 static const WCHAR machine_env[] =
6407 {'S','y','s','t','e','m','\\',
6408 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6409 'C','o','n','t','r','o','l','\\',
6410 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6411 'E','n','v','i','r','o','n','m','e','n','t',0};
6416 if (flags & ENV_MOD_MACHINE)
6419 root = HKEY_LOCAL_MACHINE;
6424 root = HKEY_CURRENT_USER;
6427 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6428 if (res != ERROR_SUCCESS)
6430 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6431 return ERROR_FUNCTION_FAILED;
6434 return ERROR_SUCCESS;
6437 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6439 MSIPACKAGE *package = param;
6440 LPCWSTR name, value, component;
6441 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6442 DWORD flags, type, size;
6449 component = MSI_RecordGetString(rec, 4);
6450 comp = get_loaded_component(package, component);
6452 return ERROR_SUCCESS;
6456 TRACE("component is disabled\n");
6457 return ERROR_SUCCESS;
6460 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6462 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6463 comp->Action = comp->Installed;
6464 return ERROR_SUCCESS;
6466 comp->Action = INSTALLSTATE_LOCAL;
6468 name = MSI_RecordGetString(rec, 2);
6469 value = MSI_RecordGetString(rec, 3);
6471 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6473 res = env_parse_flags(&name, &value, &flags);
6474 if (res != ERROR_SUCCESS || !value)
6477 if (value && !deformat_string(package, value, &deformatted))
6479 res = ERROR_OUTOFMEMORY;
6483 value = deformatted;
6485 res = open_env_key( flags, &env );
6486 if (res != ERROR_SUCCESS)
6489 if (flags & ENV_MOD_MACHINE)
6490 action |= 0x20000000;
6494 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6495 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6496 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6499 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6503 /* Nothing to do. */
6506 res = ERROR_SUCCESS;
6510 /* If we are appending but the string was empty, strip ; */
6511 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6513 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6514 newval = strdupW(value);
6517 res = ERROR_OUTOFMEMORY;
6525 /* Contrary to MSDN, +-variable to [~];path works */
6526 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6528 res = ERROR_SUCCESS;
6532 data = msi_alloc(size);
6536 return ERROR_OUTOFMEMORY;
6539 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6540 if (res != ERROR_SUCCESS)
6543 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6546 res = RegDeleteValueW(env, name);
6547 if (res != ERROR_SUCCESS)
6548 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6552 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6553 if (flags & ENV_MOD_MASK)
6557 if (flags & ENV_MOD_APPEND) multiplier++;
6558 if (flags & ENV_MOD_PREFIX) multiplier++;
6559 mod_size = lstrlenW(value) * multiplier;
6560 size += mod_size * sizeof(WCHAR);
6563 newval = msi_alloc(size);
6567 res = ERROR_OUTOFMEMORY;
6571 if (flags & ENV_MOD_PREFIX)
6573 lstrcpyW(newval, value);
6574 ptr = newval + lstrlenW(value);
6575 action |= 0x80000000;
6578 lstrcpyW(ptr, data);
6580 if (flags & ENV_MOD_APPEND)
6582 lstrcatW(newval, value);
6583 action |= 0x40000000;
6586 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6587 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6590 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6594 uirow = MSI_CreateRecord( 3 );
6595 MSI_RecordSetStringW( uirow, 1, name );
6596 MSI_RecordSetStringW( uirow, 2, newval );
6597 MSI_RecordSetInteger( uirow, 3, action );
6598 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6599 msiobj_release( &uirow->hdr );
6601 if (env) RegCloseKey(env);
6602 msi_free(deformatted);
6608 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6612 static const WCHAR ExecSeqQuery[] =
6613 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6614 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6615 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6616 if (rc != ERROR_SUCCESS)
6617 return ERROR_SUCCESS;
6619 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6620 msiobj_release(&view->hdr);
6625 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6627 MSIPACKAGE *package = param;
6628 LPCWSTR name, value, component;
6629 LPWSTR deformatted = NULL;
6638 component = MSI_RecordGetString( rec, 4 );
6639 comp = get_loaded_component( package, component );
6641 return ERROR_SUCCESS;
6645 TRACE("component is disabled\n");
6646 return ERROR_SUCCESS;
6649 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6651 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6652 comp->Action = comp->Installed;
6653 return ERROR_SUCCESS;
6655 comp->Action = INSTALLSTATE_ABSENT;
6657 name = MSI_RecordGetString( rec, 2 );
6658 value = MSI_RecordGetString( rec, 3 );
6660 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6662 r = env_parse_flags( &name, &value, &flags );
6663 if (r != ERROR_SUCCESS)
6666 if (!(flags & ENV_ACT_REMOVE))
6668 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6669 return ERROR_SUCCESS;
6672 if (value && !deformat_string( package, value, &deformatted ))
6673 return ERROR_OUTOFMEMORY;
6675 value = deformatted;
6677 r = open_env_key( flags, &env );
6678 if (r != ERROR_SUCCESS)
6684 if (flags & ENV_MOD_MACHINE)
6685 action |= 0x20000000;
6687 TRACE("Removing %s\n", debugstr_w(name));
6689 res = RegDeleteValueW( env, name );
6690 if (res != ERROR_SUCCESS)
6692 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6697 uirow = MSI_CreateRecord( 3 );
6698 MSI_RecordSetStringW( uirow, 1, name );
6699 MSI_RecordSetStringW( uirow, 2, value );
6700 MSI_RecordSetInteger( uirow, 3, action );
6701 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6702 msiobj_release( &uirow->hdr );
6704 if (env) RegCloseKey( env );
6705 msi_free( deformatted );
6709 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6713 static const WCHAR query[] =
6714 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6715 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6717 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6718 if (rc != ERROR_SUCCESS)
6719 return ERROR_SUCCESS;
6721 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6722 msiobj_release( &view->hdr );
6727 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6729 LPWSTR key, template, id;
6730 UINT r = ERROR_SUCCESS;
6732 id = msi_dup_property( package->db, szProductID );
6736 return ERROR_SUCCESS;
6738 template = msi_dup_property( package->db, szPIDTemplate );
6739 key = msi_dup_property( package->db, szPIDKEY );
6741 if (key && template)
6743 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6744 r = msi_set_property( package->db, szProductID, key );
6746 msi_free( template );
6751 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6754 package->need_reboot = 1;
6755 return ERROR_SUCCESS;
6758 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6760 static const WCHAR szAvailableFreeReg[] =
6761 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6763 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6765 TRACE("%p %d kilobytes\n", package, space);
6767 uirow = MSI_CreateRecord( 1 );
6768 MSI_RecordSetInteger( uirow, 1, space );
6769 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6770 msiobj_release( &uirow->hdr );
6772 return ERROR_SUCCESS;
6775 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6777 FIXME("%p\n", package);
6778 return ERROR_SUCCESS;
6781 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6783 FIXME("%p\n", package);
6784 return ERROR_SUCCESS;
6787 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6792 static const WCHAR driver_query[] = {
6793 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6794 'O','D','B','C','D','r','i','v','e','r',0 };
6796 static const WCHAR translator_query[] = {
6797 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6798 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6800 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6801 if (r == ERROR_SUCCESS)
6804 r = MSI_IterateRecords( view, &count, NULL, package );
6805 msiobj_release( &view->hdr );
6806 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6809 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6810 if (r == ERROR_SUCCESS)
6813 r = MSI_IterateRecords( view, &count, NULL, package );
6814 msiobj_release( &view->hdr );
6815 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6818 return ERROR_SUCCESS;
6821 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6822 LPCSTR action, LPCWSTR table )
6824 static const WCHAR query[] = {
6825 'S','E','L','E','C','T',' ','*',' ',
6826 'F','R','O','M',' ','`','%','s','`',0 };
6827 MSIQUERY *view = NULL;
6831 r = MSI_OpenQuery( package->db, &view, query, table );
6832 if (r == ERROR_SUCCESS)
6834 r = MSI_IterateRecords(view, &count, NULL, package);
6835 msiobj_release(&view->hdr);
6839 FIXME("%s -> %u ignored %s table values\n",
6840 action, count, debugstr_w(table));
6842 return ERROR_SUCCESS;
6845 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6847 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6848 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6851 static UINT ACTION_BindImage( MSIPACKAGE *package )
6853 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6854 return msi_unimplemented_action_stub( package, "BindImage", table );
6857 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6859 static const WCHAR table[] = {
6860 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6861 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6864 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6866 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6867 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6870 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6872 static const WCHAR table[] = {
6873 'M','s','i','A','s','s','e','m','b','l','y',0 };
6874 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6877 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6879 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6880 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6883 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6885 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6886 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6889 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6891 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6892 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6895 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6897 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6898 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6901 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6903 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6904 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6907 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6911 const WCHAR *action;
6912 UINT (*handler)(MSIPACKAGE *);
6916 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6917 { szAppSearch, ACTION_AppSearch },
6918 { szBindImage, ACTION_BindImage },
6919 { szCCPSearch, ACTION_CCPSearch },
6920 { szCostFinalize, ACTION_CostFinalize },
6921 { szCostInitialize, ACTION_CostInitialize },
6922 { szCreateFolders, ACTION_CreateFolders },
6923 { szCreateShortcuts, ACTION_CreateShortcuts },
6924 { szDeleteServices, ACTION_DeleteServices },
6925 { szDisableRollback, ACTION_DisableRollback },
6926 { szDuplicateFiles, ACTION_DuplicateFiles },
6927 { szExecuteAction, ACTION_ExecuteAction },
6928 { szFileCost, ACTION_FileCost },
6929 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6930 { szForceReboot, ACTION_ForceReboot },
6931 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6932 { szInstallExecute, ACTION_InstallExecute },
6933 { szInstallExecuteAgain, ACTION_InstallExecute },
6934 { szInstallFiles, ACTION_InstallFiles},
6935 { szInstallFinalize, ACTION_InstallFinalize },
6936 { szInstallInitialize, ACTION_InstallInitialize },
6937 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6938 { szInstallValidate, ACTION_InstallValidate },
6939 { szIsolateComponents, ACTION_IsolateComponents },
6940 { szLaunchConditions, ACTION_LaunchConditions },
6941 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6942 { szMoveFiles, ACTION_MoveFiles },
6943 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6944 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6945 { szInstallODBC, ACTION_InstallODBC },
6946 { szInstallServices, ACTION_InstallServices },
6947 { szPatchFiles, ACTION_PatchFiles },
6948 { szProcessComponents, ACTION_ProcessComponents },
6949 { szPublishComponents, ACTION_PublishComponents },
6950 { szPublishFeatures, ACTION_PublishFeatures },
6951 { szPublishProduct, ACTION_PublishProduct },
6952 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6953 { szRegisterComPlus, ACTION_RegisterComPlus},
6954 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6955 { szRegisterFonts, ACTION_RegisterFonts },
6956 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6957 { szRegisterProduct, ACTION_RegisterProduct },
6958 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6959 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6960 { szRegisterUser, ACTION_RegisterUser },
6961 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6962 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6963 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6964 { szRemoveFiles, ACTION_RemoveFiles },
6965 { szRemoveFolders, ACTION_RemoveFolders },
6966 { szRemoveIniValues, ACTION_RemoveIniValues },
6967 { szRemoveODBC, ACTION_RemoveODBC },
6968 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6969 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6970 { szResolveSource, ACTION_ResolveSource },
6971 { szRMCCPSearch, ACTION_RMCCPSearch },
6972 { szScheduleReboot, ACTION_ScheduleReboot },
6973 { szSelfRegModules, ACTION_SelfRegModules },
6974 { szSelfUnregModules, ACTION_SelfUnregModules },
6975 { szSetODBCFolders, ACTION_SetODBCFolders },
6976 { szStartServices, ACTION_StartServices },
6977 { szStopServices, ACTION_StopServices },
6978 { szUnpublishComponents, ACTION_UnpublishComponents },
6979 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6980 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6981 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6982 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6983 { szUnregisterFonts, ACTION_UnregisterFonts },
6984 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6985 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6986 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6987 { szValidateProductID, ACTION_ValidateProductID },
6988 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6989 { szWriteIniValues, ACTION_WriteIniValues },
6990 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6994 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7000 while (StandardActions[i].action != NULL)
7002 if (!strcmpW( StandardActions[i].action, action ))
7004 ui_actionstart( package, action );
7005 if (StandardActions[i].handler)
7007 ui_actioninfo( package, action, TRUE, 0 );
7008 *rc = StandardActions[i].handler( package );
7009 ui_actioninfo( package, action, FALSE, *rc );
7013 FIXME("unhandled standard action %s\n", debugstr_w(action));
7014 *rc = ERROR_SUCCESS;
7024 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7026 UINT rc = ERROR_SUCCESS;
7029 TRACE("Performing action (%s)\n", debugstr_w(action));
7031 handled = ACTION_HandleStandardAction(package, action, &rc);
7034 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7038 WARN("unhandled msi action %s\n", debugstr_w(action));
7039 rc = ERROR_FUNCTION_NOT_CALLED;
7045 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7047 UINT rc = ERROR_SUCCESS;
7048 BOOL handled = FALSE;
7050 TRACE("Performing action (%s)\n", debugstr_w(action));
7052 handled = ACTION_HandleStandardAction(package, action, &rc);
7055 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7057 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7062 WARN("unhandled msi action %s\n", debugstr_w(action));
7063 rc = ERROR_FUNCTION_NOT_CALLED;
7069 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7071 UINT rc = ERROR_SUCCESS;
7074 static const WCHAR ExecSeqQuery[] =
7075 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7076 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7077 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7078 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7079 static const WCHAR UISeqQuery[] =
7080 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7081 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7082 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7083 ' ', '=',' ','%','i',0};
7085 if (needs_ui_sequence(package))
7086 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7088 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7092 LPCWSTR action, cond;
7094 TRACE("Running the actions\n");
7096 /* check conditions */
7097 cond = MSI_RecordGetString(row, 2);
7099 /* this is a hack to skip errors in the condition code */
7100 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7102 msiobj_release(&row->hdr);
7103 return ERROR_SUCCESS;
7106 action = MSI_RecordGetString(row, 1);
7109 ERR("failed to fetch action\n");
7110 msiobj_release(&row->hdr);
7111 return ERROR_FUNCTION_FAILED;
7114 if (needs_ui_sequence(package))
7115 rc = ACTION_PerformUIAction(package, action, -1);
7117 rc = ACTION_PerformAction(package, action, -1);
7119 msiobj_release(&row->hdr);
7125 /****************************************************
7126 * TOP level entry points
7127 *****************************************************/
7129 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7130 LPCWSTR szCommandLine )
7135 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7136 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7138 msi_set_property( package->db, szAction, szInstall );
7140 package->script->InWhatSequence = SEQUENCE_INSTALL;
7147 dir = strdupW(szPackagePath);
7148 p = strrchrW(dir, '\\');
7152 file = szPackagePath + (p - dir);
7157 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7158 GetCurrentDirectoryW(MAX_PATH, dir);
7159 lstrcatW(dir, szBackSlash);
7160 file = szPackagePath;
7163 msi_free( package->PackagePath );
7164 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7165 if (!package->PackagePath)
7168 return ERROR_OUTOFMEMORY;
7171 lstrcpyW(package->PackagePath, dir);
7172 lstrcatW(package->PackagePath, file);
7175 msi_set_sourcedir_props(package, FALSE);
7178 msi_parse_command_line( package, szCommandLine, FALSE );
7180 msi_apply_transforms( package );
7181 msi_apply_patches( package );
7183 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7185 TRACE("setting reinstall property\n");
7186 msi_set_property( package->db, szReinstall, szAll );
7189 /* properties may have been added by a transform */
7190 msi_clone_properties( package );
7192 msi_parse_command_line( package, szCommandLine, FALSE );
7193 msi_adjust_privilege_properties( package );
7194 msi_set_context( package );
7196 if (needs_ui_sequence( package))
7198 package->script->InWhatSequence |= SEQUENCE_UI;
7199 rc = ACTION_ProcessUISequence(package);
7200 ui_exists = ui_sequence_exists(package);
7201 if (rc == ERROR_SUCCESS || !ui_exists)
7203 package->script->InWhatSequence |= SEQUENCE_EXEC;
7204 rc = ACTION_ProcessExecSequence(package, ui_exists);
7208 rc = ACTION_ProcessExecSequence(package, FALSE);
7210 package->script->CurrentlyScripting = FALSE;
7212 /* process the ending type action */
7213 if (rc == ERROR_SUCCESS)
7214 ACTION_PerformActionSequence(package, -1);
7215 else if (rc == ERROR_INSTALL_USEREXIT)
7216 ACTION_PerformActionSequence(package, -2);
7217 else if (rc == ERROR_INSTALL_SUSPEND)
7218 ACTION_PerformActionSequence(package, -4);
7220 ACTION_PerformActionSequence(package, -3);
7222 /* finish up running custom actions */
7223 ACTION_FinishCustomActions(package);
7225 if (rc == ERROR_SUCCESS && package->need_reboot)
7226 return ERROR_SUCCESS_REBOOT_REQUIRED;